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
7 changes: 6 additions & 1 deletion mrbgems/mruby-sprintf/src/sprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,8 +536,13 @@ mrb_str_format(mrb_state *mrb, mrb_int argc, const mrb_value *argv, mrb_value fm
/* Integer: encode directly to stack buffer (no allocation) */
mrb_int code = mrb_integer(val);
#ifdef MRB_UTF8_STRING
/* mrb_utf8_to_buf() writes nothing for a value it cannot encode,
and takes a uint32_t, which wraps a value outside the Unicode
range into a codepoint. Either way there is no byte to write. */
if (code < 0 || 0x10FFFF < code) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid character");
}
clen = (int)mrb_utf8_to_buf(cbuf, (uint32_t)code);
if (clen == 0) clen = 1; /* invalid codepoint: write single byte */
#else
cbuf[0] = (char)(code & 0xff);
clen = 1;
Expand Down
15 changes: 15 additions & 0 deletions mrbgems/mruby-sprintf/test/sprintf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,18 @@ def mutator.to_s
assert_equal "ok", result[0, 2]
assert_equal "B" * 200, result[2..]
end

assert('sprintf("%c") with an integer that has no UTF-8 encoding') do
skip unless __ENCODING__ == "UTF-8"
# Nothing was written to the encoder's buffer for these, and %c used to emit
# whatever byte the stack happened to hold there.
assert_raise(ArgumentError) { sprintf("%c", 0x110000) }
assert_raise(ArgumentError) { sprintf("%c", -1) }
# 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(ArgumentError) { sprintf("%c", wrapping) } if wrapping.is_a?(Integer)
end
Loading