summaryrefslogtreecommitdiffhomepage
path: root/src/class.c
diff options
context:
space:
mode:
authorKouhei Sutou <[email protected]>2016-01-22 00:20:00 +0900
committerKouhei Sutou <[email protected]>2016-01-22 00:20:00 +0900
commitc77123d20a6e971937177edf9d13763d147389c6 (patch)
tree9bd07cb2d90bbedd10434baede4edbadb7c290ae /src/class.c
parent8a74e68552a9a791de0202fff197095bd308e0eb (diff)
downloadmruby-c77123d20a6e971937177edf9d13763d147389c6.tar.gz
mruby-c77123d20a6e971937177edf9d13763d147389c6.zip
Fix SEGV by stack extension in mrb_get_args()
mrb_get_args() keeps pointer of the current stack. But address of the current stack maybe changed by method call. 'i' format character calls #to_i when the argument isn't integer but has #to_i. Here is a code that may call #to_i in mrb_get_args(): case 'i': // ... default: *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i])); break; // ... Here is a code #to_i is called: class X def initialize(i) @i = i end def to_i @i end end [][X.new(0), 0] # X#to_i is called So, mrb_get_args() shouldn't keep pointer and use it. mrb_get_args() should always refer mrb->ci->stack to use valid address of the current stack.
Diffstat (limited to 'src/class.c')
-rw-r--r--src/class.c80
1 files changed, 45 insertions, 35 deletions
diff --git a/src/class.c b/src/class.c
index ccbbe2544..6f762345d 100644
--- a/src/class.c
+++ b/src/class.c
@@ -466,9 +466,10 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
{
char c;
int i = 0;
- mrb_value *sp = mrb->c->stack + 1;
va_list ap;
int argc = mrb->c->ci->argc;
+ int arg_i = 0;
+ mrb_bool array_argv;
mrb_bool opt = FALSE;
mrb_bool given = TRUE;
@@ -477,8 +478,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
struct RArray *a = mrb_ary_ptr(mrb->c->stack[1]);
argc = a->len;
- sp = a->ptr;
+ array_argv = TRUE;
+ } else {
+ array_argv = FALSE;
}
+
+#define ARGV \
+ (array_argv ? mrb_ary_ptr(mrb->c->stack[1])->ptr : (mrb->c->stack + 1))
+
while ((c = *format++)) {
switch (c) {
case '|': case '*': case '&': case '?':
@@ -502,7 +509,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_value*);
if (i < argc) {
- *p = *sp++;
+ *p = ARGV[arg_i++];
i++;
}
}
@@ -515,7 +522,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (i < argc) {
mrb_value ss;
- ss = *sp++;
+ ss = ARGV[arg_i++];
switch (mrb_type(ss)) {
case MRB_TT_CLASS:
case MRB_TT_MODULE:
@@ -537,14 +544,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_value*);
if (*format == '!') {
format++;
- if (i < argc && mrb_nil_p(*sp)) {
- *p = *sp++;
+ if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+ *p = ARGV[arg_i++];
i++;
break;
}
}
if (i < argc) {
- *p = to_str(mrb, *sp++);
+ *p = to_str(mrb, ARGV[arg_i++]);
i++;
}
}
@@ -556,14 +563,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_value*);
if (*format == '!') {
format++;
- if (i < argc && mrb_nil_p(*sp)) {
- *p = *sp++;
+ if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+ *p = ARGV[arg_i++];
i++;
break;
}
}
if (i < argc) {
- *p = to_ary(mrb, *sp++);
+ *p = to_ary(mrb, ARGV[arg_i++]);
i++;
}
}
@@ -575,14 +582,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_value*);
if (*format == '!') {
format++;
- if (i < argc && mrb_nil_p(*sp)) {
- *p = *sp++;
+ if (i < argc && mrb_nil_p(ARGV[arg_i])) {
+ *p = ARGV[arg_i++];
i++;
break;
}
}
if (i < argc) {
- *p = to_hash(mrb, *sp++);
+ *p = to_hash(mrb, ARGV[arg_i++]);
i++;
}
}
@@ -597,7 +604,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
pl = va_arg(ap, mrb_int*);
if (*format == '!') {
format++;
- if (i < argc && mrb_nil_p(*sp)) {
+ if (i < argc && mrb_nil_p(ARGV[arg_i])) {
*ps = NULL;
*pl = 0;
i++;
@@ -605,7 +612,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
}
if (i < argc) {
- ss = to_str(mrb, *sp++);
+ ss = to_str(mrb, ARGV[arg_i++]);
*ps = RSTRING_PTR(ss);
*pl = RSTRING_LEN(ss);
i++;
@@ -620,14 +627,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
ps = va_arg(ap, const char**);
if (*format == '!') {
format++;
- if (i < argc && mrb_nil_p(*sp)) {
+ if (i < argc && mrb_nil_p(ARGV[arg_i])) {
*ps = NULL;
- i++; sp++;
+ i++; arg_i++;
break;
}
}
if (i < argc) {
- ss = to_str(mrb, *sp++);
+ ss = to_str(mrb, ARGV[arg_i++]);
*ps = mrb_string_value_cstr(mrb, &ss);
i++;
}
@@ -644,15 +651,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
pl = va_arg(ap, mrb_int*);
if (*format == '!') {
format++;
- if (i < argc && mrb_nil_p(*sp)) {
+ if (i < argc && mrb_nil_p(ARGV[arg_i])) {
*pb = 0;
*pl = 0;
- i++; sp++;
+ i++; arg_i++;
break;
}
}
if (i < argc) {
- aa = to_ary(mrb, *sp++);
+ aa = to_ary(mrb, ARGV[arg_i++]);
a = mrb_ary_ptr(aa);
*pb = a->ptr;
*pl = a->len;
@@ -666,8 +673,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_float*);
if (i < argc) {
- *p = mrb_to_flo(mrb, *sp);
- sp++;
+ *p = mrb_to_flo(mrb, ARGV[arg_i]);
+ arg_i++;
i++;
}
}
@@ -678,13 +685,13 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
p = va_arg(ap, mrb_int*);
if (i < argc) {
- switch (mrb_type(*sp)) {
+ switch (mrb_type(ARGV[arg_i])) {
case MRB_TT_FIXNUM:
- *p = mrb_fixnum(*sp);
+ *p = mrb_fixnum(ARGV[arg_i]);
break;
case MRB_TT_FLOAT:
{
- mrb_float f = mrb_float(*sp);
+ mrb_float f = mrb_float(ARGV[arg_i]);
if (!FIXABLE(f)) {
mrb_raise(mrb, E_RANGE_ERROR, "float too big for int");
@@ -696,10 +703,10 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer");
break;
default:
- *p = mrb_fixnum(mrb_Integer(mrb, *sp));
+ *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i]));
break;
}
- sp++;
+ arg_i++;
i++;
}
}
@@ -709,7 +716,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_bool *boolp = va_arg(ap, mrb_bool*);
if (i < argc) {
- mrb_value b = *sp++;
+ mrb_value b = ARGV[arg_i++];
*boolp = mrb_test(b);
i++;
}
@@ -723,7 +730,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (i < argc) {
mrb_value ss;
- ss = *sp++;
+ ss = ARGV[arg_i++];
*symp = to_sym(mrb, ss);
i++;
}
@@ -738,14 +745,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
type = va_arg(ap, struct mrb_data_type const*);
if (*format == '!') {
format++;
- if (i < argc && mrb_nil_p(*sp)) {
+ if (i < argc && mrb_nil_p(ARGV[arg_i])) {
*datap = 0;
- i++; sp++;
+ i++; arg_i++;
break;
}
}
if (i < argc) {
- *datap = mrb_data_get_ptr(mrb, *sp++, type);
+ *datap = mrb_data_get_ptr(mrb, ARGV[arg_i++], type);
++i;
}
}
@@ -787,10 +794,10 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (argc > i) {
*pl = argc-i;
if (*pl > 0) {
- *var = sp;
+ *var = ARGV + arg_i;
}
i = argc;
- sp += *pl;
+ arg_i += *pl;
}
else {
*pl = 0;
@@ -803,6 +810,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
break;
}
}
+
+#undef ARGV
+
if (!c && argc > i) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
}