[Git][ghc/ghc][wip/sjakobi/T26964] Report the module in -fcheck-prim-bounds failures
Simon Jakobi pushed to branch wip/sjakobi/T26964 at Glasgow Haskell Compiler / GHC Commits: e35ce402 by Simon Jakobi at 2026-06-05T02:48:49+02:00 Report the module in -fcheck-prim-bounds failures A failing bounds-checked primop now reports the Haskell module being compiled alongside the primop name and access details, e.g. readSmallArray#: array access out of bounds in module Main: index -1 is not within [0, 5). The module string is rendered in StgToCmm from stgToCmmThisModule and passed as an extra argument to the rtsOutOfBoundsAccess and rtsMemcpyRangeOverlap RTS helpers. The DEBUG ASSERT_IN_BOUNDS path in PrimOps.cmm has no user module and passes "<RTS>". Adds a cross-module regression test (T26964Module) asserting the module reported is the one containing the failing primop, not its caller. - - - - - 10 changed files: - compiler/GHC/StgToCmm/Prim.hs - rts/PrimOps.cmm - rts/RtsMessages.c - rts/include/rts/Messages.h - testsuite/tests/codeGen/should_fail/T26964.stderr - + testsuite/tests/codeGen/should_fail/T26964Module.hs - + testsuite/tests/codeGen/should_fail/T26964Module.stderr - + testsuite/tests/codeGen/should_fail/T26964ModuleA.hs - testsuite/tests/codeGen/should_fail/T26964b.stderr - testsuite/tests/codeGen/should_fail/all.T Changes: ===================================== compiler/GHC/StgToCmm/Prim.hs ===================================== @@ -3625,10 +3625,12 @@ emitCheckedMemcpyCall dst src n align = do doCheck platform = do name <- fromMaybe "<unknown primop>" <$> getCurrentPrimOpName nameLbl <- newStringCLit name + modLbl <- getCurrentModuleCLit overlapCheckFailed <- getCode $ emitCCallNeverReturns [] (mkLblExpr mkMemcpyRangeOverlapLabel) - [ (CmmLit nameLbl, AddrHint) ] + [ (CmmLit nameLbl, AddrHint) + , (CmmLit modLbl, AddrHint) ] emit =<< mkCmmIfThen' rangesOverlap overlapCheckFailed (Just False) where rangesOverlap = (checkDiff dst src `or` checkDiff src dst) `ne` zero @@ -3740,11 +3742,20 @@ whenCheckBounds a = do False -> pure () True -> a +-- | Render the module currently being code-generated as a string literal, for +-- use in @-fcheck-prim-bounds@ failure diagnostics. +getCurrentModuleCLit :: FCode CmmLit +getCurrentModuleCLit = do + mod <- getModuleName + ctx <- getContext + newStringCLit (renderWithContext ctx (ppr mod)) + -- | Emit a call to the RTS @rtsOutOfBoundsAccess@ bounds-check failure -- handler, passing the offending index, the number of accessed elements and -- the array size, so that the runtime can produce an informative error -- message. The name of the offending primop is read from the code generator --- environment (see 'withCurrentPrimOpName'). +-- environment (see 'withCurrentPrimOpName'), and the module being compiled is +-- read from the 'StgToCmmConfig'. emitBoundsCheckFailed :: CmmExpr -- ^ accessed index -> CmmExpr -- ^ number of accessed elements -> CmmExpr -- ^ array size (in elements) @@ -3752,12 +3763,14 @@ emitBoundsCheckFailed :: CmmExpr -- ^ accessed index emitBoundsCheckFailed idx count sz = do name <- fromMaybe "<unknown primop>" <$> getCurrentPrimOpName nameLbl <- newStringCLit name + modLbl <- getCurrentModuleCLit emitCCallNeverReturns [] (mkLblExpr mkOutOfBoundsAccessLabel) [ (idx, NoHint) , (count, NoHint) , (sz, NoHint) - , (CmmLit nameLbl, AddrHint) ] + , (CmmLit nameLbl, AddrHint) + , (CmmLit modLbl, AddrHint) ] emitBoundsCheck :: CmmExpr -- ^ accessed index -> CmmExpr -- ^ array size (in elements) ===================================== rts/PrimOps.cmm ===================================== @@ -93,7 +93,7 @@ import CLOSURE ghc_hs_iface; // the index reported here may be in bytes. count is 1 since these checks cover // a single access. #define ASSERT_IN_BOUNDS(op, ind, sz) \ - if (ind >= sz) { ccall rtsOutOfBoundsAccess(ind, 1, sz, op); } + if (ind >= sz) { ccall rtsOutOfBoundsAccess(ind, 1, sz, op, "<RTS>"); } #else #define ASSERT_IN_BOUNDS(op, ind, sz) #endif ===================================== rts/RtsMessages.c ===================================== @@ -352,32 +352,31 @@ rtsBadAlignmentBarf(void) } void -rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op) +rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op, const char *module) { if (count <= 1) { - errorBelch("%s: array access out of bounds:\n" + errorBelch("%s: array access out of bounds in module %s:\n" " index %" FMT_Int " is not within [0, %" FMT_Word ").\n" "This is usually caused by incorrect use of unsafe primops " "in user or library code.", - op, index, size); + op, module, index, size); } else { - errorBelch("%s: array access out of bounds:\n" + errorBelch("%s: array access out of bounds in module %s:\n" " range of %" FMT_Word " elements starting at index %" FMT_Int " is not within [0, %" FMT_Word ").\n" "This is usually caused by incorrect use of unsafe primops " "in user or library code.", - op, count, index, size); + op, module, count, index, size); } stg_exit(EXIT_FAILURE); } void -rtsMemcpyRangeOverlap(const char *op) +rtsMemcpyRangeOverlap(const char *op, const char *module) { - errorBelch("%s: overlapping source and destination ranges in a " - "memcpy-using operation.\n" + errorBelch("%s: overlapping source and destination ranges in module %s.\n" "This is usually caused by incorrect use of unsafe primops " "in user or library code.", - op); + op, module); stg_exit(EXIT_FAILURE); } ===================================== rts/include/rts/Messages.h ===================================== @@ -108,5 +108,5 @@ extern RtsMsgFunction rtsSysErrorMsgFn; /* Used by code generator */ void rtsBadAlignmentBarf(void) STG_NORETURN; -void rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op) STG_NORETURN; -void rtsMemcpyRangeOverlap(const char *op) STG_NORETURN; +void rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op, const char *module) STG_NORETURN; +void rtsMemcpyRangeOverlap(const char *op, const char *module) STG_NORETURN; ===================================== testsuite/tests/codeGen/should_fail/T26964.stderr ===================================== @@ -1,3 +1,3 @@ -readSmallArray#: array access out of bounds: +readSmallArray#: array access out of bounds in module Main: index -1 is not within [0, 5). This is usually caused by incorrect use of unsafe primops in user or library code. ===================================== testsuite/tests/codeGen/should_fail/T26964Module.hs ===================================== @@ -0,0 +1,6 @@ +module Main where + +import T26964ModuleA (bad) + +main :: IO () +main = bad ===================================== testsuite/tests/codeGen/should_fail/T26964Module.stderr ===================================== @@ -0,0 +1,3 @@ +readSmallArray#: array access out of bounds in module T26964ModuleA: + index -1 is not within [0, 5). +This is usually caused by incorrect use of unsafe primops in user or library code. ===================================== testsuite/tests/codeGen/should_fail/T26964ModuleA.hs ===================================== @@ -0,0 +1,17 @@ +{-# LANGUAGE UnboxedTuples #-} +{-# LANGUAGE MagicHash #-} + +-- The failing -fcheck-prim-bounds primop is emitted while code-generating this +-- helper module, so the runtime diagnostic should report T26964ModuleA, not the +-- Main module that merely calls 'bad'. + +module T26964ModuleA (bad) where + +import GHC.Exts +import GHC.IO + +{-# NOINLINE bad #-} +bad :: IO () +bad = IO $ \s0 -> + case newSmallArray# 5# () s0 of + (# s1, marr #) -> readSmallArray# marr (-1#) s1 ===================================== testsuite/tests/codeGen/should_fail/T26964b.stderr ===================================== @@ -1,3 +1,3 @@ -copyMutableByteArray#: array access out of bounds: +copyMutableByteArray#: array access out of bounds in module Main: range of 4 elements starting at index 6 is not within [0, 8). This is usually caused by incorrect use of unsafe primops in user or library code. ===================================== testsuite/tests/codeGen/should_fail/all.T ===================================== @@ -42,3 +42,9 @@ test('T26964', test('T26964b', [omit_ghci, js_skip, exit_code(1), normalise_errmsg_fun(strip_prog_prefix)], compile_and_run, ['-fcheck-prim-bounds']) +# T26964Module checks that the reported module is the one containing the failing +# primop (the helper T26964ModuleA), not the Main module that calls it. +test('T26964Module', + [omit_ghci, js_skip, exit_code(1), normalise_errmsg_fun(strip_prog_prefix), + extra_files(['T26964ModuleA.hs'])], + multimod_compile_and_run, ['T26964Module', '-fcheck-prim-bounds']) View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e35ce4028800b8b7117fa3cbf223ba8a... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e35ce4028800b8b7117fa3cbf223ba8a... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Simon Jakobi (@sjakobi2)