Advisory: broken copy-hash function.

 new new list compose Reply to this message Top page
Attachments:
+ (text/plain)

Delete this message
Author: Kaz Kylheku
Date:  
To: TXR Users
Subject: Advisory: broken copy-hash function.
Hi all,

The copy-hash function has been broken since May 2016.
The hash-diff function is also broken, since it depends
on it.

The patch follows:

From: Kaz Kylheku <kaz@???>
Date: Mon, 23 Oct 2017 06:35:35 -0700
Subject: [PATCH] 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.
---
hash.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/hash.c b/hash.c
index 8d3f2b3..444a32b 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;
  }