diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/array.c | 22 | ||||
| -rw-r--r-- | src/class.c | 18 | ||||
| -rw-r--r-- | src/error.c | 9 | ||||
| -rw-r--r-- | src/hash.c | 2 | ||||
| -rw-r--r-- | src/kernel.c | 49 | ||||
| -rw-r--r-- | src/numeric.c | 2 | ||||
| -rw-r--r-- | src/string.c | 58 | ||||
| -rw-r--r-- | src/vm.c | 46 |
8 files changed, 162 insertions, 44 deletions
diff --git a/src/array.c b/src/array.c index 056d72920..99f9fc8b2 100644 --- a/src/array.c +++ b/src/array.c @@ -165,11 +165,12 @@ ary_make_shared(mrb_state *mrb, struct RArray *a) } static void -ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) +ary_expand_capa(mrb_state *mrb, struct RArray *a, size_t len) { - mrb_int capa = a->aux.capa; + size_t capa = a->aux.capa; if (len > ARY_MAX_SIZE) { + size_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } @@ -179,12 +180,16 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) while (capa < len) { if (capa <= ARY_MAX_SIZE / 2) { capa *= 2; - } else { - capa = ARY_MAX_SIZE; + } + else { + capa = len; } } + if (capa < len || capa > ARY_MAX_SIZE) { + goto size_error; + } - if (capa > a->aux.capa) { + if (capa > (size_t)a->aux.capa) { mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa); a->aux.capa = capa; @@ -435,6 +440,7 @@ mrb_ary_pop(mrb_state *mrb, mrb_value ary) { struct RArray *a = mrb_ary_ptr(ary); + ary_modify(mrb, a); if (a->len == 0) return mrb_nil_value(); return a->ptr[--a->len]; } @@ -447,6 +453,7 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self) struct RArray *a = mrb_ary_ptr(self); mrb_value val; + ary_modify(mrb, a); if (a->len == 0) return mrb_nil_value(); if (ARY_SHARED_P(a)) { L_SHIFT: @@ -619,6 +626,10 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val size = head + argc; if (tail < a->len) size += a->len - tail; + + if (size < 0 || size > ARY_MAX_SIZE) + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + if (size > a->aux.capa) ary_expand_capa(mrb, a, size); @@ -955,6 +966,7 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); + ary_modify(mrb, a); if (ARY_SHARED_P(a)) { mrb_ary_decref(mrb, a->aux.shared); ARY_UNSET_SHARED_FLAG(a); diff --git a/src/class.c b/src/class.c index fed259b5b..45827f5ba 100644 --- a/src/class.c +++ b/src/class.c @@ -318,6 +318,20 @@ mrb_class_get(mrb_state *mrb, const char *name) } MRB_API struct RClass * +mrb_exc_get(mrb_state *mrb, const char *name) +{ + struct RClass *exc = mrb_class_get_under(mrb, mrb->object_class, name); + struct RClass *e = exc; + + while (e) { + if (e == mrb->eException_class) + return exc; + e = e->super; + } + return mrb->eException_class; +} + +MRB_API struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name) { return module_from_sym(mrb, outer, mrb_intern_cstr(mrb, name)); @@ -901,7 +915,9 @@ boot_defclass(mrb_state *mrb, struct RClass *super) static void boot_initmod(mrb_state *mrb, struct RClass *mod) { - mod->mt = kh_init(mt, mrb); + if (!mod->mt) { + mod->mt = kh_init(mt, mrb); + } } static struct RClass* diff --git a/src/error.c b/src/error.c index b24aed798..8e456ff1a 100644 --- a/src/error.c +++ b/src/error.c @@ -44,8 +44,10 @@ static mrb_value exc_initialize(mrb_state *mrb, mrb_value exc) { mrb_value mesg; + mrb_int argc; + mrb_value *argv; - if (mrb_get_args(mrb, "|o", &mesg) == 1) { + if (mrb_get_args(mrb, "|o*", &mesg, &argv, &argc) >= 1) { mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg); } return exc; @@ -278,8 +280,6 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc) mrb->exc = 0; } else { - if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) - mrb_raise(mrb, E_TYPE_ERROR, "exception object expected"); mrb->exc = mrb_obj_ptr(exc); } } @@ -287,6 +287,9 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc) MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc) { + if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) { + mrb_raise(mrb, E_TYPE_ERROR, "exception object expected"); + } mrb_exc_set(mrb, exc); if (!mrb->gc.out_of_memory) { exc_debug_info(mrb, mrb->exc); diff --git a/src/hash.c b/src/hash.c index c65c8926e..98feaceac 100644 --- a/src/hash.c +++ b/src/hash.c @@ -554,6 +554,7 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) mrb_value key; mrb_get_args(mrb, "o", &key); + mrb_hash_modify(mrb, self); return mrb_hash_delete_key(mrb, self, key); } @@ -620,6 +621,7 @@ mrb_hash_clear(mrb_state *mrb, mrb_value hash) { khash_t(ht) *h = RHASH_TBL(hash); + mrb_hash_modify(mrb, hash); if (h) kh_clear(ht, mrb, h); return hash; } diff --git a/src/kernel.c b/src/kernel.c index a5166deb2..76bd59469 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -453,12 +453,49 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_freeze(mrb_state *mrb, mrb_value self) { - struct RBasic *b = mrb_basic_ptr(self); + struct RBasic *b; + + switch (mrb_type(self)) { + case MRB_TT_FALSE: + case MRB_TT_TRUE: + case MRB_TT_FIXNUM: + case MRB_TT_SYMBOL: + case MRB_TT_FLOAT: + return self; + default: + break; + } - MRB_SET_FROZEN_FLAG(b); + b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + MRB_SET_FROZEN_FLAG(b); + } return self; } +static mrb_value +mrb_obj_frozen(mrb_state *mrb, mrb_value self) +{ + struct RBasic *b; + + switch (mrb_type(self)) { + case MRB_TT_FALSE: + case MRB_TT_TRUE: + case MRB_TT_FIXNUM: + case MRB_TT_SYMBOL: + case MRB_TT_FLOAT: + return mrb_true_value(); + default: + break; + } + + b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + return mrb_false_value(); + } + return mrb_true_value(); +} + /* 15.3.1.3.15 */ /* * call-seq: @@ -951,14 +988,17 @@ obj_respond_to(mrb_state *mrb, mrb_value self) } else { mrb_value tmp; - if (!mrb_string_p(mid)) { + if (mrb_string_p(mid)) { + tmp = mrb_check_intern_str(mrb, mid); + } + else { tmp = mrb_check_string_type(mrb, mid); if (mrb_nil_p(tmp)) { tmp = mrb_inspect(mrb, mid); mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp); } + tmp = mrb_check_intern_str(mrb, tmp); } - tmp = mrb_check_intern_str(mrb, mid); if (mrb_nil_p(tmp)) { respond_to_p = FALSE; } @@ -1134,6 +1174,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); + mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */ mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ diff --git a/src/numeric.c b/src/numeric.c index a9a2a641b..0306b1363 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1044,7 +1044,7 @@ fix_to_f(mrb_state *mrb, mrb_value num) MRB_API mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) { - mrb_int z; + mrb_int z = 0; if (!mrb_float_p(x)) { mrb_raise(mrb, E_TYPE_ERROR, "non float value"); diff --git a/src/string.c b/src/string.c index ce27cdaa1..d6bdd6975 100644 --- a/src/string.c +++ b/src/string.c @@ -121,6 +121,9 @@ mrb_str_buf_new(mrb_state *mrb, size_t capa) static void resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) { +#if SIZE_MAX > MRB_INT_MAX + mrb_assert(capacity < MRB_INT_MAX); +#endif if (RSTR_EMBED_P(s)) { if (RSTRING_EMBED_LEN_MAX < capacity) { char *const tmp = (char *)mrb_malloc(mrb, capacity+1); @@ -129,15 +132,12 @@ resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) RSTR_UNSET_EMBED_FLAG(s); s->as.heap.ptr = tmp; s->as.heap.len = len; - s->as.heap.aux.capa = capacity; + s->as.heap.aux.capa = (mrb_int)capacity; } } else { -#if SIZE_MAX > MRB_INT_MAX - mrb_assert(capacity <= MRB_INT_MAX); -#endif - s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1); - s->as.heap.aux.capa = capacity; + s->as.heap.ptr = (char*)mrb_realloc(mrb, RSTR_PTR(s), capacity+1); + s->as.heap.aux.capa = (mrb_int)capacity; } } @@ -154,22 +154,26 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) off = ptr - RSTR_PTR(s); } - if (RSTR_EMBED_P(s)) - capa = RSTRING_EMBED_LEN_MAX; - else - capa = s->as.heap.aux.capa; + capa = RSTR_CAPA(s); + if (capa <= RSTRING_EMBED_LEN_MAX) + capa = RSTRING_EMBED_LEN_MAX+1; total = RSTR_LEN(s)+len; if (total >= MRB_INT_MAX) { + size_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); } if (capa <= total) { while (total > capa) { - if (capa + 1 >= MRB_INT_MAX / 2) { - capa = MRB_INT_MAX; - break; + if (capa <= MRB_INT_MAX / 2) { + capa *= 2; } - capa = (capa + 1) * 2; + else { + capa = total; + } + } + if (capa < total || capa > MRB_INT_MAX) { + goto size_error; } resize_capa(mrb, s, capa); } @@ -515,6 +519,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) long len; check_frozen(mrb, s1); + if (s1 == s2) return mrb_obj_value(s1); len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -665,7 +670,7 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; - if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { + if (shared->nofree == 0 && shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { s->as.heap.ptr = shared->ptr; s->as.heap.aux.capa = shared->len; RSTR_PTR(s)[s->as.heap.len] = '\0'; @@ -691,14 +696,21 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) } if (RSTR_NOFREE_P(s)) { char *p = s->as.heap.ptr; + mrb_int len = s->as.heap.len; - s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1); + RSTR_UNSET_NOFREE_FLAG(s); + if (len < RSTRING_EMBED_LEN_MAX) { + RSTR_SET_EMBED_FLAG(s); + RSTR_SET_EMBED_LEN(s, len); + } + else { + s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1); + s->as.heap.aux.capa = len; + } if (p) { - memcpy(RSTR_PTR(s), p, s->as.heap.len); + memcpy(RSTR_PTR(s), p, len); } - RSTR_PTR(s)[s->as.heap.len] = '\0'; - s->as.heap.aux.capa = s->as.heap.len; - RSTR_UNSET_NOFREE_FLAG(s); + RSTR_PTR(s)[len] = '\0'; return; } } @@ -754,8 +766,14 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) other = mrb_str_to_str(mrb, other); } s2 = mrb_str_ptr(other); + if (RSTR_LEN(s2) == 0) { + return; + } len = RSTR_LEN(s1) + RSTR_LEN(s2); + if (len < 0 || len >= MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); + } if (RSTRING_CAPA(self) < len) { resize_capa(mrb, s1, len); } @@ -134,8 +134,8 @@ static void stack_extend_alloc(mrb_state *mrb, int room, int keep) { mrb_value *oldbase = mrb->c->stbase; - int size = mrb->c->stend - mrb->c->stbase; - int off = mrb->c->stack - mrb->c->stbase; + size_t size = mrb->c->stend - mrb->c->stbase; + size_t off = mrb->c->stack - mrb->c->stbase; #ifdef MRB_STACK_EXTEND_DOUBLING if (room <= size) @@ -373,7 +373,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb_method_missing(mrb, mid, self, args); } undef = mid; - n++; argc++; + argc++; } ci = cipush(mrb); ci->mid = mid; @@ -389,8 +389,18 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->nregs = argc + 2; stack_extend(mrb, ci->nregs, 0); } + else if (argc >= CALL_MAXARGS) { + mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); + stack_extend(mrb, ci->nregs, 0); + mrb->c->stack[1] = args; + if (undef) { + mrb_ary_unshift(mrb, mrb->c->stack[1], mrb_symbol_value(undef)); + } + ci->argc = -1; + argc = 1; + } else { - ci->nregs = p->body.irep->nregs + n; + ci->nregs = p->body.irep->nregs + argc; stack_extend(mrb, ci->nregs, argc+2); } if (voff >= 0) { @@ -403,7 +413,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc stack_copy(mrb->c->stack+2, argv, argc-1); } } - else if (argc > 0) { + else if (ci->argc > 0) { stack_copy(mrb->c->stack+1, argv, argc); } mrb->c->stack[argc+1] = blk; @@ -707,15 +717,22 @@ argnum_error(mrb_state *mrb, mrb_int num) { mrb_value exc; mrb_value str; + mrb_int argc = mrb->c->ci->argc; + if (argc < 0) { + mrb_value args = mrb->c->stack[1]; + if (mrb_array_p(args)) { + argc = RARRAY_LEN(args); + } + } if (mrb->c->ci->mid) { str = mrb_format(mrb, "'%S': wrong number of arguments (%S for %S)", mrb_sym2str(mrb, mrb->c->ci->mid), - mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num)); + mrb_fixnum_value(argc), mrb_fixnum_value(num)); } else { str = mrb_format(mrb, "wrong number of arguments (%S for %S)", - mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num)); + mrb_fixnum_value(argc), mrb_fixnum_value(num)); } exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str); mrb_exc_set(mrb, exc); @@ -1143,6 +1160,9 @@ RETRY_TRY_BLOCK: else { value_move(regs+a+2, regs+a+1, ++n); regs[a+1] = sym; + if (n == CALL_MAXARGS) { + regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + } } } @@ -1285,7 +1305,7 @@ RETRY_TRY_BLOCK: int a = GETARG_A(i); int n = GETARG_C(i); - if (mid == 0) { + if (mid == 0 || !mrb->c->ci->target_class) { mrb_value exc; exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method"); @@ -2408,7 +2428,8 @@ RETRY_TRY_BLOCK: CASE(OP_RANGE) { /* A B C R(A) := range_new(R(B),R(B+1),C) */ int b = GETARG_B(i); - regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); + mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); + regs[GETARG_A(i)] = val; ARENA_RESTORE(mrb, ai); NEXT; } @@ -2474,7 +2495,12 @@ RETRY_TRY_BLOCK: MRB_API mrb_value mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) { - return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */ + if (mrb->c->ci->argc < 0) { + return mrb_vm_run(mrb, proc, self, 3); /* receiver, args and block) */ + } + else { + return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */ + } } MRB_API mrb_value |
