diff options
author | Ben Gamari <ben@smart-cactus.org> | 2019-09-28 17:35:41 +0000 |
---|---|---|
committer | Ben Gamari <ben@well-typed.com> | 2020-12-01 12:48:54 -0500 |
commit | 78a5bdff108a369588a50ab69d4f927344164f40 (patch) | |
tree | 9eacf23a0d163f4c3a257665f51b4327fdf6e83b | |
parent | 2ecc569370d521eccd5fb1cfcfc69707e853a962 (diff) | |
download | haskell-78a5bdff108a369588a50ab69d4f927344164f40.tar.gz |
rts: Avoid data races in StablePtr implementation
This fixes two potentially problematic data races in the StablePtr
implementation:
* We would fail to RELEASE the stable pointer table when enlarging it,
causing other cores to potentially see uninitialized memory.
* We would fail to ACQUIRE when dereferencing a stable pointer.
-rw-r--r-- | includes/rts/StablePtr.h | 6 | ||||
-rw-r--r-- | rts/StablePtr.c | 9 |
2 files changed, 10 insertions, 5 deletions
diff --git a/includes/rts/StablePtr.h b/includes/rts/StablePtr.h index f42c353d2b..56113b9f81 100644 --- a/includes/rts/StablePtr.h +++ b/includes/rts/StablePtr.h @@ -31,5 +31,9 @@ extern DLL_IMPORT_RTS spEntry *stable_ptr_table; EXTERN_INLINE StgPtr deRefStablePtr(StgStablePtr sp) { - return stable_ptr_table[(StgWord)sp].addr; + // acquire load to ensure that we see the new SPT if it has been recently + // enlarged. + const spEntry *spt = ACQUIRE_LOAD(&stable_ptr_table); + // acquire load to ensure that the referenced object is visible. + return ACQUIRE_LOAD(&spt[(StgWord)sp].addr); } diff --git a/rts/StablePtr.c b/rts/StablePtr.c index 2181b83d90..1b2be2d50e 100644 --- a/rts/StablePtr.c +++ b/rts/StablePtr.c @@ -191,9 +191,10 @@ enlargeStablePtrTable(void) /* When using the threaded RTS, the update of stable_ptr_table is assumed to * be atomic, so that another thread simultaneously dereferencing a stable - * pointer will always read a valid address. + * pointer will always read a valid address. Release ordering to ensure + * that the new table is visible to others. */ - stable_ptr_table = new_stable_ptr_table; + RELEASE_STORE(&stable_ptr_table, new_stable_ptr_table); initSpEntryFreeList(stable_ptr_table + old_SPT_size, old_SPT_size, NULL); } @@ -247,7 +248,7 @@ exitStablePtrTable(void) STATIC_INLINE void freeSpEntry(spEntry *sp) { - sp->addr = (P_)stable_ptr_free; + RELAXED_STORE(&sp->addr, (P_)stable_ptr_free); stable_ptr_free = sp; } @@ -279,7 +280,7 @@ getStablePtr(StgPtr p) if (!stable_ptr_free) enlargeStablePtrTable(); sp = stable_ptr_free - stable_ptr_table; stable_ptr_free = (spEntry*)(stable_ptr_free->addr); - stable_ptr_table[sp].addr = p; + RELAXED_STORE(&stable_ptr_table[sp].addr, p); stablePtrUnlock(); return (StgStablePtr)(sp); } |