diff options
author | Austin Seipp <austin@well-typed.com> | 2013-11-01 22:17:01 -0500 |
---|---|---|
committer | Austin Seipp <austin@well-typed.com> | 2013-11-02 15:58:06 -0500 |
commit | a4b1a43542b11d09dd3b603d82c5a0e99da67d74 (patch) | |
tree | d37a283a60e44b5fc8cfe34b21b3d4e3ff728335 /rts | |
parent | 1082f21b1eaf7b380daefb864959e6cfad1aeec7 (diff) | |
download | haskell-a4b1a43542b11d09dd3b603d82c5a0e99da67d74.tar.gz |
Fix loop on 64bit Big-Endian platforms (#8134)
This is a fun one.
In the RTS, `cas` expects a pointer to StgWord which will translate to
unsigned long (8 bytes under LP64.) But we had previously declared
token_locked as *StgBool* - which evaluates to 'int' (4 bytes under
LP64.) That means we fail to provide enough storage for the cas
primitive, causing it to corrupt memory on a 64bit platform.
Hilariously, this somehow did not affect little-endian platforms (ARM,
x86, etc) before. That's because to clear our lock token, we would say:
token_locked = 0;
But because token_locked is 32bits technically, this only writes to
half of the 64bit quantity. On a Big-Endian machine, this won't do
anything. That is, token_locked starts as 0:
/ token_locked
|
v
0x00000000
and the first cas modifies the memory to:
/ valid / corrupted
| |
v v
0x00000000 0x00000001
We then clear token_locked, but this doesn't change the corrupted 4
bytes of memory. And then we try to lock the token again, spinning until
it is released - clearly a deadlock.
Related: Windows (amd64) doesn't follow LP64, but LLP64, where both
int and long are 4 bytes, so this shouldn't change anything on these
platforms.
Thanks to Reid Barton for helping the diagnosis. Also, thanks to Jens
Peterson who confirmed this also fixes building GHC on Fedora/ppc64 and
Fedora/s390x.
Authored-by: Gustavo Luiz Duarte <gustavold@linux.vnet.ibm.com>
Signed-off-by: Austin Seipp <austin@well-typed.com>
Diffstat (limited to 'rts')
-rw-r--r-- | rts/STM.c | 2 |
1 files changed, 1 insertions, 1 deletions
@@ -949,7 +949,7 @@ void stmPreGCHook (Capability *cap) { static volatile StgInt64 max_commits = 0; #if defined(THREADED_RTS) -static volatile StgBool token_locked = FALSE; +static volatile StgWord token_locked = FALSE; static void getTokenBatch(Capability *cap) { while (cas((void *)&token_locked, FALSE, TRUE) == TRUE) { /* nothing */ } |