summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoritz Angermann <moritz.angermann@gmail.com>2021-07-23 21:20:26 +0800
committerZubin Duggal <zubin.duggal@gmail.com>2021-08-04 18:25:25 +0530
commit44c9ebcb65537044540e171f594ea544ea2c20ea (patch)
tree26cefadcbdb2ebcedcc41af648a876e71c6eeebc
parent37ad8856fd97dfdbd334e88300ff661f772b8110 (diff)
downloadhaskell-44c9ebcb65537044540e171f594ea544ea2c20ea.tar.gz
[rts] Untag bq->bh prior to reading the info table
In `checkBlockingQueues` we must always untag the `bh` field of an `StgBlockingQueue`. While at first glance it might seem a sensible assumption that `bh` will always be a blackhole and therefore never be tagged, the GC could shortcut the indirection and put a tagged pointer into the indirection. This blew up on aarch64-darwin with a misaligned access. `bh` pointed to an address that always ended in 0xa. On architectures that are a little less strict about alignment, this would have read a garbage info table pointer, which very, very unlikely would have been equal to `stg_BLACKHOLE_info` and therefore things accidentally worked. However, on AArch64, the read of the info table pointer resulted in a SIGBUS due to misaligned read. Fixes #20093. (cherry picked from commit 1832676aba0a5d75ac934a62eff55e35f95587d5)
-rw-r--r--rts/Threads.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/rts/Threads.c b/rts/Threads.c
index e1a401c9b3..fc9a895ed8 100644
--- a/rts/Threads.c
+++ b/rts/Threads.c
@@ -407,7 +407,18 @@ checkBlockingQueues (Capability *cap, StgTSO *tso)
continue;
}
- p = bq->bh;
+ // We need to always ensure we untag bh. While it might seem a
+ // sensible assumption that bh will never be tagged, the GC could
+ // shortcut the indirection and put a tagged pointer into the
+ // indirection.
+ //
+ // This blew up on aarch64-darwin with misaligned access. bh pointing
+ // to an address that always ended in 0xa. Thus on architectures that
+ // are a little less strict about alignment, this would have read a
+ // garbage pinfo, which very, very unlikely would have been equal to
+ // stg_BLACKHOLE_info. Thus while the code would have done the wrong
+ // thing the result would be the same in almost all cases. See #20093.
+ p = UNTAG_CLOSURE(bq->bh);
const StgInfoTable *pinfo = ACQUIRE_LOAD(&p->header.info);
if (pinfo != &stg_BLACKHOLE_info ||
((StgInd *)p)->indirectee != (StgClosure*)bq)