summaryrefslogtreecommitdiffstats
path: root/hash.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-10-23 06:35:35 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-10-23 06:35:35 -0700
commit09ababf4284febbc9c96a62e6711826d110e3eb1 (patch)
tree06c07a6fcda4d4e29048fb688c83100ccc903c1f /hash.c
parent6fb9b42ea256a50d00d4e3c3e37cb7866c4baf29 (diff)
downloadtxr-09ababf4284febbc9c96a62e6711826d110e3eb1.tar.gz
txr-09ababf4284febbc9c96a62e6711826d110e3eb1.tar.bz2
txr-09ababf4284febbc9c96a62e6711826d110e3eb1.zip
hash: fix broken copy_hash.
Impact assessment: this bug affects the correctness of all programs which rely on copying hash tables. Direct reliance means the use of copy-hash, or using the generic copy function on hash objects. Indirect reliance occurs through hash-diff which uses copy-hash. Nothing in TXR itself calls hash-diff. The the listener's Tab completion relies on copy-hash for package-sensitive symbol visibility calculation. Since that is an interactive feature, the impact is low. * hash.c (copy_hash_chain): New static function. (copy_hash): Use copy_hash_chain instead of copy_alist, since the pairs are hash conses and not regular conses: they have a hash value field that must be copied.
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/hash.c b/hash.c
index 8d3f2b37..444a32b8 100644
--- a/hash.c
+++ b/hash.c
@@ -677,6 +677,20 @@ val make_similar_hash(val existing)
return hash;
}
+static val copy_hash_chain(val chain)
+{
+ list_collect_decl(out, ptail);
+
+ for (; chain; chain = cdr(chain)) {
+ val entry = car(chain);
+ val nentry = cons(car(entry), cdr(entry));
+ nentry->ch.hash = entry->ch.hash;
+ ptail = list_collect(ptail, nentry);
+ }
+
+ return out;
+}
+
val copy_hash(val existing)
{
struct hash *ex = coerce(struct hash *, cobj_handle(existing, hash_s));
@@ -698,7 +712,7 @@ val copy_hash(val existing)
h->acons_new_c_fun = ex->acons_new_c_fun;
for (iter = zero; lt(iter, mod); iter = plus(iter, one))
- set(vecref_l(h->table, iter), copy_alist(vecref(ex->table, iter)));
+ set(vecref_l(h->table, iter), copy_hash_chain(vecref(ex->table, iter)));
return hash;
}