diff --git a/ChangeLog b/ChangeLog index 2eff9f5e80..909f2e4fc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Tue Jun 5 20:13:15 2012 Nobuyoshi Nakada + + * object.c (rb_obj_init_copy): should check if trusted too. + Tue Jun 5 19:59:13 2012 Tanaka Akira * process.c (strtok): declaration removed because it is not used. diff --git a/enumerator.c b/enumerator.c index e62eabf61f..f01ddd51e6 100644 --- a/enumerator.c +++ b/enumerator.c @@ -373,6 +373,7 @@ enumerator_init_copy(VALUE obj, VALUE orig) { struct enumerator *ptr0, *ptr1; + if (!OBJ_INIT_COPY(obj, orig)) return obj; ptr0 = enumerator_ptr(orig); if (ptr0->fib) { /* Fibers cannot be copied */ @@ -1146,6 +1147,8 @@ generator_init_copy(VALUE obj, VALUE orig) { struct generator *ptr0, *ptr1; + if (!OBJ_INIT_COPY(obj, orig)) return obj; + ptr0 = generator_ptr(orig); TypedData_Get_Struct(obj, struct generator, &generator_data_type, ptr1); diff --git a/file.c b/file.c index 846f3147f9..6fc64a4739 100644 --- a/file.c +++ b/file.c @@ -4470,12 +4470,7 @@ rb_stat_init_copy(VALUE copy, VALUE orig) { struct stat *nst; - if (copy == orig) return orig; - rb_check_frozen(copy); - /* need better argument type check */ - if (!rb_obj_is_instance_of(orig, rb_obj_class(copy))) { - rb_raise(rb_eTypeError, "wrong argument class"); - } + if (!OBJ_INIT_COPY(copy, orig)) return copy; if (DATA_PTR(copy)) { xfree(DATA_PTR(copy)); DATA_PTR(copy) = 0; diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 9690964ac8..a3d583c2ea 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -252,6 +252,9 @@ rb_check_trusted_inline(VALUE obj) #define rb_check_trusted(obj) rb_check_trusted_inline(obj) #endif +#define OBJ_INIT_COPY(obj, orig) \ + ((obj) != (orig) && (rb_obj_init_copy((obj), (orig)), 1)) + /* eval.c */ int rb_sourceline(void); const char *rb_sourcefile(void); diff --git a/io.c b/io.c index 3d4fe54848..f24bfbb5b0 100644 --- a/io.c +++ b/io.c @@ -6387,7 +6387,7 @@ rb_io_init_copy(VALUE dest, VALUE io) off_t pos; io = rb_io_get_io(io); - if (dest == io) return dest; + if (!OBJ_INIT_COPY(dest, io)) return dest; GetOpenFile(io, orig); MakeOpenFile(dest, fptr); @@ -7286,6 +7286,7 @@ argf_initialize(VALUE argf, VALUE argv) static VALUE argf_initialize_copy(VALUE argf, VALUE orig) { + if (!OBJ_INIT_COPY(argf, orig)) return argf; ARGF = argf_of(orig); ARGF.argv = rb_obj_dup(ARGF.argv); if (ARGF.inplace) { diff --git a/object.c b/object.c index dbb8db63dd..1177466d7f 100644 --- a/object.c +++ b/object.c @@ -342,6 +342,7 @@ rb_obj_init_copy(VALUE obj, VALUE orig) { if (obj == orig) return obj; rb_check_frozen(obj); + rb_check_trusted(obj); if (TYPE(obj) != TYPE(orig) || rb_obj_class(obj) != rb_obj_class(orig)) { rb_raise(rb_eTypeError, "initialize_copy should take same class object"); } diff --git a/random.c b/random.c index 9dbcbd1d62..d05fe6d9c6 100644 --- a/random.c +++ b/random.c @@ -596,9 +596,14 @@ random_get_seed(VALUE obj) static VALUE random_copy(VALUE obj, VALUE orig) { - rb_random_t *rnd1 = get_rnd(obj); - rb_random_t *rnd2 = get_rnd(orig); - struct MT *mt = &rnd1->mt; + rb_random_t *rnd1, *rnd2; + struct MT *mt; + + if (!OBJ_INIT_COPY(obj, orig)) return obj; + + rnd1 = get_rnd(obj); + rnd2 = get_rnd(orig); + mt = &rnd1->mt; *rnd1 = *rnd2; mt->next = mt->state + numberof(mt->state) - mt->left + 1; diff --git a/re.c b/re.c index 500173d3cb..4191d5bcb8 100644 --- a/re.c +++ b/re.c @@ -939,11 +939,8 @@ match_init_copy(VALUE obj, VALUE orig) { struct rmatch *rm; - if (obj == orig) return obj; + if (!OBJ_INIT_COPY(obj, orig)) return obj; - if (!rb_obj_is_instance_of(orig, rb_obj_class(obj))) { - rb_raise(rb_eTypeError, "wrong argument class"); - } RMATCH(obj)->str = RMATCH(orig)->str; RMATCH(obj)->regexp = RMATCH(orig)->regexp; @@ -3260,12 +3257,7 @@ rb_reg_init_copy(VALUE copy, VALUE re) const char *s; long len; - if (copy == re) return copy; - rb_check_frozen(copy); - /* need better argument type check */ - if (!rb_obj_is_instance_of(re, rb_obj_class(copy))) { - rb_raise(rb_eTypeError, "wrong argument type"); - } + if (!OBJ_INIT_COPY(copy, re)) return copy; rb_reg_check(re); s = RREGEXP_SRC_PTR(re); len = RREGEXP_SRC_LEN(re); diff --git a/struct.c b/struct.c index 8168f62bb1..91d562b97c 100644 --- a/struct.c +++ b/struct.c @@ -606,11 +606,7 @@ rb_struct_to_h(VALUE s) VALUE rb_struct_init_copy(VALUE copy, VALUE s) { - if (copy == s) return copy; - rb_check_frozen(copy); - if (!rb_obj_is_instance_of(s, rb_obj_class(copy))) { - rb_raise(rb_eTypeError, "wrong argument class"); - } + if (!OBJ_INIT_COPY(copy, s)) return copy; if (RSTRUCT_LEN(copy) != RSTRUCT_LEN(s)) { rb_raise(rb_eTypeError, "struct size mismatch"); } diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb index d63886a81e..70dcd04201 100644 --- a/test/ruby/test_object.rb +++ b/test/ruby/test_object.rb @@ -764,4 +764,36 @@ class TestObject < Test::Unit::TestCase assert_equal((eval("raise #{code}") rescue $!.inspect), out.chomp, bug5473) end end + + def assert_not_initialize_copy + a = yield + b = yield + assert_nothing_raised("copy") {a.instance_eval {initialize_copy(b)}} + c = a.dup.freeze + assert_raise(RuntimeError, "frozen") {c.instance_eval {initialize_copy(b)}} + d = a.dup.trust + assert_raise(SecurityError, "untrust") do + proc { + $SAFE = 4 + d.instance_eval {initialize_copy(b)} + }.call + end + [a, b, c, d] + end + + def test_bad_initialize_copy + assert_not_initialize_copy {Object.new} + assert_not_initialize_copy {[].to_enum} + assert_not_initialize_copy {Enumerator::Generator.new {}} + assert_not_initialize_copy {Enumerator::Yielder.new {}} + assert_not_initialize_copy {File.stat(__FILE__)} + assert_not_initialize_copy {open(__FILE__)}.each(&:close) + assert_not_initialize_copy {ARGF.class.new} + assert_not_initialize_copy {Random.new} + assert_not_initialize_copy {//} + assert_not_initialize_copy {/.*/.match("foo")} + st = Struct.new(:foo) + assert_not_initialize_copy {st.new} + assert_not_initialize_copy {Time.now} + end end diff --git a/time.c b/time.c index b0a2be2455..0d771d2715 100644 --- a/time.c +++ b/time.c @@ -3425,8 +3425,7 @@ time_init_copy(VALUE copy, VALUE time) { struct time_object *tobj, *tcopy; - if (copy == time) return copy; - time_modify(copy); + if (!OBJ_INIT_COPY(copy, time)) return copy; GetTimeval(time, tobj); GetTimeval(copy, tcopy); MEMCPY(tcopy, tobj, struct time_object, 1);