diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-05-29 05:39:03 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-05-29 05:39:03 +0000 |
commit | 238394e7384d68627b1faa9a45c95517e9ea47e3 (patch) | |
tree | 837f4c9da5f7be9aaa095056885220b80e29343b | |
parent | d8bbb5eda83f92bfa6045bc5165f7578e524a2f5 (diff) | |
download | ruby-238394e7384d68627b1faa9a45c95517e9ea47e3.tar.gz |
parse.y: check NTH_REF range
* compile.c (iseq_compile_each): out of range NTH_REF is always
nil.
* parse.y (parse_numvar): check overflow of NTH_REF and range.
[ruby-core:69393] [Bug #11192]
* util.c (ruby_scan_digits): make public and add length parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50671 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | compile.c | 4 | ||||
-rw-r--r-- | internal.h | 1 | ||||
-rw-r--r-- | parse.y | 27 | ||||
-rw-r--r-- | test/ruby/test_syntax.rb | 7 | ||||
-rw-r--r-- | util.c | 22 |
6 files changed, 57 insertions, 14 deletions
@@ -1,3 +1,13 @@ +Fri May 29 14:39:00 2015 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * compile.c (iseq_compile_each): out of range NTH_REF is always + nil. + + * parse.y (parse_numvar): check overflow of NTH_REF and range. + [ruby-core:69393] [Bug #11192] + + * util.c (ruby_scan_digits): make public and add length parameter. + Fri May 29 11:18:58 2015 Eric Wong <e@80x24.org> * ext/socket/ancdata.c (bsock_sendmsg_internal, @@ -4920,6 +4920,10 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) } case NODE_NTH_REF:{ if (!poped) { + if (!node->nd_nth) { + ADD_INSN(ret, line, putnil); + break; + } ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */, INT2FIX(node->nd_nth << 1)); } diff --git a/internal.h b/internal.h index c68d42efb4..509e19a228 100644 --- a/internal.h +++ b/internal.h @@ -1272,6 +1272,7 @@ VALUE rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb /* util.c (export) */ extern const signed char ruby_digit36_to_number_table[]; extern const char ruby_hexdigits[]; +extern unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow); /* variable.c (export) */ void rb_gc_mark_global_tbl(void); @@ -694,9 +694,7 @@ new_args_tail_gen(struct parser_params *parser, VALUE k, VALUE kr, VALUE b) # define rb_warningV(fmt,a) ripper_warningV(parser, (fmt), (a)) static void ripper_warn0(struct parser_params*, const char*); static void ripper_warnI(struct parser_params*, const char*, int); -#if 0 /* not in use right now */ static void ripper_warnS(struct parser_params*, const char*, const char*); -#endif static void ripper_warnV(struct parser_params*, const char*, VALUE); static void ripper_warning0(struct parser_params*, const char*); static void ripper_warningS(struct parser_params*, const char*, const char*); @@ -7593,6 +7591,27 @@ tokenize_ident(struct parser_params *parser, const enum lex_state_e last_state) } static int +parse_numvar(struct parser_params *parser) +{ + size_t len; + int overflow; + unsigned long n = ruby_scan_digits(tok()+1, toklen()-1, 10, &len, &overflow); + const unsigned long nth_ref_max = + (FIXNUM_MAX / 2 < INT_MAX) ? FIXNUM_MAX / 2 : INT_MAX; + /* NTH_REF is left-shifted to be ORed with back-ref flag and + * turned into a Fixnum, in compile.c */ + + if (overflow || n > nth_ref_max) { + /* compile_error()? */ + rb_warnS("`%s' is too big for a number variable, always nil", tok()); + return 0; /* $0 is $PROGRAM_NAME, not NTH_REF */ + } + else { + return (int)n; + } +} + +static int parse_gvar(struct parser_params *parser, const enum lex_state_e last_state) { register int c; @@ -7670,7 +7689,7 @@ parse_gvar(struct parser_params *parser, const enum lex_state_e last_state) pushback(c); if (IS_lex_state_for(last_state, EXPR_FNAME)) goto gvar; tokfix(); - set_yylval_node(NEW_NTH_REF(atoi(tok()+1))); + set_yylval_node(NEW_NTH_REF(parse_numvar(parser))); return tNTH_REF; default: @@ -11070,14 +11089,12 @@ ripper_warnI(struct parser_params *parser, const char *fmt, int a) STR_NEW2(fmt), INT2NUM(a)); } -#if 0 /* not in use right now */ static void ripper_warnS(struct parser_params *parser, const char *fmt, const char *str) { rb_funcall(parser->value, id_warn, 2, STR_NEW2(fmt), STR_NEW2(str)); } -#endif static void ripper_warnV(struct parser_params *parser, const char *fmt, VALUE v) diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 21752e20d3..189cf1358d 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -579,6 +579,13 @@ eom assert_syntax_error('0...%w.', /unterminated string/, bug10957) end + def test_too_big_nth_ref + bug11192 = '[ruby-core:69393] [Bug #11192]' + assert_warn(/too big/, bug11192) do + eval('$99999999999999999') + end + end + private def not_label(x) @result = x; @not_label ||= nil end @@ -76,21 +76,25 @@ const signed char ruby_digit36_to_number_table[] = { /*f*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; -static unsigned long -scan_digits(const char *str, int base, size_t *retlen, int *overflow) +unsigned long +ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow) { const char *start = str; unsigned long ret = 0, x; unsigned long mul_overflow = (~(unsigned long)0) / base; - int c; + *overflow = 0; - while ((c = (unsigned char)*str++) != '\0') { - int d = ruby_digit36_to_number_table[c]; + if (!len) { + *retlen = 0; + return 0; + } + + do { + int d = ruby_digit36_to_number_table[(unsigned char)*str++]; if (d == -1 || base <= d) { - *retlen = (str-1) - start; - return ret; + break; } if (mul_overflow < ret) *overflow = 1; @@ -99,7 +103,7 @@ scan_digits(const char *str, int base, size_t *retlen, int *overflow) ret += d; if (ret < x) *overflow = 1; - } + } while (len < 0 || --len); *retlen = (str-1) - start; return ret; } @@ -151,7 +155,7 @@ ruby_strtoul(const char *str, char **endptr, int base) b = base == 0 ? 10 : base; } - ret = scan_digits(str, b, &len, &overflow); + ret = ruby_scan_digits(str, -1, b, &len, &overflow); if (0 < len) subject_found = str+len; |