Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
3f00f234 by Cheng Shao at 2026-06-30T21:40:32-04:00
compiler: fix missing handling of CmmUnsafeForeignCall node in LayoutStack
This patch fixes missing handling of `CmmUnsafeForeignCall` middle
node in the `LayoutStack` pass.
Before proc-points splitting, this pass computes liveliness of local
registers, and spills those alive across a Cmm native call onto the
stack. It need to traverse all middle nodes in each block and check
whether a local register is an assignee, if so then the previous
mapping in `sm_regs` is invalidated and needs to be dropped. However,
it didn't handle `CmmUnsafeForeignCall` node which may also assign to
a local register. When proc-points splitting is enabled, this can
produce an invalid basic block that doesn't properly backup the
updated local register to the stack before doing a Cmm call, resulting
in completely invalid runtime behavior.
The patch also adds a `T27447` regression test. With no-TNTC or with
LLVM backend, without the fix the test case would output a stale
0x1111111111111111 value, instead of the expected 0x2222222222222222
output.
Fixes #27447.
Co-authored-by: Codex
- - - - -
6 changed files:
- + changelog.d/fix-layout-stack-fcall
- compiler/GHC/Cmm/LayoutStack.hs
- + testsuite/tests/cmm/should_run/T27447.hs
- + testsuite/tests/cmm/should_run/T27447.stdout
- + testsuite/tests/cmm/should_run/T27447_cmm.cmm
- testsuite/tests/cmm/should_run/all.T
Changes:
=====================================
changelog.d/fix-layout-stack-fcall
=====================================
@@ -0,0 +1,4 @@
+section: compiler
+synopsis: Fix invalid cmm basic block output when proc-point splitting is enabled (wasm/llvm/unregisterised)
+issues: #27447
+mrs: !16271
=====================================
compiler/GHC/Cmm/LayoutStack.hs
=====================================
@@ -408,6 +408,8 @@ procMiddle stackmaps node sm
where loc = getStackLoc area off stackmaps
CmmAssign (CmmLocal r) _other
-> sm { sm_regs = delFromUFM (sm_regs sm) r }
+ CmmUnsafeForeignCall _ results _
+ -> sm { sm_regs = delListFromUFM (sm_regs sm) results }
_other
-> sm
=====================================
testsuite/tests/cmm/should_run/T27447.hs
=====================================
@@ -0,0 +1,40 @@
+{-# LANGUAGE GHCForeignImportPrim #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UnliftedFFITypes #-}
+
+import Foreign
+import GHC.Exts
+import GHC.IO
+import GHC.Word
+import Text.Printf
+
+foreign import prim "t27447_repro"
+ t27447_repro# :: Addr# -> State# RealWorld -> (# State# RealWorld, Word64# #)
+
+expected :: Word64
+expected = 0x2222222222222222
+
+stale :: Word64
+stale = 0x1111111111111111
+
+runCmm :: Ptr a -> IO Word64
+runCmm (Ptr p#) = IO $ \s ->
+ case t27447_repro# p# s of
+ (# s', w# #) -> (# s', W64# w# #)
+
+main :: IO ()
+main = allocaBytesAligned 48 8 $ \raw -> do
+ let node0 = raw
+ node1 = raw `plusPtr` 24
+
+ pokeByteOff node0 0 (1 :: Word64)
+ pokeByteOff node0 8 node1
+ pokeByteOff node0 16 stale
+
+ pokeByteOff node1 0 (0 :: Word64)
+ pokeByteOff node1 8 node1
+ pokeByteOff node1 16 expected
+
+ got <- runCmm node0
+ printf "0x%016x\n" got
=====================================
testsuite/tests/cmm/should_run/T27447.stdout
=====================================
@@ -0,0 +1 @@
+0x2222222222222222
=====================================
testsuite/tests/cmm/should_run/T27447_cmm.cmm
=====================================
@@ -0,0 +1,24 @@
+#include "Cmm.h"
+
+t27447_repro (W_ x) {
+ I64 ty;
+ W_ old;
+
+again:
+ ty = I64[x];
+ switch [0 .. 2] (ty) {
+ case 0: {
+ return (I64[x + 16]);
+ }
+ case 1: {
+ old = x;
+ x = %acquire W_[x + 8];
+ I64[old] = 0;
+ goto again;
+ }
+ case 2: {
+ STK_CHK_GEN();
+ goto again;
+ }
+ }
+}
=====================================
testsuite/tests/cmm/should_run/all.T
=====================================
@@ -33,7 +33,7 @@ test('T22871',
test('JumpTableNoStackDealloc',
[ extra_run_opts('"' + config.libdir + '"')
- , req_cmm
+ , req_cmm
, when(arch('wasm32'), skip) # wasm32 doesn't support the printf() calls
, when(arch('i386'), skip) # i386 doesn't support `MO_U_Rem W64` (`_c1::I64 % 10 :: W64`)
],
@@ -52,3 +52,11 @@ test('T25601',
[req_cmm],
multi_compile_and_run,
['T25601', [('T25601a.cmm', '')], ''])
+
+test('T27447',
+ [ req_cmm
+ , extra_ways(['optasm'])
+ , when(have_llvm(), extra_ways(['optasm', 'optllvm']))
+ ],
+ multi_compile_and_run,
+ ['T27447', [('T27447_cmm.cmm', '')], ''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/3f00f234d0d5b3b3b2a23a5dc70ce372...
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/3f00f234d0d5b3b3b2a23a5dc70ce372...
You're receiving this email because of your account on gitlab.haskell.org.