Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions mrbgems/mruby-pack/src/pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -775,12 +775,15 @@ pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, int count, u
{
char utf8[4];
int len;
uint32_t c = (uint32_t)mrb_integer(o);
mrb_int c = mrb_integer(o);

len = (int)mrb_utf8_to_buf(utf8, c);
if (len == 0) {
/* mrb_utf8_to_buf() takes a uint32_t, which wraps a value outside the
Unicode range into a codepoint, so the range has to be checked on the
mrb_int before the cast. */
if (c < 0 || 0x10FFFF < c) {
mrb_raise(mrb, E_RANGE_ERROR, "pack(U): value out of range");
}
len = (int)mrb_utf8_to_buf(utf8, (uint32_t)c);

str = str_len_ensure(mrb, str, sidx + len);
memcpy(RSTRING_PTR(str) + sidx, utf8, len);
Expand Down
13 changes: 13 additions & 0 deletions mrbgems/mruby-pack/test/pack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,19 @@ def assert_pack tmpl, packed, unpacked
assert_raise(RangeError) { [0x40000000].pack("U") }
end

assert 'pack("U") with a value outside the Unicode range' do
assert_equal [0xF4, 0x8F, 0xBF, 0xBF], [0x10FFFF].pack("U").unpack("C*")
assert_raise(RangeError) { [0x110000].pack("U") }

# The encoder takes a uint32_t, so a value that wraps into the Unicode range
# must not come out as the character it wraps to. The shift is computed at
# run time because the constant folder would reject the literal on a build
# with a 32-bit mrb_int and no bigint, where there is nothing to test.
shift = 32
wrapping = ((1 << shift) + 0x41) rescue nil
assert_raise(RangeError) { [wrapping].pack("U") } if wrapping.is_a?(Integer)
end

assert 'unpack1' do
d = 1234
assert_equal(d, [d].pack("i").unpack1("i"))
Expand Down
Loading