Fix unlikely but possible race in `WeakValueDictionary` jv
authorJan Vrany <jan.vrany@labware.com>
Thu, 25 Mar 2021 20:30:03 +0000
branchjv
changeset 25411 248600ba8fd9
parent 25410 c91ea94445d1
child 25412 f34d8a7f4b7c
Fix unlikely but possible race in `WeakValueDictionary` It may happen that value in `valueArray` could have been already collected by the GC but #clearDeadSlots have not yet been called. When this happened, `#at:ifAbsentPut:` returned tombstone rather than updating the dictionary with value from block. This commit fixes this by checking whether `valueArray` contain the tombstone and if so, clearing up the dead slots and restarting the operation. HTH.
WeakValueDictionary.st
--- a/WeakValueDictionary.st	Wed Feb 03 11:52:30 2021 +0000
+++ b/WeakValueDictionary.st	Thu Mar 25 20:30:03 2021 +0000
@@ -1,5 +1,6 @@
 "
  COPYRIGHT (c) 1992 by Claus Gittinger
+ COPYRIGHT (c) 2021 LabWare
 	      All Rights Reserved
 
  This software is furnished under a license and may be used
@@ -25,6 +26,7 @@
 copyright
 "
  COPYRIGHT (c) 1992 by Claus Gittinger
+ COPYRIGHT (c) 2021 LabWare
 	      All Rights Reserved
 
  This software is furnished under a license and may be used
@@ -300,6 +302,38 @@
     "Modified: / 13.12.2001 / 14:18:56 / martin"
 !
 
+findKeyOrNilOrDeletedEntry:key
+    | index value |
+
+    (OperatingSystem blockInterrupts) ifFalse:[
+        "/
+        "/ may never be entered with interrupts enabled
+        "/
+        OperatingSystem unblockInterrupts.
+        self error:'unblocked call of findKeyOrNil'.
+    ].
+
+    "/ It may happen that value could have been already
+    "/ collected by the GC but #clearDeadSlots have not yet
+    "/ been called. In that case, valueArray would contain
+    "/ a tombstone (a SmallInteger).
+    "/ 
+    "/ So, we check whether the value contains tombstone
+    "/ and if so, clear all dead slots and restart.
+    [
+        index := super findKeyOrNilOrDeletedEntry:key.
+        value := valueArray at: index.
+        value class == SmallInteger
+    ] whileTrue: [ 
+        self clearDeadSlots
+    ].
+    OperatingSystem unblockInterrupts.
+
+    ^ index
+
+    "Created: / 25-03-2021 / 20:03:12 / Jan Vrany <jan.vrany@labware.com>"
+!
+
 possiblyShrink
     "check if the receiver has become too empty (after a remove)
      and shrink if it makes sense.
@@ -384,5 +418,10 @@
 
 version
     ^ '$Header$'
+!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
 ! !