diff options
author | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-09-22 04:48:52 +0000 |
---|---|---|
committer | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-09-22 04:48:52 +0000 |
commit | 0c97c8e33584e6203bb09c08f92b63bd2cca8ae7 (patch) | |
tree | 8006036c98680136b7470af4431d95663fcfffec | |
parent | 56173249ef486db321c8aa01a680966f921f5201 (diff) | |
download | bundler-0c97c8e33584e6203bb09c08f92b63bd2cca8ae7.tar.gz |
* hash.c (rb_hash_rehash): add iteration check. [ruby-dev:24301]
* st.c (st_foreach): add deep check.
* hash.c (rb_hash_fetch): returns KeyError instead of IndexError.
* hash.c (env_fetch): ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@6950 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | error.c | 2 | ||||
-rw-r--r-- | hash.c | 89 | ||||
-rw-r--r-- | ruby.h | 1 | ||||
-rw-r--r-- | st.c | 16 | ||||
-rw-r--r-- | st.h | 34 |
6 files changed, 103 insertions, 49 deletions
@@ -1,3 +1,13 @@ +Wed Sep 22 13:38:12 2004 Yukihiro Matsumoto <matz@ruby-lang.org> + + * hash.c (rb_hash_rehash): add iteration check. [ruby-dev:24301] + + * st.c (st_foreach): add deep check. + + * hash.c (rb_hash_fetch): returns KeyError instead of IndexError. + + * hash.c (env_fetch): ditto. + Wed Sep 22 13:02:02 2004 NAKAMURA Usaku <usa@ruby-lang.org> * win32/win32.c (rb_w32_call_handler): workaround for Ctrl-C. @@ -297,6 +297,7 @@ VALUE rb_eRuntimeError; VALUE rb_eTypeError; VALUE rb_eArgError; VALUE rb_eIndexError; +VALUE rb_eKeyError; VALUE rb_eRangeError; VALUE rb_eNameError; VALUE rb_eNoMethodError; @@ -1052,6 +1053,7 @@ Init_Exception() rb_eTypeError = rb_define_class("TypeError", rb_eStandardError); rb_eArgError = rb_define_class("ArgumentError", rb_eStandardError); rb_eIndexError = rb_define_class("IndexError", rb_eStandardError); + rb_eKeyError = rb_define_class("KeyError", rb_eIndexError); rb_eRangeError = rb_define_class("RangeError", rb_eStandardError); rb_eNameError = rb_define_class("NameError", rb_eStandardError); rb_define_method(rb_eNameError, "initialize", name_err_initialize, -1); @@ -24,16 +24,6 @@ #define HASH_DELETED FL_USER1 #define HASH_PROC_DEFAULT FL_USER2 -static void -rb_hash_modify(hash) - VALUE hash; -{ - if (!RHASH(hash)->tbl) rb_raise(rb_eTypeError, "uninitialized Hash"); - if (OBJ_FROZEN(hash)) rb_error_frozen("hash"); - if (!OBJ_TAINTED(hash) && rb_safe_level() >= 4) - rb_raise(rb_eSecurityError, "Insecure: can't modify hash"); -} - VALUE rb_hash_freeze(hash) VALUE hash; @@ -121,24 +111,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_eArgError, "rehash occurred during iteration"); - } - if (RHASH(arg->hash)->iter_lev == 0) { - rb_raise(rb_eArgError, "block re-entered"); + if (RHASH(arg->hash)->tbl != tbl) { + rb_raise(rb_eRuntimeError, "rehash occurred during iteration"); + } + 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 @@ -188,7 +187,7 @@ hash_alloc(klass) OBJSETUP(hash, klass, T_HASH); hash->ifnone = Qnil; - hash->tbl = st_init_table(&objhash); + hash->tbl = 0; return (VALUE)hash; } @@ -199,6 +198,18 @@ rb_hash_new() return hash_alloc(rb_cHash); } +static void +rb_hash_modify(hash) + VALUE hash; +{ + if (OBJ_FROZEN(hash)) rb_error_frozen("hash"); + if (!OBJ_TAINTED(hash) && rb_safe_level() >= 4) + rb_raise(rb_eSecurityError, "Insecure: can't modify hash"); + if (RHASH(hash)->tbl == 0) { + RHASH(hash)->tbl = st_init_table(&objhash); + } +} + /* * call-seq: * Hash.new => hash @@ -325,7 +336,7 @@ rb_hash_rehash_i(key, value, tbl) * values of key objects have changed since they were inserted, this * method will reindex <i>hsh</i>. If <code>Hash#rehash</code> is * called while an iterator is traversing the hash, an - * <code>IndexError</code> will be raised in the iterator. + * <code>RuntimeError</code> will be raised in the iterator. * * a = [ "a", "b" ] * c = [ "c", "d" ] @@ -343,6 +354,9 @@ rb_hash_rehash(hash) { st_table *tbl; + if (RHASH(hash)->iter_lev > 0) { + rb_raise(rb_eRuntimeError, "rehash during iteration"); + } rb_hash_modify(hash); tbl = st_init_table_with_size(&objhash, RHASH(hash)->tbl->num_entries); st_foreach(RHASH(hash)->tbl, rb_hash_rehash_i, (st_data_t)tbl); @@ -385,7 +399,7 @@ rb_hash_aref(hash, key) * * Returns a value from the hash for the given key. If the key can't be * found, there are several options: With no other arguments, it will - * raise an <code>IndexError</code> exception; if <i>default</i> is + * raise an <code>KeyError</code> exception; if <i>default</i> is * given, then that will be returned; if the optional code block is * specified, then that will be run and its result returned. * @@ -402,7 +416,7 @@ rb_hash_aref(hash, key) * * <em>produces:</em> * - * prog.rb:2:in `fetch': key not found (IndexError) + * prog.rb:2:in `fetch': key not found (KeyError) * from prog.rb:2 * */ @@ -426,7 +440,7 @@ rb_hash_fetch(argc, argv, hash) if (!st_lookup(RHASH(hash)->tbl, key, &val)) { if (block_given) return rb_yield(key); if (argc == 1) { - rb_raise(rb_eIndexError, "key not found"); + rb_raise(rb_eKeyError, "key not found"); } return if_none; } @@ -525,7 +539,7 @@ rb_hash_default_proc(hash) } static int -index_i(key, value, args) +key_i(key, value, args) VALUE key, value; VALUE *args; { @@ -538,7 +552,7 @@ index_i(key, value, args) /* * call-seq: - * hsh.index(value) => key + * hsh.key(value) => key * * Returns the key for a given value. If not found, returns <code>nil</code>. * @@ -549,7 +563,7 @@ index_i(key, value, args) */ static VALUE -rb_hash_index(hash, value) +rb_hash_key(hash, value) VALUE hash, value; { VALUE args[2]; @@ -557,11 +571,19 @@ rb_hash_index(hash, value) args[0] = value; args[1] = Qnil; - st_foreach(RHASH(hash)->tbl, index_i, (st_data_t)args); + st_foreach(RHASH(hash)->tbl, key_i, (st_data_t)args); return args[1]; } +static VALUE +rb_hash_index(hash, value) + VALUE hash, value; +{ + rb_warn("Hash#index is deprecated; use Hash#key"); + return rb_hash_key(hash, value); +} + /* * call-seq: * hsh.delete(key) => value @@ -803,8 +825,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; } @@ -1671,7 +1697,7 @@ env_fetch(argc, argv) if (!env) { if (block_given) return rb_yield(key); if (argc == 1) { - rb_raise(rb_eIndexError, "key not found"); + rb_raise(rb_eKeyError, "key not found"); } return if_none; } @@ -2345,6 +2371,7 @@ Init_Hash() rb_define_method(rb_cHash,"default", rb_hash_default, -1); rb_define_method(rb_cHash,"default=", rb_hash_set_default, 1); rb_define_method(rb_cHash,"default_proc", rb_hash_default_proc, 0); + rb_define_method(rb_cHash,"key", rb_hash_key, 1); rb_define_method(rb_cHash,"index", rb_hash_index, 1); rb_define_method(rb_cHash,"size", rb_hash_size, 0); rb_define_method(rb_cHash,"length", rb_hash_size, 0); @@ -604,6 +604,7 @@ RUBY_EXTERN VALUE rb_eFatal; RUBY_EXTERN VALUE rb_eArgError; RUBY_EXTERN VALUE rb_eEOFError; RUBY_EXTERN VALUE rb_eIndexError; +RUBY_EXTERN VALUE rb_eKeyError; RUBY_EXTERN VALUE rb_eRangeError; RUBY_EXTERN VALUE rb_eIOError; RUBY_EXTERN VALUE rb_eRuntimeError; @@ -3,6 +3,7 @@ /* static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */ #include "config.h" +#include "defines.h" #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -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; @@ -25,23 +25,23 @@ 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}; - -st_table *st_init_table(struct st_hash_type *); -st_table *st_init_table_with_size(struct st_hash_type *, int); -st_table *st_init_numtable(void); -st_table *st_init_numtable_with_size(int); -st_table *st_init_strtable(void); -st_table *st_init_strtable_with_size(int); -int st_delete(st_table *, st_data_t *, st_data_t *); -int st_delete_safe(st_table *, st_data_t *, st_data_t *, st_data_t); -int st_insert(st_table *, st_data_t, st_data_t); -int st_lookup(st_table *, st_data_t, st_data_t *); -void st_foreach(st_table *, int (*)(), st_data_t); -void st_add_direct(st_table *, st_data_t, st_data_t); -void st_free_table(st_table *); -void st_cleanup_safe(st_table *, st_data_t); -st_table *st_copy(st_table *); +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)); +st_table *st_init_numtable _((void)); +st_table *st_init_numtable_with_size _((int)); +st_table *st_init_strtable _((void)); +st_table *st_init_strtable_with_size _((int)); +int st_delete _((st_table *, st_data_t *, st_data_t *)); +int st_delete_safe _((st_table *, st_data_t *, st_data_t *, st_data_t)); +int st_insert _((st_table *, st_data_t, st_data_t)); +int st_lookup _((st_table *, st_data_t, st_data_t *)); +void st_foreach _((st_table *, int (*)(), st_data_t)); +void st_add_direct _((st_table *, st_data_t, st_data_t)); +void st_free_table _((st_table *)); +void st_cleanup_safe _((st_table *, st_data_t)); +st_table *st_copy _((st_table *)); #define ST_NUMCMP ((int (*)()) 0) #define ST_NUMHASH ((int (*)()) -2) |