mruby-pack: check the pack("U") range before the cast to uint32_t - #7114
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough
ChangesUnicode pack validation
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@mrbgems/mruby-pack/test/pack.rb`:
- Around line 219-220: Guard the wrapping test setup before evaluating the shift
expression: only construct wrapping and run the pack assertion when the build
supports the required integer width, such as under the existing
MRB_USE_BIGINT/64-bit condition. Keep the RangeError assertion unchanged for
supported builds and avoid evaluating 1 << 32 on MRB_INT32 configurations.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 8eb22d89-8f9f-403e-8cf5-ed44eba5cc56
📒 Files selected for processing (2)
mrbgems/mruby-pack/src/pack.cmrbgems/mruby-pack/test/pack.rb
`pack_utf8()` cast its `mrb_int` argument to `uint32_t` and let
`mrb_utf8_to_buf()` report an out of range value by answering 0. The cast
wraps, so a value above 0xFFFFFFFF came back inside the Unicode range and
packed as the character it wrapped to:
```ruby
[(1 << 32) + 0x41].pack("U").bytes #=> [65]
```
CRuby raises there:
```ruby
[(1 << 32) + 0x41].pack("U") # RangeError: pack(U): value out of range
```
Check the range on the `mrb_int` before the cast, the way `int_chr_utf8()`
in mruby-string-ext already guards the shared encoder. Once the range is
checked `mrb_utf8_to_buf()` can no longer answer 0, so the test on the way
back is gone.
A negative argument raised before this too, but by wrapping to 0xFFFFFFFF
and landing above U+10FFFF, not because its sign was ever examined. The
result is the same, the reason for it is now written down.
`pack("U")` keeps rejecting everything above U+10FFFF. CRuby accepts up to
0x7FFFFFFF through the 5 and 6 byte sequences of the pre RFC 3629
encoding, which mruby's own `unpack("U")` does not read back, so that
range difference is left alone.
1e5b809 to
c1b6b30
Compare
[(1 << 32) + 0x41].pack("U")packs"A"on a build with a 64 bitmrb_int.pack_utf8()hands its argument tomrb_utf8_to_buf()as auint32_tand treats a return of 0 as out of range:
The cast wraps, so the encoder never sees the value that was passed in and
answers with a perfectly good byte count:
Fix
Check
c < 0 || 0x10FFFF < con themrb_intbefore the cast and raisethe same
RangeErrorwith the same message.int_chr_utf8()inmruby-string-ext guards the shared encoder the same way. With the range
checked,
mrb_utf8_to_buf()cannot answer 0, so the test on its returnvalue is dropped.
A negative argument raised before this too, but by wrapping to 0xFFFFFFFF
and landing above U+10FFFF, not because its sign was ever examined. The
result is unchanged and now follows from the check.
Scope
The accepted range stays at U+10FFFF. CRuby reaches 0x7FFFFFFF using the 5
and 6 byte sequences of the pre RFC 3629 encoding:
mruby's
unpack("U")rejects those sequences as malformed, so wideningpack("U")alone would leave the pair inconsistent, and widening bothwould put the core UTF-8 helpers back outside RFC 3629. That is a separate
decision from this bug, so the range difference is left as it is.
Related: #7113 fixes the same wrapping cast in
sprintf("%c"), where thesymptom was sharper because the encoder writes nothing to its buffer for a
value it rejects.
Tests
A new case in
mrbgems/mruby-pack/test/pack.rbcovers U+10FFFF, the firstvalue above it, and the wrapping argument. The shift is computed at run time
rather than written as a literal, because on a build with a 32 bit
mrb_intand no bigint the constant folder rejects
1 << 32while the file is beingcompiled and the whole test file is dropped without a word. On such a build
the value cannot be constructed at all, so the assertion is skipped.
Suites pass:
MRB_UTF8_STRING: 2250 tests, 0 failuresMRB_INT32without bigint: 1504 tests, 0 failures. With the literal formit is 1456, the difference being every mruby-pack test.
Summary by CodeRabbit
Bug Fixes
Tests