custom-hash: fix ephemeron race

The pattern

  (ephemeron-value
   (hash-ref! intern key
     (lambda ()
       (make-ephemeron key (wrap key)))))

is wrong, because a GC might happen between the time that the
epehemeron is found in the table (or the time that the key was just
added to the table) and the time that `ephemeron-value` is called to
extract the value. If the key is not otherwise accessible, the value
may no longer be in the ephemeron.
This commit is contained in:
Matthew Flatt 2018-09-13 11:06:03 -06:00
parent 9772c05040
commit d5aa191fb2

View File

@ -168,10 +168,18 @@
(define (wrap-key spec key)
(define wrap (custom-spec-wrap spec))
(define intern (custom-spec-intern spec))
(ephemeron-value
(hash-ref! intern key
(lambda ()
(make-ephemeron key (wrap key))))))
;; Rely on the fact that a wrapped key is never represented as `#f`
(define e (hash-ref intern key #f))
(cond
[(not e)
(define wrapped-key (wrap key))
(hash-set! intern key (make-ephemeron key wrapped-key))
wrapped-key]
[else
(define wrapped-key (ephemeron-value e))
(or wrapped-key
;; Ephemeron was just cleared; try again
(wrap-key spec key))]))
(define (hash-check-key who d key)
(define spec (custom-hash-spec d))