From d5aa191fb26db097406faea017b9de18c59cea1e Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Thu, 13 Sep 2018 11:06:03 -0600 Subject: [PATCH] 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. --- racket/collects/racket/private/custom-hash.rkt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/racket/collects/racket/private/custom-hash.rkt b/racket/collects/racket/private/custom-hash.rkt index 71db64bc46..4d0b64c122 100644 --- a/racket/collects/racket/private/custom-hash.rkt +++ b/racket/collects/racket/private/custom-hash.rkt @@ -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))