diff options
author | Adam Sandberg Ericsson <adam@sandbergericsson.se> | 2022-06-18 10:01:22 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2022-07-07 23:24:34 -0400 |
commit | 42c917df5be8d75f79a283a8ed59fbaf099bc973 (patch) | |
tree | 9efeae5f39cd9c8ff49ec68ceb3b9f5f5a6ee2cf | |
parent | fa59223b05e24d6e477e3ab0ab296e32b2b65a8b (diff) | |
download | haskell-42c917df5be8d75f79a283a8ed59fbaf099bc973.tar.gz |
rts: allow NULL to be used as an invalid StgStablePtr
-rw-r--r-- | libraries/base/GHC/Stable.hs | 2 | ||||
-rw-r--r-- | rts/PrimOps.cmm | 10 | ||||
-rw-r--r-- | rts/StablePtr.c | 21 | ||||
-rw-r--r-- | rts/TopHandler.c | 4 | ||||
-rw-r--r-- | rts/include/rts/StablePtr.h | 7 | ||||
-rw-r--r-- | rts/include/stg/Types.h | 3 |
6 files changed, 41 insertions, 6 deletions
diff --git a/libraries/base/GHC/Stable.hs b/libraries/base/GHC/Stable.hs index fd4534133c..4c8123e07c 100644 --- a/libraries/base/GHC/Stable.hs +++ b/libraries/base/GHC/Stable.hs @@ -44,6 +44,8 @@ garbage collection (ordinary references may be relocated during garbage collection). Consequently, stable pointers can be passed to foreign code, which can treat it as an opaque reference to a Haskell value. +The @StablePtr@ 0 is reserved for representing NULL in foreign code. + A value of type @StablePtr a@ is a stable pointer to a Haskell expression of type @a@. -} diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm index 84c5850f97..b865092ed1 100644 --- a/rts/PrimOps.cmm +++ b/rts/PrimOps.cmm @@ -2307,7 +2307,7 @@ stg_newIOPortzh () } /* ----------------------------------------------------------------------------- - Stable pointer primitives + Stable name primitives ------------------------------------------------------------------------- */ stg_makeStableNamezh ( P_ obj ) @@ -2347,6 +2347,10 @@ stg_makeStableNamezh ( P_ obj ) return (sn_obj); } +/* ----------------------------------------------------------------------------- + Stable pointer primitives + ------------------------------------------------------------------------- */ + stg_makeStablePtrzh ( P_ obj ) { W_ sp; @@ -2358,7 +2362,9 @@ stg_makeStablePtrzh ( P_ obj ) stg_deRefStablePtrzh ( P_ sp ) { W_ r; - r = spEntry_addr(W_[stable_ptr_table] + sp*SIZEOF_spEntry); + // see Note [NULL StgStablePtr] in StablePtr.c + // here we assume that sp is a valid StablePtr# + r = spEntry_addr(W_[stable_ptr_table] + (sp-1)*SIZEOF_spEntry); return (r); } diff --git a/rts/StablePtr.c b/rts/StablePtr.c index ffd1d0775a..c2e7cda2c3 100644 --- a/rts/StablePtr.c +++ b/rts/StablePtr.c @@ -88,6 +88,16 @@ https://gitlab.haskell.org/ghc/ghc/issues/7670 for details. */ +/* + * Note [NULL StgStablePtr] + * ~~~~~~~~~~~~~~~~~~~~~~~~ + * + * StablePtr index 0 is reserved to represent NULL. Consequently, we must + * subtract 1 to get the index into the array and add 1 to the index to get the + * StablePtr. + */ + + spEntry *stable_ptr_table = NULL; static spEntry *stable_ptr_free = NULL; static unsigned int SPT_size = 0; @@ -255,8 +265,13 @@ freeSpEntry(spEntry *sp) void freeStablePtrUnsafe(StgStablePtr sp) { - ASSERT((StgWord)sp < SPT_size); - freeSpEntry(&stable_ptr_table[(StgWord)sp]); + // see Note [NULL StgStablePtr] + if (sp == NULL) { + return; + } + StgWord spw = (StgWord)sp - 1; + ASSERT(spw < SPT_size); + freeSpEntry(&stable_ptr_table[spw]); } void @@ -282,6 +297,8 @@ getStablePtr(StgPtr p) stable_ptr_free = (spEntry*)(stable_ptr_free->addr); RELAXED_STORE(&stable_ptr_table[sp].addr, p); stablePtrUnlock(); + // see Note [NULL StgStablePtr] + sp = sp + 1; return (StgStablePtr)(sp); } diff --git a/rts/TopHandler.c b/rts/TopHandler.c index d5175015e7..f3ab55c85e 100644 --- a/rts/TopHandler.c +++ b/rts/TopHandler.c @@ -28,6 +28,10 @@ StgTSO *getTopHandlerThread(void) { ACQUIRE_LOCK(&m); StgWeak *weak = (StgWeak*)deRefStablePtr(topHandlerPtr); RELEASE_LOCK(&m); + if (weak == NULL) { + // topHandlerPtr was never initialised + return NULL; + } const StgInfoTable *info = weak->header.info; load_load_barrier(); if (info == &stg_WEAK_info) { diff --git a/rts/include/rts/StablePtr.h b/rts/include/rts/StablePtr.h index 73cd5bed4d..2af8c152a3 100644 --- a/rts/include/rts/StablePtr.h +++ b/rts/include/rts/StablePtr.h @@ -31,9 +31,14 @@ extern DLL_IMPORT_RTS spEntry *stable_ptr_table; ATTR_ALWAYS_INLINE EXTERN_INLINE StgPtr deRefStablePtr(StgStablePtr sp) { + // see Note [NULL StgStablePtr] + if (sp == 0) { + return NULL; + } + StgWord spw = (StgWord)sp - 1; // 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); + return ACQUIRE_LOAD(&spt[spw].addr); } diff --git a/rts/include/stg/Types.h b/rts/include/stg/Types.h index 1a9b1685fa..f8743c3351 100644 --- a/rts/include/stg/Types.h +++ b/rts/include/stg/Types.h @@ -162,7 +162,8 @@ typedef StgWord* StgPtr; /* heap or stack pointer */ typedef StgWord volatile* StgVolatilePtr; /* pointer to volatile word */ typedef StgWord StgOffset; /* byte offset within closure */ typedef StgWord8 StgCode; /* close enough */ -typedef void* StgStablePtr; +typedef void* StgStablePtr; /* adjusted index into stable_ptr_table, + see Note [NULL StgStablePtr] in StablePtr.c */ typedef StgWord8* StgByteArray; /* |