diff --git a/collects/tests/racket/basic.rktl b/collects/tests/racket/basic.rktl index cc9fbc3a18..76efb190ab 100644 --- a/collects/tests/racket/basic.rktl +++ b/collects/tests/racket/basic.rktl @@ -2346,6 +2346,47 @@ (arity-test hash-eq? 1 1) (arity-test hash-weak? 1 1) +;; Ensure that hash-table hashing is not sensitive to the +;; order of key+value additions +(let () + (define ht (make-hash)) + (define ht2 (make-hash)) + + (struct a (x) #:transparent) + + (define (shuffle c l) + (if (zero? c) + l + (shuffle + (sub1 c) + (let ([n (quotient (length l) 2)]) + (let loop ([a (take l n)][b (drop l n)]) + (cond + [(null? a) b] + [(null? b) a] + [(zero? (random 2)) + (cons (car a) (loop (cdr a) b))] + [else + (cons (car b) (loop a (cdr b)))])))))) + + (define l (for/list ([i (in-range 1000)]) + i)) + + (define l2 (shuffle 7 l)) + + (for ([i (in-list l)]) + (hash-set! ht (a i) (a (a i)))) + (for ([i (in-list l2)]) + (hash-set! ht2 (a i) (a (a i)))) + + (test (equal-hash-code ht) values (equal-hash-code ht2)) + + (let ([ht (for/hash ([i (in-list l)]) + (values (a i) (a (a i))))] + [ht2 (for/hash ([i (in-list l2)]) + (values (a i) (a (a i))))]) + (test (equal-hash-code ht) values (equal-hash-code ht2)))) + ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Misc diff --git a/src/racket/src/hash.c b/src/racket/src/hash.c index 346f193743..5ca641a4ce 100644 --- a/src/racket/src/hash.c +++ b/src/racket/src/hash.c @@ -1207,12 +1207,13 @@ static long equal_hash_key(Scheme_Object *o, long k, Hash_Info *hi) Scheme_Hash_Table *ht = (Scheme_Hash_Table *)o; Scheme_Object **vals, **keys; int i; - long vk; + long vk, old_depth; # include "mzhashchk.inc" k = (k << 1) + 3; hi->depth += 2; + old_depth = hi->depth; keys = ht->keys; vals = ht->vals; @@ -1223,6 +1224,7 @@ static long equal_hash_key(Scheme_Object *o, long k, Hash_Info *hi) vk += equal_hash_key(vals[i], 0, hi); MZ_MIX(vk); k += vk; /* can't mix k, because the key order shouldn't matter */ + hi->depth = old_depth; /* also needed to avoid order-sensitivity */ } } @@ -1233,13 +1235,14 @@ static long equal_hash_key(Scheme_Object *o, long k, Hash_Info *hi) Scheme_Hash_Tree *ht = (Scheme_Hash_Tree *)o; Scheme_Object *ik, *iv; int i; - long vk; + long vk, old_depth; # include "mzhashchk.inc" k = (k << 1) + 3; hi->depth += 2; - + old_depth = hi->depth; + for (i = ht->count; i--; ) { scheme_hash_tree_index(ht, i, &ik, &iv); vk = equal_hash_key(ik, 0, hi); @@ -1247,6 +1250,7 @@ static long equal_hash_key(Scheme_Object *o, long k, Hash_Info *hi) vk += equal_hash_key(iv, 0, hi); MZ_MIX(vk); k += vk; /* can't mix k, because the key order shouldn't matter */ + hi->depth = old_depth; /* also needed to avoid order-sensitivity */ } return k;