]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix clrhash bug when hash table needs rehashing
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 22 Aug 2019 01:54:08 +0000 (18:54 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 22 Aug 2019 02:01:49 +0000 (19:01 -0700)
Problem reported by Pip Cet in:
https://lists.gnu.org/r/emacs-devel/2019-08/msg00316.html
* src/fns.c (maybe_resize_hash_table): Prefer ASET to gc_aset
where either will do.  Simplify appending of Qunbound values.
Put index_size calculation closer to where it’s needed.
(hash_clear): If hash_rehash_needed_p (h), don’t clear the
nonexistent hash vector.  Use memclear to speed up clearing.
* src/lisp.h (HASH_TABLE_SIZE): Check that the size is positive,
and tell that to the compiler.

src/fns.c
src/lisp.h

index b606d6299cae4445f41b168391b3ab7a7b0a3bde..8ca0953fe85d99402feed6f114c718932bd4fe63 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -4198,21 +4198,20 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h)
                                          new_size);
       ptrdiff_t next_size = ASIZE (next);
       for (ptrdiff_t i = old_size; i < next_size - 1; i++)
-       gc_aset (next, i, make_fixnum (i + 1));
-      gc_aset (next, next_size - 1, make_fixnum (-1));
-      ptrdiff_t index_size = hash_index_size (h, next_size);
+       ASET (next, i, make_fixnum (i + 1));
+      ASET (next, next_size - 1, make_fixnum (-1));
 
       /* Build the new&larger key_and_value vector, making sure the new
          fields are initialized to `unbound`.  */
       Lisp_Object key_and_value
        = larger_vecalloc (h->key_and_value, 2 * (next_size - old_size),
                           2 * next_size);
-      for (ptrdiff_t i = ASIZE (h->key_and_value);
-            i < ASIZE (key_and_value); i++)
+      for (ptrdiff_t i = 2 * old_size; i < 2 * next_size; i++)
         ASET (key_and_value, i, Qunbound);
 
       Lisp_Object hash = larger_vector (h->hash, next_size - old_size,
                                        next_size);
+      ptrdiff_t index_size = hash_index_size (h, next_size);
       h->index = make_vector (index_size, make_fixnum (-1));
       h->key_and_value = key_and_value;
       h->hash = hash;
@@ -4404,17 +4403,14 @@ hash_clear (struct Lisp_Hash_Table *h)
 {
   if (h->count > 0)
     {
-      ptrdiff_t i, size = HASH_TABLE_SIZE (h);
-
-      for (i = 0; i < size; ++i)
-       {
-         set_hash_next_slot (h, i, i < size - 1 ? i + 1 : -1);
-         set_hash_key_slot (h, i, Qunbound);
-         set_hash_value_slot (h, i, Qnil);
-         set_hash_hash_slot (h, i, Qnil);
-       }
-
-      for (i = 0; i < ASIZE (h->index); ++i)
+      ptrdiff_t size = HASH_TABLE_SIZE (h);
+      if (!hash_rehash_needed_p (h))
+       memclear (XVECTOR (h->hash)->contents, size * word_size);
+      memclear (XVECTOR (h->key_and_value)->contents, size * 2 * word_size);
+      for (ptrdiff_t i = 0; i < size; i++)
+       set_hash_next_slot (h, i, i < size - 1 ? i + 1 : -1);
+
+      for (ptrdiff_t i = 0; i < ASIZE (h->index); i++)
        ASET (h->index, i, make_fixnum (-1));
 
       h->next_free = 0;
index 56ad99b8e395a1a592ea0be8c2965f5ec75d4b4f..ae5a81e7b5ee61e4d10e10ba77b4ec1687e6e106 100644 (file)
@@ -2307,7 +2307,7 @@ struct Lisp_Hash_Table
      weakness of the table.  */
   Lisp_Object weak;
 
-  /* Vector of hash codes.
+  /* Vector of hash codes, or nil if the table needs rehashing.
      If the I-th entry is unused, then hash[I] should be nil.  */
   Lisp_Object hash;
 
@@ -2327,8 +2327,7 @@ struct Lisp_Hash_Table
      'index' are special and are either ignored by the GC or traced in
      a special way (e.g. because of weakness).  */
 
-  /* Number of key/value entries in the table.  This number is
-     negated if the table needs rehashing.  */
+  /* Number of key/value entries in the table.  */
   ptrdiff_t count;
 
   /* Index of first free entry in free list, or -1 if none.  */
@@ -2413,7 +2412,9 @@ HASH_HASH (const struct Lisp_Hash_Table *h, ptrdiff_t idx)
 INLINE ptrdiff_t
 HASH_TABLE_SIZE (const struct Lisp_Hash_Table *h)
 {
-  return ASIZE (h->next);
+  ptrdiff_t size = ASIZE (h->next);
+  eassume (0 < size);
+  return size;
 }
 
 void hash_table_rehash (struct Lisp_Hash_Table *h);