mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* 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
This commit is contained in:
		
							parent
							
								
									56173249ef
								
							
						
					
					
						commit
						0c97c8e335
					
				
					 6 changed files with 101 additions and 47 deletions
				
			
		
							
								
								
									
										10
									
								
								ChangeLog
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								ChangeLog
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								error.c
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								error.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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										87
									
								
								hash.c
									
										
									
									
									
								
							
							
						
						
									
										87
									
								
								hash.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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)->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
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								ruby.h
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								ruby.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								st.c
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								st.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										32
									
								
								st.h
									
										
									
									
									
								
							
							
						
						
									
										32
									
								
								st.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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};
 | 
			
		||||
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 *);
 | 
			
		||||
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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue