diff options
author | Moritz Angermann <moritz.angermann@gmail.com> | 2021-07-23 21:20:26 +0800 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2021-07-25 09:41:46 -0400 |
commit | 1832676aba0a5d75ac934a62eff55e35f95587d5 (patch) | |
tree | 084fb541fd43decc6387a852cea8b3027f003209 /rts | |
parent | 3801b35a4c479b07275a61df11d0107c242a4e43 (diff) | |
download | haskell-1832676aba0a5d75ac934a62eff55e35f95587d5.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.
Diffstat (limited to 'rts')
-rw-r--r-- | rts/Threads.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/rts/Threads.c b/rts/Threads.c index 2560a4d765..130d451640 100644 --- a/rts/Threads.c +++ b/rts/Threads.c @@ -423,7 +423,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) |