summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Sandberg Ericsson <adam@sandbergericsson.se>2022-06-18 10:01:22 +0100
committerAdam Sandberg Ericsson <adam@sandbergericsson.se>2022-06-27 12:31:29 +0100
commit545fa3477ff5aeca493e300872292e7688c43135 (patch)
tree03a81552dde5d2cb69ab14691ed4e5de42dd212e
parent9c575f24d41fed616e6f96fcbb4fa9a9687497a6 (diff)
downloadhaskell-wip/adamse/null-stable-ptr.tar.gz
rts: allow NULL to be used as an invalid StgStablePtrwip/adamse/null-stable-ptr
-rw-r--r--libraries/base/GHC/Stable.hs2
-rw-r--r--rts/PrimOps.cmm10
-rw-r--r--rts/StablePtr.c21
-rw-r--r--rts/TopHandler.c4
-rw-r--r--rts/include/rts/StablePtr.h7
-rw-r--r--rts/include/stg/Types.h3
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;
/*