summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--compile.c4
-rw-r--r--internal.h1
-rw-r--r--parse.y27
-rw-r--r--test/ruby/test_syntax.rb7
-rw-r--r--util.c22
6 files changed, 57 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 3cfd09e..7bad6b7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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,
diff --git a/compile.c b/compile.c
index e5cf964..cdcb19b 100644
--- a/compile.c
+++ b/compile.c
@@ -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 c68d42e..509e19a 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);
diff --git a/parse.y b/parse.y
index 36845b4..dd75442 100644
--- a/parse.y
+++ b/parse.y
@@ -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 21752e2..189cf13 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
diff --git a/util.c b/util.c
index 807f43f..0319fb5 100644
--- a/util.c
+++ b/util.c
@@ -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;