diff options
| -rw-r--r-- | doc/file/filename_matching.md | 208 | ||||
| -rw-r--r-- | ext/json/json.h | 8 | ||||
| -rw-r--r-- | ext/json/parser/parser.c | 22 | ||||
| -rw-r--r-- | io.c | 4 | ||||
| -rw-r--r-- | io_buffer.c | 12 | ||||
| -rw-r--r-- | sprintf.c | 44 | ||||
| -rw-r--r-- | test/.excludes-mmtk/TestObjSpace.rb | 1 | ||||
| -rw-r--r-- | test/ruby/test_io_buffer.rb | 9 | ||||
| -rw-r--r-- | test/ruby/test_sprintf.rb | 6 |
9 files changed, 237 insertions, 77 deletions
diff --git a/doc/file/filename_matching.md b/doc/file/filename_matching.md index cf5b60bac2..fca02f1d83 100644 --- a/doc/file/filename_matching.md +++ b/doc/file/filename_matching.md @@ -41,17 +41,30 @@ see the table above. A simple string matches itself: ```ruby -File.fnmatch('xyzzy', 'xyzzy') # => true -File.fnmatch('one_two_three', 'one_two_three') # => true -File.fnmatch('123', '123') # => true -File.fnmatch('Form 27B/6', 'Form 27B/6') # => true -File.fnmatch('bcd', 'abcde') # => false # Must be exact. +File.fnmatch('xyzzy', 'xyzzy') # => true +File.fnmatch('one_two_three', 'one_two_three') # => true +File.fnmatch('123', '123') # => true +File.fnmatch('Form 27B/6', 'Form 27B/6') # => true + +Pathname('xyzzy').fnmatch('xyzzy') # => true +Pathname('one_two_three').fnmatch('one_two_three') # => true +Pathname('123').fnmatch('123') # => true +Pathname('Form 27B/6').fnmatch('Form 27B/6') # => true + +# Must be exact. +pattern = 'abcde' +path = 'abc' +File.fnmatch(pattern, path) # => false +Pathname(path).fnmatch(pattern) # => false ``` By default, the matching is case-sensitive: ```ruby -File.fnmatch('abc', 'ABC') # => false +pattern = 'abc' +path = 'ABC' +File.fnmatch(pattern, path) # => false +Pathname(path).fnmatch(pattern) # => false ``` Case-sensitivity may be modified by flags: @@ -61,8 +74,11 @@ Case-sensitivity may be modified by flags: By default, the alternatives pattern is disabled: -```rutby -File.fnmatch('R{ub,foo}y', 'Ruby') # => false +```ruby +pattern = 'R{ub,foo}y' +path = 'Ruby' +File.fnmatch(pattern, path) # => false +Pathname(path).fnmatch(pattern) # => false ``` It may be enabled by flag [`File::FNM_EXTGLOB`](#constant-filefnmextglob). @@ -70,7 +86,10 @@ It may be enabled by flag [`File::FNM_EXTGLOB`](#constant-filefnmextglob). By default, the Windows short name pattern is disabled: ```ruby -File.fnmatch('PROGRAM~1', 'Program Files') # => false +pattern ='PROGRAM~1' +path = 'Program Files' +File.fnmatch(pattern, path) # => false +Pathname(path).fnmatch(pattern) # => false ``` It may be enabled by flag [`File::FNM_SHORTNAME`](#constant-filefnmshortname). @@ -80,16 +99,31 @@ It may be enabled by flag [`File::FNM_SHORTNAME`](#constant-filefnmshortname). The asterisk pattern (`'*'`) matches any sequence of characters: ```ruby -File.fnmatch('*', 'foo') # => true -File.fnmatch('*', '') # => true -File.fnmatch('*', '*') # => true -File.fnmatch('\*', 'foo') # => false # Escaped. +pattern = '*' +File.fnmatch(pattern, 'foo') # => true +File.fnmatch(pattern, '') # => true +File.fnmatch(pattern, 'foo') # => true + +Pathname('foo').fnmatch(pattern) # => true +Pathname('').fnmatch(pattern) # => true +Pathname('*').fnmatch(pattern) # => true +``` + +The pattern may be escaped: + +```ruby +pattern = '\*' +File.fnmatch(pattern, 'foo') # => false +Pathname('foo').fnmatch(pattern) # => false ``` By default, the asterisk pattern does not match a leading period (as in a dot-file): ```ruby -File.fnmatch('*', '.document') # => false +pattern = '*' +path = '.document' +File.fnmatch(pattern, path) # => false +Pathname(path).fnmatch(pattern) # => false ``` That matching may be enabled by flag [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch). @@ -97,7 +131,10 @@ That matching may be enabled by flag [`File::FNM_DOTMATCH`](#constant-filefnmdot By default, the asterisk pattern matches across file separators: ```ruby -File.fnmatch('*.rb', 'lib/test.rb') # => true +pattern = '*.rb' +path = 'lib/test.rb' +File.fnmatch(pattern, path) # => true +Pathname(path).fnmatch(pattern) # => true ``` That matching may be disabled by flag [`File::FNM_PATHNAME`](#constant-filefnmpathname). @@ -107,17 +144,37 @@ That matching may be disabled by flag [`File::FNM_PATHNAME`](#constant-filefnmpa The question-mark pattern (`'?'`) matches any single character: ```ruby -File.fnmatch('?', 'f') # => true -File.fnmatch("foo-?.txt", "foo-1.txt") # => true -File.fnmatch('?', 'foo') # => false -File.fnmatch('?', '') # => false -File.fnmatch('\?', 'f') # => false # Escaped. +pattern = '?' +File.fnmatch(pattern, 'f') # => true +File.fnmatch(pattern, '') # => false +File.fnmatch(pattern, 'foo') # => false + +Pathname('f').fnmatch(pattern) # => true +Pathname('').fnmatch(pattern) # => false +Pathname('foo').fnmatch(pattern) # => false + +pattern = 'foo-?.txt' +path = 'foo-1.txt' +File.fnmatch(pattern, path) # => true +Pathname(path).fnmatch(pattern) # => true +``` + +The pattern may be escaped: + +```ruby +pattern = '\?' +path = 'f' +File.fnmatch(pattern, path) # => false +Pathname(path).fnmatch(pattern) # => false ``` By default, pattern `'?'` matches the file separator: ```ruby -File.fnmatch('foo?boo', 'foo/boo') # => true +pattern = 'foo?bar' +path = 'foo/bar' +File.fnmatch(pattern, path) # => true +Pathname(path).fnmatch(pattern) # => true ``` That matching may be disabled by flag [`File::FNM_PATHNAME`](#constant-filefnmpathname). @@ -128,18 +185,40 @@ Characters enclosed in square brackets define a set of characters, any of which matches a single character: ```ruby -File.fnmatch('[ruby]', 'r') # => true -File.fnmatch('[ruby]', 'u') # => true -File.fnmatch('[ruby]', 'y') # => true -File.fnmatch('[ruby]', 'ruby') # => false -File.fnmatch('\[ruby]', 'r') # => false # Escaped. +pattern = '[ruby]' +File.fnmatch(pattern, 'r') # => true +File.fnmatch(pattern, 'u') # => true +File.fnmatch(pattern, 'y') # => true + +Pathname('r').fnmatch(pattern) # => true +Pathname('u').fnmatch(pattern) # => true +Pathname('y').fnmatch(pattern) # => true + +# Matches a single character. +pattern = '[ruby]' +path = 'ruby' +File.fnmatch(pattern, path) # => false +Pathname(path).fnmatch(pattern) # => false +``` + +The pattern may be escaped: + +```ruby +pattern = '\[ruby]' +path = 'r' +File.fnmatch(pattern, path) # => false +Pathname(path).fnmatch(pattern) # => false ``` The character set may be negated: ```ruby -File.fnmatch('[^ruby]', 'r') # => false -File.fnmatch('[^ruby]', 'u') # => false +pattern = '[^ruby]' +File.fnmatch(pattern, 'r') # => false +File.fnmatch(pattern, 'u') # => false + +Pathname('r').fnmatch(pattern) # => false +Pathname('u').fnmatch(pattern) # => false ``` ### Single Character from a \Range (`'[a-c]'`, `'[^a-c]'`) @@ -148,18 +227,42 @@ A range of characters enclosed in square brackets defines a set of characters, any of which matches a single character: ```ruby -File.fnmatch('[a-c]', 'b') # => true -File.fnmatch('[a-c]', 'd') # => false -File.fnmatch('[a-c]', 'abc') # => false -File.fnmatch('R[t-v][a-c]y', 'Ruby') # => true # Multiple ranges allowed. -File.fnmatch('\[a-c]', 'b') # => false # Escaped. +pattern = '[a-c]' +File.fnmatch(pattern, 'b') # => true +File.fnmatch(pattern, 'd') # => false +File.fnmatch(pattern, 'abc') # => false + +Pathname('b').fnmatch(pattern) # => true +Pathname('d').fnmatch(pattern) # => false +Pathname('abc').fnmatch(pattern) # => false +``` + +The pattern may be escaped: + +```ruby +pattern = '\[a-c]' +path = 'b' +File.fnmatch(pattern, path) # => false +Pathname(path).fnmatch(pattern) # => false + +``` + +Multiple ranges are allowed: + +```ruby +pattern = 'R[t-v][a-c]y' +path = 'Ruby' +File.fnmatch(pattern, path) # => true +Pathname(path).fnmatch(pattern) # => true ``` The range may be negated: ```ruby -File.fnmatch('[^a-c]', 'b') # => false -File.fnmatch('[^a-c]', 'd') # => true +pattern = '[^a-c]' +path = 'b' +File.fnmatch(pattern, path) # => false +Pathname(path).fnmatch(pattern) # => false ``` ### Escape (`'\'`) @@ -168,21 +271,36 @@ The backslash character (`'\'`) may be used to escape any of the characters that filename matching treats as special: ```ruby -File.fnmatch('[a-c]', 'b') # => true -File.fnmatch('\[a-c]', 'b') # => false -File.fnmatch('[a-c\]', 'b') # => false -File.fnmatch('[a\-c]', 'b') # => false - -File.fnmatch('{a,b}', 'b', File::FNM_EXTGLOB) # => true -File.fnmatch('\{a,b}', 'b', File::FNM_EXTGLOB) # => false -File.fnmatch('{a\,b}', 'b', File::FNM_EXTGLOB) # => false -File.fnmatch('{a,b\}', 'b', File::FNM_EXTGLOB) # => false +path = 'b' +File.fnmatch('[a-c]', path) # => true +File.fnmatch('\[a-c]', path) # => false +File.fnmatch('[a-c\]', path) # => false +File.fnmatch('[a\-c]', path) # => false + +Pathname(path).fnmatch('[a-c]') # => true +Pathname(path).fnmatch('\[a-c]') # => false +Pathname(path).fnmatch('[a-c\]') # => false +Pathname(path).fnmatch('[a\-c]') # => false + +File.fnmatch('{a,b}', path, File::FNM_EXTGLOB) # => true +File.fnmatch('\{a,b}', path, File::FNM_EXTGLOB) # => false +File.fnmatch('{a\,b}', path, File::FNM_EXTGLOB) # => false +File.fnmatch('{a,b\}', path, File::FNM_EXTGLOB) # => false + +Pathname(path).fnmatch('{a,b}', File::FNM_EXTGLOB) # => true +Pathname(path).fnmatch('\{a,b}', File::FNM_EXTGLOB) # => false +Pathname(path).fnmatch('{a,b\}', File::FNM_EXTGLOB) # => false +Pathname(path).fnmatch('{a\,b}', File::FNM_EXTGLOB) # => false + ``` Use a double-backslash to represent an ordinary backslash: ```ruby -File.fnmatch('\\\\', '\\') # => true +pattern = '\\\\' +path = '\\' +File.fnmatch(pattern, path) # => true +Pathname(path).fnmatch(pattern) # => true ``` By default escape pattern `'\'` is enabled; diff --git a/ext/json/json.h b/ext/json/json.h index cf9420d4dd..78b0eee0a4 100644 --- a/ext/json/json.h +++ b/ext/json/json.h @@ -11,6 +11,9 @@ #if defined(RUBY_DEBUG) && RUBY_DEBUG # define JSON_ASSERT RUBY_ASSERT +# ifndef JSON_DEBUG +# define JSON_DEBUG 1 +# endif #else # ifdef JSON_DEBUG # include <assert.h> @@ -20,6 +23,11 @@ # endif #endif +#ifdef JSON_DEBUG +# define JSON_UNREACHABLE_RETURN(val) rb_bug("Unreachable") +#else +# define JSON_UNREACHABLE_RETURN UNREACHABLE_RETURN +#endif /* shims */ #if SIZEOF_UINT64_T == SIZEOF_LONG_LONG diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index c0631728c3..6b8164c062 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -488,7 +488,7 @@ static const rb_data_type_t JSON_Parser_frame_stack_type = { .dfree = json_frame_stack_free, .dsize = json_frame_stack_memsize, }, - .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE, }; static json_frame_stack *json_frame_stack_spill(json_frame_stack *old_stack, VALUE *handle, json_frame_stack **stack_ref) @@ -1489,7 +1489,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config) case JSON_PHASE_OBJECT_KEY: goto JSON_PHASE_OBJECT_KEY; case JSON_PHASE_OBJECT_COLON: goto JSON_PHASE_OBJECT_COLON; } - UNREACHABLE_RETURN(Qundef); + JSON_UNREACHABLE_RETURN(Qundef); JSON_PHASE_DONE: { // The root document value is parsed; it is the lone survivor on @@ -1623,10 +1623,10 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config) case JSON_PHASE_ARRAY_COMMA: goto JSON_PHASE_ARRAY_COMMA; case JSON_PHASE_OBJECT_COMMA: goto JSON_PHASE_OBJECT_COMMA; case JSON_PHASE_VALUE: goto JSON_PHASE_VALUE; - case JSON_PHASE_OBJECT_KEY: UNREACHABLE_RETURN(Qundef); + case JSON_PHASE_OBJECT_KEY: JSON_UNREACHABLE_RETURN(Qundef); case JSON_PHASE_OBJECT_COLON: goto JSON_PHASE_OBJECT_COLON; } - UNREACHABLE_RETURN(Qundef); + JSON_UNREACHABLE_RETURN(Qundef); } JSON_PHASE_OBJECT_KEY: { @@ -1648,7 +1648,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config) raise_parse_error("expected object key, got: %s", state); } } - UNREACHABLE_RETURN(Qundef); + JSON_UNREACHABLE_RETURN(Qundef); } JSON_PHASE_OBJECT_COLON: { @@ -1669,7 +1669,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config) raise_parse_error("expected ':' after object key, got: %s", state); } } - UNREACHABLE_RETURN(Qundef); + JSON_UNREACHABLE_RETURN(Qundef); } JSON_PHASE_ARRAY_COMMA: { @@ -1705,13 +1705,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config) case JSON_PHASE_ARRAY_COMMA: goto JSON_PHASE_ARRAY_COMMA; case JSON_PHASE_OBJECT_COMMA: goto JSON_PHASE_OBJECT_COMMA; case JSON_PHASE_VALUE: goto JSON_PHASE_VALUE; - case JSON_PHASE_OBJECT_KEY: UNREACHABLE_RETURN(Qundef); + case JSON_PHASE_OBJECT_KEY: JSON_UNREACHABLE_RETURN(Qundef); case JSON_PHASE_OBJECT_COLON: goto JSON_PHASE_OBJECT_COLON; } } else { raise_parse_error("expected ',' or ']' after array value", state); } - UNREACHABLE_RETURN(Qundef); + JSON_UNREACHABLE_RETURN(Qundef); } JSON_PHASE_OBJECT_COMMA: { @@ -1754,16 +1754,16 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config) case JSON_PHASE_ARRAY_COMMA: goto JSON_PHASE_ARRAY_COMMA; case JSON_PHASE_OBJECT_COMMA: goto JSON_PHASE_OBJECT_COMMA; case JSON_PHASE_VALUE: goto JSON_PHASE_VALUE; - case JSON_PHASE_OBJECT_KEY: UNREACHABLE_RETURN(Qundef); + case JSON_PHASE_OBJECT_KEY: JSON_UNREACHABLE_RETURN(Qundef); case JSON_PHASE_OBJECT_COLON: goto JSON_PHASE_OBJECT_COLON; } } else { raise_parse_error("expected ',' or '}' after object value, got: %s", state); } - UNREACHABLE_RETURN(Qundef); + JSON_UNREACHABLE_RETURN(Qundef); } - UNREACHABLE_RETURN(Qundef); + JSON_UNREACHABLE_RETURN(Qundef); } static void json_ensure_eof(JSON_ParserState *state) @@ -8798,14 +8798,14 @@ rb_io_print(int argc, const VALUE *argv, VALUE out) * * Writes the given objects to <tt>$stdout</tt>; returns +nil+. * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt> - * <tt>$\\</tt>), if it is not +nil+. + * (<tt>$\\</tt>), if it is not +nil+. * * With argument +objects+ given, for each object: * * - Converts via its method +to_s+ if not a string. * - Writes to <tt>stdout</tt>. * - If not the last object, writes the output field separator - * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+. + * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+. * * With default separators: * diff --git a/io_buffer.c b/io_buffer.c index faa5304248..d9f50fc234 100644 --- a/io_buffer.c +++ b/io_buffer.c @@ -3625,6 +3625,10 @@ io_buffer_and_inplace(VALUE self, VALUE mask) size_t size; io_buffer_get_bytes_for_writing(buffer, &base, &size); + const void *mask_base; + size_t mask_size; + io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size); + memory_and_inplace(base, size, mask_buffer->base, mask_buffer->size); return self; @@ -3671,6 +3675,10 @@ io_buffer_or_inplace(VALUE self, VALUE mask) size_t size; io_buffer_get_bytes_for_writing(buffer, &base, &size); + const void *mask_base; + size_t mask_size; + io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size); + memory_or_inplace(base, size, mask_buffer->base, mask_buffer->size); return self; @@ -3717,6 +3725,10 @@ io_buffer_xor_inplace(VALUE self, VALUE mask) size_t size; io_buffer_get_bytes_for_writing(buffer, &base, &size); + const void *mask_base; + size_t mask_size; + io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size); + memory_xor_inplace(base, size, mask_buffer->base, mask_buffer->size); return self; @@ -65,18 +65,30 @@ sign_bits(int base, const char *p) #define FPREC 64 #define FPREC0 128 +static long +expand_result(VALUE result, long bsiz, long blen, long l) +{ + int cr = ENC_CODERANGE(result); + RUBY_ASSERT(bsiz >= blen); + while (l > bsiz - blen) { + bsiz *= 2; + if (bsiz < 0) rb_raise(rb_eArgError, "too big specifier"); + } + rb_str_resize(result, bsiz); + ENC_CODERANGE_SET(result, cr); + return bsiz; +} + #define CHECK(l) do {\ - int cr = ENC_CODERANGE(result);\ - RUBY_ASSERT(bsiz >= blen); \ - while ((l) > bsiz - blen) {\ - bsiz*=2;\ - if (bsiz<0) rb_raise(rb_eArgError, "too big specifier");\ - }\ - rb_str_resize(result, bsiz);\ - ENC_CODERANGE_SET(result, cr);\ + bsiz = expand_result(result, bsiz, blen, l);\ buf = RSTRING_PTR(result);\ } while (0) +#define CHECK_WIDTH(l, w) do { \ + if ((l) > INT_MAX - (w)) rb_raise(rb_eArgError, "width too big");\ + CHECK((l)+(w));\ +} while (0) + #define PUSH(s, l) do { \ CHECK(l);\ PUSH_(s, l);\ @@ -469,19 +481,13 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) rb_enc_mbcput(c, &buf[blen], enc); blen += n; } - else if ((flags & FMINUS)) { - --width; - CHECK(n + (width > 0 ? width : 0)); - rb_enc_mbcput(c, &buf[blen], enc); - blen += n; - if (width > 0) FILL_(' ', width); - } else { --width; - CHECK(n + (width > 0 ? width : 0)); - if (width > 0) FILL_(' ', width); + CHECK_WIDTH(n, (width > 0 ? width : 0)); + if (!(flags & FMINUS) && (width > 0)) FILL_(' ', width); rb_enc_mbcput(c, &buf[blen], enc); blen += n; + if ((flags & FMINUS) && (width > 0)) FILL_(' ', width); } } break; @@ -518,7 +524,7 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) /* need to adjust multi-byte string pos */ if ((flags&FWIDTH) && (width > slen)) { width -= (int)slen; - CHECK(len + width); + CHECK_WIDTH(len, width); if (!(flags&FMINUS)) { FILL_(' ', width); width = 0; @@ -832,7 +838,7 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) if (sign || (flags&FSPACE)) ++len; if (prec > 0) ++len; /* period */ fill = width > len ? width - len : 0; - CHECK(fill + len); + CHECK(fill + len); /* max(width, len) */ if (fill && !(flags&(FMINUS|FZERO))) { FILL_(' ', fill); } diff --git a/test/.excludes-mmtk/TestObjSpace.rb b/test/.excludes-mmtk/TestObjSpace.rb index 94eb2c436d..feb05063df 100644 --- a/test/.excludes-mmtk/TestObjSpace.rb +++ b/test/.excludes-mmtk/TestObjSpace.rb @@ -2,3 +2,4 @@ exclude(:test_dump_all_full, "testing behaviour specific to default GC") exclude(:test_dump_flag_age, "testing behaviour specific to default GC") exclude(:test_dump_flags, "testing behaviour specific to default GC") exclude(:test_dump_objects_dumps_page_slot_sizes, "testing behaviour specific to default GC") +exclude(:test_trace_object_allocations_does_not_reuse_freed_allocation_info, "hang up") diff --git a/test/ruby/test_io_buffer.rb b/test/ruby/test_io_buffer.rb index b6372f25b8..327a3ece9c 100644 --- a/test/ruby/test_io_buffer.rb +++ b/test/ruby/test_io_buffer.rb @@ -712,6 +712,10 @@ class TestIOBuffer < Test::Unit::TestCase assert_raise(IO::Buffer::InvalidatedError) { slice | mask } assert_raise(IO::Buffer::InvalidatedError) { slice ^ mask } assert_raise(IO::Buffer::InvalidatedError) { ~slice } + + assert_raise(IO::Buffer::InvalidatedError) { slice.and!(mask) } + assert_raise(IO::Buffer::InvalidatedError) { slice.or!(mask) } + assert_raise(IO::Buffer::InvalidatedError) { slice.xor!(mask) } end def test_operators_raise_on_freed_mask @@ -723,6 +727,11 @@ class TestIOBuffer < Test::Unit::TestCase assert_raise(IO::Buffer::InvalidatedError) { source & mask_slice } assert_raise(IO::Buffer::InvalidatedError) { source | mask_slice } assert_raise(IO::Buffer::InvalidatedError) { source ^ mask_slice } + + source = source.dup + assert_raise(IO::Buffer::InvalidatedError) { source.and!(mask_slice) } + assert_raise(IO::Buffer::InvalidatedError) { source.or!(mask_slice) } + assert_raise(IO::Buffer::InvalidatedError) { source.xor!(mask_slice) } end def test_bit_count diff --git a/test/ruby/test_sprintf.rb b/test/ruby/test_sprintf.rb index 1c7e89c265..bbbe6e7ec3 100644 --- a/test/ruby/test_sprintf.rb +++ b/test/ruby/test_sprintf.rb @@ -1,5 +1,6 @@ # frozen_string_literal: false require 'test/unit' +require 'rbconfig/sizeof' class TestSprintf < Test::Unit::TestCase def test_positional @@ -539,6 +540,11 @@ class TestSprintf < Test::Unit::TestCase def test_width_underflow bug = 'https://github.com/mruby/mruby/issues/3347' assert_equal("!", sprintf("%*c", 0, ?!.ord), bug) + + int_max = RbConfig::LIMITS["INT_MAX"] + assert_raise_with_message(ArgumentError, /width too big/) { + sprintf "%*c", int_max, 0x80 + } end def test_negative_width_overflow |
