Test for undef bugs in the LLVM backend when validating
authorReid Barton <rwbarton@gmail.com>
Wed, 27 Jan 2016 10:05:59 +0000 (11:05 +0100)
committerBen Gamari <ben@smart-cactus.org>
Wed, 27 Jan 2016 10:32:15 +0000 (11:32 +0100)
In an attempt to catch bugs involving using undef values, replace
undef literals by values likely to cause crashes or test failures.
We do this only when validating since it is a deoptimization.

This depends on D1857 to catch such bugs in the RTS (such as #11487).

Test Plan:
Did a build with
```
BuildFlavour = quick-llvm
SRC_HC_OPTS_STAGE1 = -fllvm-fill-undef-with-garbage
```
The build crashed when running ghc-stage2, as expected.

Reviewers: austin, bgamari

Reviewed By: bgamari

Subscribers: thomie

Differential Revision: https://phabricator.haskell.org/D1858

compiler/llvmGen/Llvm/Types.hs
compiler/main/DynFlags.hs
mk/flavours/validate.mk

index d533b4a..5c2ce5e 100644 (file)
@@ -217,7 +217,31 @@ ppLit f@(LMFloatLit _ _)       = sdocWithDynFlags (\dflags ->
                                    error $ "Can't print this float literal!" ++ showSDoc dflags (ppr f))
 ppLit (LMVectorLit ls  )       = char '<' <+> ppCommaJoin ls <+> char '>'
 ppLit (LMNullLit _     )       = text "null"
-ppLit (LMUndefLit _    )       = text "undef"
+-- Trac 11487 was an issue where we passed undef for some arguments
+-- that were actually live. By chance the registers holding those
+-- arguments usually happened to have the right values anyways, but
+-- that was not guaranteed. To find such bugs reliably, we set the
+-- flag below when validating, which replaces undef literals (at
+-- common types) with values that are likely to cause a crash or test
+-- failure.
+ppLit (LMUndefLit t    )       = sdocWithDynFlags f
+  where f dflags
+          | gopt Opt_LlvmFillUndefWithGarbage dflags,
+            Just lit <- garbageLit t   = ppLit lit
+          | otherwise                  = text "undef"
+
+garbageLit :: LlvmType -> Maybe LlvmLit
+garbageLit t@(LMInt w)     = Just (LMIntLit (0xbbbbbbbbbbbbbbb0 `mod` (2^w)) t)
+  -- Use a value that looks like an untagged pointer, so we are more
+  -- likely to try to enter it
+garbageLit t
+  | isFloat t              = Just (LMFloatLit 12345678.9 t)
+garbageLit t@(LMPointer _) = Just (LMNullLit t)
+  -- Using null isn't totally ideal, since some functions may check for null.
+  -- But producing another value is inconvenient since it needs a cast,
+  -- and the knowledge for how to format casts is in PpLlvm.
+garbageLit _               = Nothing
+  -- More cases could be added, but this should do for now.
 
 -- | Return the 'LlvmType' of the 'LlvmVar'
 getVarType :: LlvmVar -> LlvmType
index 83de48c..b86d1a7 100644 (file)
@@ -422,6 +422,7 @@ data GeneralFlag
    | Opt_PedanticBottoms                -- Be picky about how we treat bottom
    | Opt_LlvmTBAA                       -- Use LLVM TBAA infastructure for improving AA (hidden flag)
    | Opt_LlvmPassVectorsInRegisters     -- Pass SIMD vectors in registers (requires a patched LLVM) (hidden flag)
+   | Opt_LlvmFillUndefWithGarbage       -- Testing for undef bugs (hidden flag)
    | Opt_IrrefutableTuples
    | Opt_CmmSink
    | Opt_CmmElimCommonBlocks
@@ -3055,6 +3056,7 @@ fFlags = [
   flagSpec "liberate-case"                    Opt_LiberateCase,
   flagHiddenSpec "llvm-pass-vectors-in-regs"  Opt_LlvmPassVectorsInRegisters,
   flagHiddenSpec "llvm-tbaa"                  Opt_LlvmTBAA,
+  flagHiddenSpec "llvm-fill-undef-with-garbage" Opt_LlvmFillUndefWithGarbage,
   flagSpec "loopification"                    Opt_Loopification,
   flagSpec "omit-interface-pragmas"           Opt_OmitInterfacePragmas,
   flagSpec "omit-yields"                      Opt_OmitYields,
index 94892d4..1a636fa 100644 (file)
@@ -1,4 +1,5 @@
 SRC_HC_OPTS        = -O0 -H64m
+SRC_HC_OPTS_STAGE1 = -fllvm-fill-undef-with-garbage   # See Trac 11487
 GhcStage1HcOpts    = -O
 GhcStage2HcOpts    = -O -dcore-lint
 GhcLibHcOpts       = -O -dcore-lint