From 9dcc08646f0a26b61ae162daffeb0ce5fbc60f0e Mon Sep 17 00:00:00 2001 From: matz Date: Wed, 22 Sep 2004 04:47:37 +0000 Subject: [PATCH] * hash.c (rb_hash_rehash): add iteration check. [ruby-dev:24301] * st.c (st_foreach): add deep check. * array.c (rb_ary_collect_bang): element size might change during comparison. [ruby-dev:24300] * array.c (rb_ary_reject_bang): ditto. [ruby-dev:24300] * array.c (rb_ary_eql): ditto. [ruby-dev:24300] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@6949 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 15 +++++++++++++++ array.c | 12 +++++++----- hash.c | 33 +++++++++++++++++++++++---------- st.c | 16 +++++++++++++++- st.h | 2 +- 5 files changed, 61 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7ab1878fc3..047d51e6f7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Wed Sep 22 13:38:12 2004 Yukihiro Matsumoto + + * hash.c (rb_hash_rehash): add iteration check. [ruby-dev:24301] + + * st.c (st_foreach): add deep check. + Wed Sep 22 13:06:14 2004 NAKAMURA Usaku * win32/win32.c (rb_w32_call_handler): workaround for Ctrl-C. @@ -7,6 +13,15 @@ Wed Sep 22 00:11:12 2004 Dave Thomas * process.c: Add documentation for fork() +Wed Sep 22 09:04:41 2004 Yukihiro Matsumoto + + * array.c (rb_ary_collect_bang): element size might change during + comparison. [ruby-dev:24300] + + * array.c (rb_ary_reject_bang): ditto. [ruby-dev:24300] + + * array.c (rb_ary_eql): ditto. [ruby-dev:24300] + Tue Sep 21 18:29:49 2004 Yukihiro Matsumoto * array.c (rb_ary_equal): merge miss. diff --git a/array.c b/array.c index b921e55a2f..da32a8984e 100644 --- a/array.c +++ b/array.c @@ -1717,7 +1717,7 @@ rb_ary_collect_bang(ary) rb_ary_modify(ary); for (i = 0; i < RARRAY(ary)->len; i++) { - RARRAY(ary)->ptr[i] = rb_yield(RARRAY(ary)->ptr[i]); + rb_ary_store(ary, i, rb_yield(RARRAY(ary)->ptr[i])); } return ary; } @@ -1983,14 +1983,16 @@ rb_ary_reject_bang(ary) rb_ary_modify(ary); for (i1 = i2 = 0; i1 < RARRAY(ary)->len; i1++) { - if (RTEST(rb_yield(RARRAY(ary)->ptr[i1]))) continue; + VALUE v = RARRAY(ary)->ptr[i1]; + if (RTEST(rb_yield(v))) continue; if (i1 != i2) { - RARRAY(ary)->ptr[i2] = RARRAY(ary)->ptr[i1]; + rb_ary_store(ary, i2, v); } i2++; } if (RARRAY(ary)->len == i2) return Qnil; - RARRAY(ary)->len = i2; + if (i2 < RARRAY(ary)->len) + RARRAY(ary)->len = i2; return ary; } @@ -2497,7 +2499,7 @@ rb_ary_eql(ary1, ary2) if (TYPE(ary2) != T_ARRAY) return Qfalse; if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse; for (i=0; ilen; i++) { - if (!rb_eql(RARRAY(ary1)->ptr[i], RARRAY(ary2)->ptr[i])) + if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i))) return Qfalse; } return Qtrue; diff --git a/hash.c b/hash.c index 89666ca831..4485305024 100644 --- a/hash.c +++ b/hash.c @@ -121,24 +121,33 @@ struct rb_hash_foreach_arg { }; static int -rb_hash_foreach_iter(key, value, arg) +rb_hash_foreach_iter(key, value, arg, err) VALUE key, value; struct rb_hash_foreach_arg *arg; + int err; { int status; - st_table *tbl = RHASH(arg->hash)->tbl; - struct st_table_entry **bins = tbl->bins; + st_table *tbl; + if (err) { + rb_raise(rb_eRuntimeError, "hash modified during iteration"); + } + tbl = RHASH(arg->hash)->tbl; if (key == Qundef) return ST_CONTINUE; status = (*arg->func)(key, value, arg->arg); - if (RHASH(arg->hash)->tbl != tbl || - RHASH(arg->hash)->tbl->bins != bins) { - rb_raise(rb_eIndexError, "rehash occurred during iteration"); + if (RHASH(arg->hash)->tbl != tbl) { + rb_raise(rb_eRuntimeError, "rehash occurred during iteration"); } - if (RHASH(arg->hash)->iter_lev == 0) { - rb_raise(rb_eArgError, "block re-entered"); + switch (status) { + case ST_DELETE: + st_delete_safe(tbl, (st_data_t*)&key, 0, Qundef); + FL_SET(arg->hash, HASH_DELETED); + case ST_CONTINUE: + break; + case ST_STOP: + return ST_STOP; } - return status; + return ST_CHECK; } static VALUE @@ -836,8 +845,12 @@ static VALUE rb_hash_clear(hash) VALUE hash; { + void *tmp; + rb_hash_modify(hash); - st_foreach(RHASH(hash)->tbl, clear_i, 0); + if (RHASH(hash)->tbl->num_entries > 0) { + st_foreach(RHASH(hash)->tbl, clear_i, 0); + } return hash; } diff --git a/st.c b/st.c index 753dce9a02..12ed401145 100644 --- a/st.c +++ b/st.c @@ -3,6 +3,7 @@ /* static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */ #include "config.h" +#include "defines.h" #include #include #include @@ -492,8 +493,21 @@ st_foreach(table, func, arg) for(i = 0; i < table->num_bins; i++) { last = 0; for(ptr = table->bins[i]; ptr != 0;) { - retval = (*func)(ptr->key, ptr->record, arg); + retval = (*func)(ptr->key, ptr->record, arg, 0); switch (retval) { + case ST_CHECK: /* check if hash is modified during iteration */ + tmp = 0; + if (i < table->num_bins) { + for (tmp = table->bins[i]; tmp; tmp=tmp->next) { + if (tmp == ptr) break; + } + } + if (!tmp) { + /* call func with error notice */ + retval = (*func)(0, 0, arg, 1); + return; + } + /* fall through */ case ST_CONTINUE: last = ptr; ptr = ptr->next; diff --git a/st.h b/st.h index bbb4306abf..cdf8a1220b 100644 --- a/st.h +++ b/st.h @@ -25,7 +25,7 @@ struct st_table { #define st_is_member(table,key) st_lookup(table,key,(st_data_t *)0) -enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE}; +enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE, ST_CHECK}; st_table *st_init_table(struct st_hash_type *); st_table *st_init_table_with_size(struct st_hash_type *, int);