diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2023-06-19 20:02:12 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2023-06-19 20:02:12 -0700 |
commit | 96f428d5e3f77c21ba625fdbe3ca1fd3afda1755 (patch) | |
tree | 575d97f7c9e71ec8806080e29c3e8839d079124c | |
parent | 7c6eba0aa30cad6c2115d5d05d11333a4489bfd4 (diff) | |
download | txr-96f428d5e3f77c21ba625fdbe3ca1fd3afda1755.tar.gz txr-96f428d5e3f77c21ba625fdbe3ca1fd3afda1755.tar.bz2 txr-96f428d5e3f77c21ba625fdbe3ca1fd3afda1755.zip |
hash: bug: initial hash mask miscalculation.
Hash tables are supposed to start with a mask of 255,
which is the 256 modulus less one. However, due to a
coding mistake, they get a modulus of 252. Now this still
works. It just has a few zero bits in it: 1111 1100
rather than 11111111. When this grows by doubling in size,
we get 1 1111 1001, 11 1111 0011 and so on.
Now this still all works, because hash values AND-ed
with such a mask are no greater than that mask. The
table isn't accessed out of bounds. It's just inefficiently
used.
* hash.c (do_make_hash, make_similar_hash, clearhash):
When converting the power-of-two modulus, which is a Lisp
word, to the integer mask, subtract 1 from the integer
value, not the original Lisp word.
-rw-r--r-- | hash.c | 6 |
1 files changed, 3 insertions, 3 deletions
@@ -924,7 +924,7 @@ static val do_make_hash(hash_weak_opt_t wkopt, hash_type_t type, val seed) h->seed = c_unum(default_arg(seed, if3(hash_seed_s, hash_seed, zero)), self); h->wkopt = wkopt; - h->mask = c_unum(mod - 1, self); + h->mask = c_unum(mod, self) - 1; h->count = 0; h->table = table; h->userdata = nil; @@ -996,7 +996,7 @@ val make_similar_hash(val existing) val table = vector(mod, nil); val hash = cobj(coerce(mem_t *, h), hash_cls, &hash_ops); - h->mask = c_unum(mod - 1, self); + h->mask = c_unum(mod, self) - 1; h->count = 0; h->table = table; h->userdata = ex->userdata; @@ -1147,7 +1147,7 @@ val clearhash(val hash) val mod = num_fast(256); val table = vector(mod, nil); ucnum oldcount = h->count; - h->mask = c_unum(mod - 1, self); + h->mask = c_unum(mod, self) - 1; h->count = 0; h->table = table; setcheck(hash, table); |