Simon Jakobi pushed to branch wip/sjakobi/T26964 at Glasgow Haskell Compiler / GHC

Commits:

10 changed files:

Changes:

  • compiler/GHC/StgToCmm/Prim.hs
    ... ... @@ -3625,10 +3625,12 @@ emitCheckedMemcpyCall dst src n align = do
    3625 3625
         doCheck platform = do
    
    3626 3626
             name <- fromMaybe "<unknown primop>" <$> getCurrentPrimOpName
    
    3627 3627
             nameLbl <- newStringCLit name
    
    3628
    +        modLbl <- getCurrentModuleCLit
    
    3628 3629
             overlapCheckFailed <- getCode $
    
    3629 3630
               emitCCallNeverReturns []
    
    3630 3631
                 (mkLblExpr mkMemcpyRangeOverlapLabel)
    
    3631
    -            [ (CmmLit nameLbl, AddrHint) ]
    
    3632
    +            [ (CmmLit nameLbl, AddrHint)
    
    3633
    +            , (CmmLit modLbl,  AddrHint) ]
    
    3632 3634
             emit =<< mkCmmIfThen' rangesOverlap overlapCheckFailed (Just False)
    
    3633 3635
           where
    
    3634 3636
             rangesOverlap = (checkDiff dst src `or` checkDiff src dst) `ne` zero
    
    ... ... @@ -3740,11 +3742,20 @@ whenCheckBounds a = do
    3740 3742
         False -> pure ()
    
    3741 3743
         True  -> a
    
    3742 3744
     
    
    3745
    +-- | Render the module currently being code-generated as a string literal, for
    
    3746
    +-- use in @-fcheck-prim-bounds@ failure diagnostics.
    
    3747
    +getCurrentModuleCLit :: FCode CmmLit
    
    3748
    +getCurrentModuleCLit = do
    
    3749
    +    mod <- getModuleName
    
    3750
    +    ctx <- getContext
    
    3751
    +    newStringCLit (renderWithContext ctx (ppr mod))
    
    3752
    +
    
    3743 3753
     -- | Emit a call to the RTS @rtsOutOfBoundsAccess@ bounds-check failure
    
    3744 3754
     -- handler, passing the offending index, the number of accessed elements and
    
    3745 3755
     -- the array size, so that the runtime can produce an informative error
    
    3746 3756
     -- message. The name of the offending primop is read from the code generator
    
    3747
    --- environment (see 'withCurrentPrimOpName').
    
    3757
    +-- environment (see 'withCurrentPrimOpName'), and the module being compiled is
    
    3758
    +-- read from the 'StgToCmmConfig'.
    
    3748 3759
     emitBoundsCheckFailed :: CmmExpr  -- ^ accessed index
    
    3749 3760
                           -> CmmExpr  -- ^ number of accessed elements
    
    3750 3761
                           -> CmmExpr  -- ^ array size (in elements)
    
    ... ... @@ -3752,12 +3763,14 @@ emitBoundsCheckFailed :: CmmExpr -- ^ accessed index
    3752 3763
     emitBoundsCheckFailed idx count sz = do
    
    3753 3764
         name <- fromMaybe "<unknown primop>" <$> getCurrentPrimOpName
    
    3754 3765
         nameLbl <- newStringCLit name
    
    3766
    +    modLbl <- getCurrentModuleCLit
    
    3755 3767
         emitCCallNeverReturns []
    
    3756 3768
           (mkLblExpr mkOutOfBoundsAccessLabel)
    
    3757 3769
           [ (idx,            NoHint)
    
    3758 3770
           , (count,          NoHint)
    
    3759 3771
           , (sz,             NoHint)
    
    3760
    -      , (CmmLit nameLbl, AddrHint) ]
    
    3772
    +      , (CmmLit nameLbl, AddrHint)
    
    3773
    +      , (CmmLit modLbl,  AddrHint) ]
    
    3761 3774
     
    
    3762 3775
     emitBoundsCheck :: CmmExpr  -- ^ accessed index
    
    3763 3776
                     -> CmmExpr  -- ^ array size (in elements)
    

  • rts/PrimOps.cmm
    ... ... @@ -93,7 +93,7 @@ import CLOSURE ghc_hs_iface;
    93 93
     // the index reported here may be in bytes. count is 1 since these checks cover
    
    94 94
     // a single access.
    
    95 95
     #define ASSERT_IN_BOUNDS(op, ind, sz) \
    
    96
    -    if (ind >= sz) { ccall rtsOutOfBoundsAccess(ind, 1, sz, op); }
    
    96
    +    if (ind >= sz) { ccall rtsOutOfBoundsAccess(ind, 1, sz, op, "<RTS>"); }
    
    97 97
     #else
    
    98 98
     #define ASSERT_IN_BOUNDS(op, ind, sz)
    
    99 99
     #endif
    

  • rts/RtsMessages.c
    ... ... @@ -352,32 +352,31 @@ rtsBadAlignmentBarf(void)
    352 352
     }
    
    353 353
     
    
    354 354
     void
    
    355
    -rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op)
    
    355
    +rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op, const char *module)
    
    356 356
     {
    
    357 357
         if (count <= 1) {
    
    358
    -        errorBelch("%s: array access out of bounds:\n"
    
    358
    +        errorBelch("%s: array access out of bounds in module %s:\n"
    
    359 359
                        "    index %" FMT_Int " is not within [0, %" FMT_Word ").\n"
    
    360 360
                        "This is usually caused by incorrect use of unsafe primops "
    
    361 361
                        "in user or library code.",
    
    362
    -                   op, index, size);
    
    362
    +                   op, module, index, size);
    
    363 363
         } else {
    
    364
    -        errorBelch("%s: array access out of bounds:\n"
    
    364
    +        errorBelch("%s: array access out of bounds in module %s:\n"
    
    365 365
                        "    range of %" FMT_Word " elements starting at index %" FMT_Int
    
    366 366
                        " is not within [0, %" FMT_Word ").\n"
    
    367 367
                        "This is usually caused by incorrect use of unsafe primops "
    
    368 368
                        "in user or library code.",
    
    369
    -                   op, count, index, size);
    
    369
    +                   op, module, count, index, size);
    
    370 370
         }
    
    371 371
         stg_exit(EXIT_FAILURE);
    
    372 372
     }
    
    373 373
     
    
    374 374
     void
    
    375
    -rtsMemcpyRangeOverlap(const char *op)
    
    375
    +rtsMemcpyRangeOverlap(const char *op, const char *module)
    
    376 376
     {
    
    377
    -    errorBelch("%s: overlapping source and destination ranges in a "
    
    378
    -               "memcpy-using operation.\n"
    
    377
    +    errorBelch("%s: overlapping source and destination ranges in module %s.\n"
    
    379 378
                    "This is usually caused by incorrect use of unsafe primops "
    
    380 379
                    "in user or library code.",
    
    381
    -               op);
    
    380
    +               op, module);
    
    382 381
         stg_exit(EXIT_FAILURE);
    
    383 382
     }

  • rts/include/rts/Messages.h
    ... ... @@ -108,5 +108,5 @@ extern RtsMsgFunction rtsSysErrorMsgFn;
    108 108
     
    
    109 109
     /* Used by code generator */
    
    110 110
     void rtsBadAlignmentBarf(void) STG_NORETURN;
    
    111
    -void rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op) STG_NORETURN;
    
    112
    -void rtsMemcpyRangeOverlap(const char *op) STG_NORETURN;
    111
    +void rtsOutOfBoundsAccess(StgInt index, StgWord count, StgWord size, const char *op, const char *module) STG_NORETURN;
    
    112
    +void rtsMemcpyRangeOverlap(const char *op, const char *module) STG_NORETURN;

  • testsuite/tests/codeGen/should_fail/T26964.stderr
    1
    -readSmallArray#: array access out of bounds:
    
    1
    +readSmallArray#: array access out of bounds in module Main:
    
    2 2
         index -1 is not within [0, 5).
    
    3 3
     This is usually caused by incorrect use of unsafe primops in user or library code.

  • testsuite/tests/codeGen/should_fail/T26964Module.hs
    1
    +module Main where
    
    2
    +
    
    3
    +import T26964ModuleA (bad)
    
    4
    +
    
    5
    +main :: IO ()
    
    6
    +main = bad

  • testsuite/tests/codeGen/should_fail/T26964Module.stderr
    1
    +readSmallArray#: array access out of bounds in module T26964ModuleA:
    
    2
    +    index -1 is not within [0, 5).
    
    3
    +This is usually caused by incorrect use of unsafe primops in user or library code.

  • testsuite/tests/codeGen/should_fail/T26964ModuleA.hs
    1
    +{-# LANGUAGE UnboxedTuples #-}
    
    2
    +{-# LANGUAGE MagicHash #-}
    
    3
    +
    
    4
    +-- The failing -fcheck-prim-bounds primop is emitted while code-generating this
    
    5
    +-- helper module, so the runtime diagnostic should report T26964ModuleA, not the
    
    6
    +-- Main module that merely calls 'bad'.
    
    7
    +
    
    8
    +module T26964ModuleA (bad) where
    
    9
    +
    
    10
    +import GHC.Exts
    
    11
    +import GHC.IO
    
    12
    +
    
    13
    +{-# NOINLINE bad #-}
    
    14
    +bad :: IO ()
    
    15
    +bad = IO $ \s0 ->
    
    16
    +  case newSmallArray# 5# () s0 of
    
    17
    +    (# s1, marr #) -> readSmallArray# marr (-1#) s1

  • testsuite/tests/codeGen/should_fail/T26964b.stderr
    1
    -copyMutableByteArray#: array access out of bounds:
    
    1
    +copyMutableByteArray#: array access out of bounds in module Main:
    
    2 2
         range of 4 elements starting at index 6 is not within [0, 8).
    
    3 3
     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',
    42 42
     test('T26964b',
    
    43 43
          [omit_ghci, js_skip, exit_code(1), normalise_errmsg_fun(strip_prog_prefix)],
    
    44 44
          compile_and_run, ['-fcheck-prim-bounds'])
    
    45
    +# T26964Module checks that the reported module is the one containing the failing
    
    46
    +# primop (the helper T26964ModuleA), not the Main module that calls it.
    
    47
    +test('T26964Module',
    
    48
    +     [omit_ghci, js_skip, exit_code(1), normalise_errmsg_fun(strip_prog_prefix),
    
    49
    +      extra_files(['T26964ModuleA.hs'])],
    
    50
    +     multimod_compile_and_run, ['T26964Module', '-fcheck-prim-bounds'])