[prev in list] [next in list] [prev in thread] [next in thread] 

List:       sbcl-commits
Subject:    [Sbcl-commits] master: Fix make-hash-table with weakness + GC race
From:       Douglas Katzman via Sbcl-commits <sbcl-commits () lists ! sourceforge ! net>
Date:       2020-06-23 21:42:23
Message-ID: 1592948544.113079.14237 () sfp-scm-2 ! v30 ! lw ! sourceforge ! com
[Download RAW message or body]

The branch "master" has been updated in SBCL:
       via  ad7f20ccde66fa7b11dc45fd3c3aa546dab90cdd (commit)
      from  7c0b715e75e046b6fe737f0feef1cc81efdee480 (commit)

- Log -----------------------------------------------------------------
commit ad7f20ccde66fa7b11dc45fd3c3aa546dab90cdd
Author: Douglas Katzman <dougk@google.com>
Date:   Tue Jun 23 17:38:37 2020 -0400

    Fix make-hash-table with weakness + GC race
---
 src/code/target-hash-table.lisp | 20 +++++++++++---------
 src/runtime/gc-common.c         |  2 +-
 tests/hash-table.impure.lisp    | 25 +++++++++++++++++++++++++
 3 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/src/code/target-hash-table.lisp b/src/code/target-hash-table.lisp
index fcb6b28f6..7ffdb8abe 100644
--- a/src/code/target-hash-table.lisp
+++ b/src/code/target-hash-table.lisp
@@ -297,7 +297,11 @@ Examples:
 (defun set-kv-hwm (vector hwm) (setf (svref vector 0) hwm))
 (defsetf kv-vector-high-water-mark set-kv-hwm)
 
-(defmacro new-kv-vector (size weakp)
+;;; Make a new key/value vector. Weak tables do not mark the vector as weak
+;;; initially, because the vector can't hold a backpointer to the table
+;;; since the table hasn't been made yet. (GC asserts that every weak hash-table
+;;; storage vector has a table pointer - no exceptions)
+(defmacro %alloc-kv-pairs (size)
   `(let ((v (make-array (+ (* 2 ,size) kv-pairs-overhead-slots)
                         :initial-element +empty-ht-slot+)))
      (setf (kv-vector-high-water-mark v) 0)
@@ -306,11 +310,7 @@ Examples:
      ;; is set, so it needs to see a valid value in the 'supplement' slot.
      ;; Neither 0 nor +empty-ht-slot+ is a valid value.
      (setf (kv-vector-supplement v) nil)
-     (set-header-data v (if ,weakp
-                            (logior sb-vm:vector-weak-subtype
-                                    sb-vm:vector-hashing-subtype)
-                            sb-vm:vector-hashing-subtype))
-
+     (set-header-data v sb-vm:vector-hashing-subtype)
      v))
 
 (defun install-hash-table-lock (table)
@@ -488,7 +488,7 @@ Examples:
                                      :element-type 'hash-table-index
                                      :initial-element 0))
            (weakp (logtest flags hash-table-weak-flag))
-           (kv-vector (new-kv-vector size weakp))
+           (kv-vector (%alloc-kv-pairs size))
            ;; Needs to be the half the length of the KV vector to link
            ;; KV entries - mapped to indices at 2i and 2i+1 -
            ;; together.
@@ -521,6 +521,9 @@ Examples:
             (if weakp
                 table
                 (or hash-vector (= table-kind hash-table-kind-eql))))
+      (when weakp
+        (set-header-data kv-vector (logior sb-vm:vector-hashing-subtype
+                                           sb-vm:vector-weak-subtype)))
       (when (logtest flags hash-table-synchronized-flag)
         (install-hash-table-lock table))
       table))
@@ -631,8 +634,7 @@ multiple threads accessing the same hash-table without locking."
          (new-index-vector (make-array new-n-buckets
                                        :element-type 'hash-table-index
                                        :initial-element 0))
-         ;; New kv vector is not marked as weak, even for a weak table
-         (new-kv-vector (new-kv-vector new-size nil))
+         (new-kv-vector (%alloc-kv-pairs new-size))
          (new-next-vector (make-array (1+ new-size) :element-type 'hash-table-index))
          (new-hash-vector
            (when old-hash-vector
diff --git a/src/runtime/gc-common.c b/src/runtime/gc-common.c
index 60e1e40ab..0d8833755 100644
--- a/src/runtime/gc-common.c
+++ b/src/runtime/gc-common.c
@@ -1358,7 +1358,7 @@ scav_vector (lispobj *where, lispobj header)
     }
 
     lispobj* data = where + 2;
-    // Verify that the rehash epoch is a fixnum
+    // Verify that the rehash stamp is a fixnum
     gc_assert(fixnump(data[1]));
 
     /* Scavenge element (length-1), which may be a hash-table structure. */
diff --git a/tests/hash-table.impure.lisp b/tests/hash-table.impure.lisp
index 6f7b28475..8e005cb72 100644
--- a/tests/hash-table.impure.lisp
+++ b/tests/hash-table.impure.lisp
@@ -3,6 +3,31 @@
 ;;; Keep moving everything that can move during each GC
 #+gencgc (setf (generation-number-of-gcs-before-promotion 0) 1000000)
 
+;;; Check for GC invariant loss during weak table creation.
+;;; This didn't always fail, but might have, and now shouldn't.
+(defglobal *number-of-weak-tables* 0)
+(defun make-weak-key-table () (make-hash-table :weakness :key))
+(defun something-useless (x) (list x))
+(defun weak-table-allocation-test ()
+  (let ((thread
+         (sb-thread:make-thread
+           (lambda ()
+             (loop
+               (sleep .0001)
+               (gc)
+               (sb-thread:barrier (:read))
+               (when (> *number-of-weak-tables* 1000) (return)))))))
+    (loop repeat 1001 do
+      (something-useless (make-weak-key-table))
+      (incf *number-of-weak-tables*)
+      (sb-thread:barrier (:write)))
+    (sb-thread:join-thread thread)))
+;;; Interpreted code is probably too slow to be useful in this test
+(compile 'weak-table-allocation-test)
+(weak-table-allocation-test)
+(with-test (:name :weak-table-gc-invariant :skipped-on (not :sb-thread))
+  (weak-table-allocation-test))
+
 (defun is-address-sensitive (tbl)
   (let ((data (sb-kernel:get-header-data (sb-impl::hash-table-pairs tbl))))
     (logtest data sb-vm:vector-addr-hashing-subtype)))

-----------------------------------------------------------------------


hooks/post-receive
-- 
SBCL


_______________________________________________
Sbcl-commits mailing list
Sbcl-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sbcl-commits
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic