From 6f10f06c2776c8dfa7e727f2a000dc48bd296bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Lindqvist?= Date: Wed, 5 Oct 2016 19:09:55 +0200 Subject: [PATCH] hash-sets,hashtables: make it so the array backing the hash is non-empty Commit 70c7f9e02910746918cc16bf588ef543fda80790 made it so the code assumes the array is not empty. But it can be empty if the hashtable is created using "hashtable new" and then it can crash because it reads uninitialized memory. Setting the initial of the array slot to a valid hash-array should fix that. --- core/hash-sets/hash-sets.factor | 5 ++++- core/hashtables/hashtables-tests.factor | 21 ++++++++++++++++++--- core/hashtables/hashtables.factor | 8 +++++++- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/core/hash-sets/hash-sets.factor b/core/hash-sets/hash-sets.factor index 03577db12a..6bbd327371 100644 --- a/core/hash-sets/hash-sets.factor +++ b/core/hash-sets/hash-sets.factor @@ -10,7 +10,10 @@ IN: hash-sets TUPLE: hash-set { count array-capacity } { deleted array-capacity } - { array array } ; + { array array initial: { + T{ tombstone } T{ tombstone } T{ tombstone } T{ tombstone } + } + } ; hash@ +] unit-test { H{ } } [ { } [ dup ] H{ } map>assoc ] unit-test @@ -182,5 +188,14 @@ H{ } "x" set { 1 } [ 2 "h" get at ] unit-test +! Previously this could break as hashtable new created a backing an +! empty backing array and the code assumed its length was > 0. +{ f f } [ + compact-gc 77 hashtable new [ clone ] change-array at* +] unit-test + ! Random test case -{ "A" } [ 100 iota [ dup ] H{ } map>assoc 32 over delete-at "A" 32 pick set-at 32 of ] unit-test +{ "A" } [ + 100 iota [ dup ] H{ } map>assoc 32 over + delete-at "A" 32 pick set-at 32 of +] unit-test diff --git a/core/hashtables/hashtables.factor b/core/hashtables/hashtables.factor index ee14103cb8..6e2903d8ee 100644 --- a/core/hashtables/hashtables.factor +++ b/core/hashtables/hashtables.factor @@ -4,10 +4,16 @@ USING: accessors arrays assocs kernel kernel.private math math.private sequences sequences.private slots.private vectors ; IN: hashtables +! Required because the hashtable definition references tombstone. + + TUPLE: hashtable { count array-capacity } { deleted array-capacity } - { array array } ; + { array array initial: { + T{ tombstone } T{ tombstone } T{ tombstone } T{ tombstone } + } + } ;