Skip to content

string.c: check the append size before mrb_str_cat() modifies - #7038

Merged
matz merged 1 commit into
mruby:masterfrom
takumin:string-cat-size-check
Aug 9, 2026
Merged

string.c: check the append size before mrb_str_cat() modifies#7038
matz merged 1 commit into
mruby:masterfrom
takumin:string-cat-size-check

Conversation

@takumin

@takumin takumin commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

mrb_str_cat() takes len as a size_t and hands it to mrb_int_add_overflow(), whose
parameters are mrb_int. A len above MRB_INT_MAX is therefore converted before the
check can see it, and the conversion yields a negative value on the builds mruby targets.
The addition then does not overflow, total comes out below the current length, the
capacity branch is skipped, and memcpy() still runs with the original size_t count,
writing past the buffer.

mrb_str_cat(mrb, str, ptr, len);   /* len > MRB_INT_MAX */

Nothing inside mruby reaches this. Every internal caller passes a length that came from a
string, and str_check_length() keeps those below MRB_INT_MAX. An extension calling the
public mrb_str_cat() with a length it computed itself can, and a length arriving from
outside is exactly the case a size check is there for.

The change

Reject a len that does not fit before it is converted:

  if (len > (size_t)MRB_INT_MAX ||
      mrb_int_add_overflow(RSTR_LEN(s), (mrb_int)len, &total)) {
  size_error:
    mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
  }

The comparison is correct in both directions of the type mismatch. Where size_t is
narrower than mrb_int, MRB_INT_MAX is all ones in its low bits, so the conversion
lands on SIZE_MAX and the condition is never true. That is the right answer there, since
no size_t can exceed MRB_INT_MAX on such a build in the first place.

The whole size check moves ahead of mrb_str_modify() as well. RSTR_LEN(s) is the same
before and after that call, so the check reads the same value, and a string that is about
to raise is no longer unshared first.

Relation to #7039 and #7043

Both touch the same handful of lines at the top of mrb_str_cat(). #7039 carries this
commit as its first of two, since it depends on the check being in place. #7043 is
independent of both. Whichever lands first, I will rebase the others onto it.

Testing

rake test with build_config/default.rb, MRUBY_CONFIG=asan rake test
(address,undefined), and MRUBY_CONFIG=ci/gcc-clang rake test, which covers
MRB_GC_STRESS with MRB_USE_DEBUG_HOOK, MRB_GC_FIXED_ARENA, and the C++ ABI build.
KO: 0 and Crash: 0 on all of them.

`mrb_str_cat()` takes `len` as a `size_t` and hands it to
`mrb_int_add_overflow()`, whose parameters are `mrb_int`. A `len` above
`MRB_INT_MAX` is therefore converted before the check can see it, and the
conversion yields a negative value on the builds mruby targets: the
addition does not overflow, `total` comes out below the current length,
the capacity branch is skipped, and `memcpy()` still runs with the
original `size_t` count and writes past the buffer.

Nothing inside mruby reaches this. Every internal caller passes a length
that came from a string, and `str_check_length()` keeps those below
`MRB_INT_MAX`. An extension calling the public `mrb_str_cat()` with a
length it computed itself can.

Reject a `len` that does not fit before it is converted. The whole size
check moves ahead of `mrb_str_modify()` as well, so a string that is
about to raise is no longer unshared first.
@takumin
takumin requested a review from matz as a code owner August 9, 2026 13:03
@github-actions github-actions Bot added the core label Aug 9, 2026
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

mrb_str_cat now validates the append length before modifying the string. It rejects values that exceed MRB_INT_MAX or overflow the combined string size.

Changes

String append validation

Layer / File(s) Summary
Validate append length
src/string.c
mrb_str_cat checks the append length and combined string size before calling mrb_str_modify.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • mruby/mruby#7002: Adds input-length validation for string or buffer operations.
  • mruby/mruby#7024: Prevents length-related narrowing and overflow errors in another code path.

Suggested reviewers: matz

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: validating append size before mrb_str_cat() modifies the string.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@matz
matz merged commit 28e42c8 into mruby:master Aug 9, 2026
21 checks passed
@takumin
takumin deleted the string-cat-size-check branch August 9, 2026 13:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants