Cheng Shao pushed to branch wip/terrorjack/asan at Glasgow Haskell Compiler / GHC

Commits:

12 changed files:

Changes:

  • .gitlab/generate-ci/gen_ci.hs
    ... ... @@ -162,6 +162,7 @@ data BuildConfig
    162 162
                     , tablesNextToCode :: Bool
    
    163 163
                     , threadSanitiser :: Bool
    
    164 164
                     , ubsan :: Bool
    
    165
    +                , asan :: Bool
    
    165 166
                     , noSplitSections :: Bool
    
    166 167
                     , validateNonmovingGc :: Bool
    
    167 168
                     , textWithSIMDUTF :: Bool
    
    ... ... @@ -173,7 +174,7 @@ configureArgsStr :: BuildConfig -> String
    173 174
     configureArgsStr bc = unwords $
    
    174 175
          ["--enable-unregisterised"| unregisterised bc ]
    
    175 176
       ++ ["--disable-tables-next-to-code" | not (tablesNextToCode bc) ]
    
    176
    -  ++ ["--with-intree-gmp" | Just _ <- pure (crossTarget bc) ]
    
    177
    +  ++ ["--with-intree-gmp" | isJust (crossTarget bc) || ubsan bc || asan bc ]
    
    177 178
       ++ ["--with-system-libffi" | crossTarget bc == Just "wasm32-wasi" ]
    
    178 179
       ++ ["--enable-ipe-data-compression" | withZstd bc ]
    
    179 180
       ++ ["--enable-strict-ghc-toolchain-check"]
    
    ... ... @@ -188,6 +189,7 @@ mkJobFlavour BuildConfig{..} = Flavour buildFlavour opts
    188 189
                [HostFullyStatic | hostFullyStatic] ++
    
    189 190
                [ThreadSanitiser | threadSanitiser] ++
    
    190 191
                [UBSan | ubsan] ++
    
    192
    +           [ASan | asan] ++
    
    191 193
                [NoSplitSections | noSplitSections, buildFlavour == Release ] ++
    
    192 194
                [BootNonmovingGc | validateNonmovingGc ] ++
    
    193 195
                [TextWithSIMDUTF | textWithSIMDUTF]
    
    ... ... @@ -201,6 +203,7 @@ data FlavourTrans =
    201 203
         | HostFullyStatic
    
    202 204
         | ThreadSanitiser
    
    203 205
         | UBSan
    
    206
    +    | ASan
    
    204 207
         | NoSplitSections
    
    205 208
         | BootNonmovingGc
    
    206 209
         | TextWithSIMDUTF
    
    ... ... @@ -230,6 +233,7 @@ vanilla = BuildConfig
    230 233
       , tablesNextToCode = True
    
    231 234
       , threadSanitiser = False
    
    232 235
       , ubsan = False
    
    236
    +  , asan = False
    
    233 237
       , noSplitSections = False
    
    234 238
       , validateNonmovingGc = False
    
    235 239
       , textWithSIMDUTF = False
    
    ... ... @@ -283,8 +287,8 @@ llvm = vanilla { llvmBootstrap = True }
    283 287
     tsan :: BuildConfig
    
    284 288
     tsan = vanilla { threadSanitiser = True }
    
    285 289
     
    
    286
    -enableUBSan :: BuildConfig
    
    287
    -enableUBSan = vanilla { withDwarf = True, ubsan = True }
    
    290
    +enableUBSanASan :: BuildConfig
    
    291
    +enableUBSanASan = vanilla { withDwarf = True, ubsan = True, asan = True }
    
    288 292
     
    
    289 293
     noTntc :: BuildConfig
    
    290 294
     noTntc = vanilla { tablesNextToCode = False }
    
    ... ... @@ -381,6 +385,7 @@ flavourString (Flavour base trans) = base_string base ++ concatMap (("+" ++) . f
    381 385
         flavour_string HostFullyStatic = "host_fully_static"
    
    382 386
         flavour_string ThreadSanitiser = "thread_sanitizer_cmm"
    
    383 387
         flavour_string UBSan = "ubsan"
    
    388
    +    flavour_string ASan = "asan"
    
    384 389
         flavour_string NoSplitSections = "no_split_sections"
    
    385 390
         flavour_string BootNonmovingGc = "boot_nonmoving_gc"
    
    386 391
         flavour_string TextWithSIMDUTF = "text_simdutf"
    
    ... ... @@ -1213,15 +1218,24 @@ fedora_x86 =
    1213 1218
       , hackage_doc_job (disableValidate (standardBuildsWithConfig Amd64 (Linux Fedora43) releaseConfig))
    
    1214 1219
       , disableValidate (standardBuildsWithConfig Amd64 (Linux Fedora43) dwarf)
    
    1215 1220
       , disableValidate (standardBuilds Amd64 (Linux Fedora43))
    
    1216
    -    -- For UBSan jobs, only enable for validate/nightly pipelines.
    
    1217
    -    -- Also disable docs since it's not the point for UBSan jobs.
    
    1221
    +    -- For UBSan/ASan jobs, only enable for validate/nightly
    
    1222
    +    -- pipelines. Also disable docs since it's not the point for
    
    1223
    +    -- UBSan/ASan jobs.
    
    1224
    +    --
    
    1225
    +    -- See
    
    1226
    +    -- https://github.com/llvm/llvm-project/blob/llvmorg-21.1.8/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
    
    1227
    +    -- for ASAN options help, for now these are required to pass the
    
    1228
    +    -- testsuite
    
    1218 1229
       , modifyJobs
    
    1219 1230
           ( setVariable "HADRIAN_ARGS" "--docs=none"
    
    1220 1231
               . addVariable
    
    1221 1232
                 "UBSAN_OPTIONS"
    
    1222 1233
                 "suppressions=$CI_PROJECT_DIR/rts/.ubsan-suppressions"
    
    1234
    +          . addVariable
    
    1235
    +            "ASAN_OPTIONS"
    
    1236
    +            "detect_leaks=false:handle_segv=0:handle_sigfpe=0:verify_asan_link_order=false"
    
    1223 1237
           )
    
    1224
    -      $ validateBuilds Amd64 (Linux Fedora43) enableUBSan
    
    1238
    +      $ validateBuilds Amd64 (Linux Fedora43) enableUBSanASan
    
    1225 1239
       ]
    
    1226 1240
       where
    
    1227 1241
         hackage_doc_job = rename (<> "-hackage") . modifyJobs (addVariable "HADRIAN_ARGS" "--haddock-for-hackage")
    

  • .gitlab/jobs.yaml
    ... ... @@ -3195,7 +3195,7 @@
    3195 3195
           "XZ_OPT": "-9"
    
    3196 3196
         }
    
    3197 3197
       },
    
    3198
    -  "nightly-x86_64-linux-fedora43-validate+debug_info+ubsan": {
    
    3198
    +  "nightly-x86_64-linux-fedora43-validate+debug_info+ubsan+asan": {
    
    3199 3199
         "after_script": [
    
    3200 3200
           ".gitlab/ci.sh save_cache",
    
    3201 3201
           ".gitlab/ci.sh save_test_output",
    
    ... ... @@ -3206,7 +3206,7 @@
    3206 3206
         "artifacts": {
    
    3207 3207
           "expire_in": "8 weeks",
    
    3208 3208
           "paths": [
    
    3209
    -        "ghc-x86_64-linux-fedora43-validate+debug_info+ubsan.tar.xz",
    
    3209
    +        "ghc-x86_64-linux-fedora43-validate+debug_info+ubsan+asan.tar.xz",
    
    3210 3210
             "junit.xml",
    
    3211 3211
             "unexpected-test-output.tar.gz"
    
    3212 3212
           ],
    
    ... ... @@ -3248,14 +3248,15 @@
    3248 3248
           "x86_64-linux"
    
    3249 3249
         ],
    
    3250 3250
         "variables": {
    
    3251
    +      "ASAN_OPTIONS": "detect_leaks=false:handle_segv=0:handle_sigfpe=0:verify_asan_link_order=false",
    
    3251 3252
           "BIGNUM_BACKEND": "gmp",
    
    3252
    -      "BIN_DIST_NAME": "ghc-x86_64-linux-fedora43-validate+debug_info+ubsan",
    
    3253
    -      "BUILD_FLAVOUR": "validate+debug_info+ubsan",
    
    3254
    -      "CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check",
    
    3253
    +      "BIN_DIST_NAME": "ghc-x86_64-linux-fedora43-validate+debug_info+ubsan+asan",
    
    3254
    +      "BUILD_FLAVOUR": "validate+debug_info+ubsan+asan",
    
    3255
    +      "CONFIGURE_ARGS": "--with-intree-gmp --enable-strict-ghc-toolchain-check",
    
    3255 3256
           "HADRIAN_ARGS": "--docs=none",
    
    3256 3257
           "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check",
    
    3257 3258
           "RUNTEST_ARGS": "",
    
    3258
    -      "TEST_ENV": "x86_64-linux-fedora43-validate+debug_info+ubsan",
    
    3259
    +      "TEST_ENV": "x86_64-linux-fedora43-validate+debug_info+ubsan+asan",
    
    3259 3260
           "UBSAN_OPTIONS": "suppressions=$CI_PROJECT_DIR/rts/.ubsan-suppressions",
    
    3260 3261
           "XZ_OPT": "-9"
    
    3261 3262
         }
    
    ... ... @@ -7346,7 +7347,7 @@
    7346 7347
           "TEST_ENV": "x86_64-linux-fedora43-validate+debug_info"
    
    7347 7348
         }
    
    7348 7349
       },
    
    7349
    -  "x86_64-linux-fedora43-validate+debug_info+ubsan": {
    
    7350
    +  "x86_64-linux-fedora43-validate+debug_info+ubsan+asan": {
    
    7350 7351
         "after_script": [
    
    7351 7352
           ".gitlab/ci.sh save_cache",
    
    7352 7353
           ".gitlab/ci.sh save_test_output",
    
    ... ... @@ -7357,7 +7358,7 @@
    7357 7358
         "artifacts": {
    
    7358 7359
           "expire_in": "2 weeks",
    
    7359 7360
           "paths": [
    
    7360
    -        "ghc-x86_64-linux-fedora43-validate+debug_info+ubsan.tar.xz",
    
    7361
    +        "ghc-x86_64-linux-fedora43-validate+debug_info+ubsan+asan.tar.xz",
    
    7361 7362
             "junit.xml",
    
    7362 7363
             "unexpected-test-output.tar.gz"
    
    7363 7364
           ],
    
    ... ... @@ -7383,7 +7384,7 @@
    7383 7384
         ],
    
    7384 7385
         "rules": [
    
    7385 7386
           {
    
    7386
    -        "if": "((($ONLY_JOBS) && ($ONLY_JOBS =~ /.*\\bx86_64-linux-fedora43-validate\\+debug_info\\+ubsan(\\s|$).*/)) || (($ONLY_JOBS == null) && ((($CI_MERGE_REQUEST_LABELS =~ /.*full-ci.*/) || ($CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/) || ($CI_COMMIT_BRANCH == \"master\") || ($CI_COMMIT_BRANCH =~ /ghc-[0-9]+\\.[0-9]+/))))) && ($RELEASE_JOB != \"yes\") && ($NIGHTLY == null)",
    
    7387
    +        "if": "((($ONLY_JOBS) && ($ONLY_JOBS =~ /.*\\bx86_64-linux-fedora43-validate\\+debug_info\\+ubsan\\+asan(\\s|$).*/)) || (($ONLY_JOBS == null) && ((($CI_MERGE_REQUEST_LABELS =~ /.*full-ci.*/) || ($CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/) || ($CI_COMMIT_BRANCH == \"master\") || ($CI_COMMIT_BRANCH =~ /ghc-[0-9]+\\.[0-9]+/))))) && ($RELEASE_JOB != \"yes\") && ($NIGHTLY == null)",
    
    7387 7388
             "when": "on_success"
    
    7388 7389
           }
    
    7389 7390
         ],
    
    ... ... @@ -7399,14 +7400,15 @@
    7399 7400
           "x86_64-linux"
    
    7400 7401
         ],
    
    7401 7402
         "variables": {
    
    7403
    +      "ASAN_OPTIONS": "detect_leaks=false:handle_segv=0:handle_sigfpe=0:verify_asan_link_order=false",
    
    7402 7404
           "BIGNUM_BACKEND": "gmp",
    
    7403
    -      "BIN_DIST_NAME": "ghc-x86_64-linux-fedora43-validate+debug_info+ubsan",
    
    7404
    -      "BUILD_FLAVOUR": "validate+debug_info+ubsan",
    
    7405
    -      "CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check",
    
    7405
    +      "BIN_DIST_NAME": "ghc-x86_64-linux-fedora43-validate+debug_info+ubsan+asan",
    
    7406
    +      "BUILD_FLAVOUR": "validate+debug_info+ubsan+asan",
    
    7407
    +      "CONFIGURE_ARGS": "--with-intree-gmp --enable-strict-ghc-toolchain-check",
    
    7406 7408
           "HADRIAN_ARGS": "--docs=none",
    
    7407 7409
           "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check",
    
    7408 7410
           "RUNTEST_ARGS": "",
    
    7409
    -      "TEST_ENV": "x86_64-linux-fedora43-validate+debug_info+ubsan",
    
    7411
    +      "TEST_ENV": "x86_64-linux-fedora43-validate+debug_info+ubsan+asan",
    
    7410 7412
           "UBSAN_OPTIONS": "suppressions=$CI_PROJECT_DIR/rts/.ubsan-suppressions"
    
    7411 7413
         }
    
    7412 7414
       },
    

  • hadrian/doc/flavours.md
    ... ... @@ -242,6 +242,10 @@ The supported transformers are listed below:
    242 242
             <td><code>ubsan</code></td>
    
    243 243
             <td>Build all stage1+ C/C++ code with UndefinedBehaviorSanitizer support</td>
    
    244 244
         </tr>
    
    245
    +    <tr>
    
    246
    +        <td><code>asan</code></td>
    
    247
    +        <td>Build all stage1+ C/C++ code with AddressSanitizer support</td>
    
    248
    +    </tr>
    
    245 249
         <tr>
    
    246 250
             <td><code>llvm</code></td>
    
    247 251
             <td>Use GHC's LLVM backend (`-fllvm`) for all stage1+ compilation.</td>
    

  • hadrian/src/Flavour.hs
    ... ... @@ -8,6 +8,7 @@ module Flavour
    8 8
       , splitSections
    
    9 9
       , enableThreadSanitizer
    
    10 10
       , enableUBSan
    
    11
    +  , enableASan
    
    11 12
       , enableLateCCS
    
    12 13
       , enableHashUnitIds
    
    13 14
       , enableDebugInfo, enableTickyGhc
    
    ... ... @@ -56,6 +57,7 @@ flavourTransformers = M.fromList
    56 57
         , "thread_sanitizer" =: enableThreadSanitizer False
    
    57 58
         , "thread_sanitizer_cmm" =: enableThreadSanitizer True
    
    58 59
         , "ubsan"            =: enableUBSan
    
    60
    +    , "asan"             =: enableASan
    
    59 61
         , "llvm"             =: viaLlvmBackend
    
    60 62
         , "profiled_ghc"     =: enableProfiledGhc
    
    61 63
         , "no_dynamic_ghc"   =: disableDynamicGhcPrograms
    
    ... ... @@ -303,6 +305,28 @@ enableUBSan =
    303 305
               builder Testsuite ? arg "--config=have_ubsan=True"
    
    304 306
             ]
    
    305 307
     
    
    308
    +-- | Build all stage1+ C/C++ code with AddressSanitizer support:
    
    309
    +-- https://clang.llvm.org/docs/AddressSanitizer.html
    
    310
    +enableASan :: Flavour -> Flavour
    
    311
    +enableASan =
    
    312
    +  addArgs $
    
    313
    +    notStage0
    
    314
    +      ? mconcat
    
    315
    +        [ package rts
    
    316
    +            ? builder (Cabal Flags)
    
    317
    +            ? arg "+asan"
    
    318
    +            <> (needSharedLibSAN ? arg "+shared-libsan"),
    
    319
    +          builder (Ghc CompileHs) ? arg "-optc-fsanitize=address",
    
    320
    +          builder (Ghc CompileCWithGhc) ? arg "-optc-fsanitize=address",
    
    321
    +          builder (Ghc CompileCppWithGhc) ? arg "-optcxx-fsanitize=address",
    
    322
    +          builder (Ghc LinkHs)
    
    323
    +            ? arg "-optc-fsanitize=address"
    
    324
    +            <> arg "-optl-fsanitize=address"
    
    325
    +            <> (needSharedLibSAN ? arg "-optl-shared-libsan"),
    
    326
    +          builder (Cc CompileC) ? arg "-fsanitize=address",
    
    327
    +          builder Testsuite ? arg "--config=have_asan=True"
    
    328
    +        ]
    
    329
    +
    
    306 330
     -- | Use the LLVM backend in stages 1 and later.
    
    307 331
     viaLlvmBackend :: Flavour -> Flavour
    
    308 332
     viaLlvmBackend = addArgs $ notStage0 ? builder Ghc ? arg "-fllvm"
    

  • rts/include/Stg.h
    ... ... @@ -335,6 +335,7 @@ external prototype return neither of these types to workaround #11395.
    335 335
     #include "stg/MachRegsForHost.h"
    
    336 336
     #include "stg/Regs.h"
    
    337 337
     #include "stg/Ticky.h"
    
    338
    +#include "rts/ASANUtils.h"
    
    338 339
     #include "rts/TSANUtils.h"
    
    339 340
     
    
    340 341
     #if IN_STG_CODE
    

  • rts/include/rts/ASANUtils.h
    1
    +#pragma once
    
    2
    +
    
    3
    +#if defined(__SANITIZE_ADDRESS__)
    
    4
    +#define ASAN_ENABLED
    
    5
    +#elif defined(__has_feature)
    
    6
    +#if __has_feature(address_sanitizer)
    
    7
    +#define ASAN_ENABLED
    
    8
    +#endif
    
    9
    +#endif
    
    10
    +
    
    11
    +#if defined(ASAN_ENABLED)
    
    12
    +#include <sanitizer/asan_interface.h>
    
    13
    +#define USED_IF_ASAN
    
    14
    +#else
    
    15
    +#include <stdlib.h>
    
    16
    +#define USED_IF_ASAN __attribute__((unused))
    
    17
    +#endif
    
    18
    +
    
    19
    +static inline void
    
    20
    +__ghc_asan_poison_memory_region(void const volatile *addr USED_IF_ASAN,
    
    21
    +                                size_t size USED_IF_ASAN) {
    
    22
    +#if defined(ASAN_ENABLED)
    
    23
    +  __asan_poison_memory_region(addr, size);
    
    24
    +#endif
    
    25
    +}
    
    26
    +
    
    27
    +static inline void
    
    28
    +__ghc_asan_unpoison_memory_region(void const volatile *addr USED_IF_ASAN,
    
    29
    +                                  size_t size USED_IF_ASAN) {
    
    30
    +#if defined(ASAN_ENABLED)
    
    31
    +  __asan_unpoison_memory_region(addr, size);
    
    32
    +#endif
    
    33
    +}

  • rts/rts.cabal
    ... ... @@ -97,6 +97,12 @@ flag ubsan
    97 97
         UndefinedBehaviorSanitizer.
    
    98 98
       default: False
    
    99 99
       manual: True
    
    100
    +flag asan
    
    101
    +  description:
    
    102
    +    Link with -fsanitize=address, to be enabled when building with
    
    103
    +    AddressSanitizer.
    
    104
    +  default: False
    
    105
    +  manual: True
    
    100 106
     flag shared-libsan
    
    101 107
       description:
    
    102 108
         Link with -shared-libsan, to guarantee only one copy of the
    
    ... ... @@ -216,6 +222,9 @@ library
    216 222
           if flag(ubsan)
    
    217 223
             ld-options: -fsanitize=undefined
    
    218 224
     
    
    225
    +      if flag(asan)
    
    226
    +        ld-options: -fsanitize=address
    
    227
    +
    
    219 228
           if flag(shared-libsan)
    
    220 229
             ld-options: -shared-libsan
    
    221 230
     
    
    ... ... @@ -280,6 +289,7 @@ library
    280 289
                             -- ^ generated
    
    281 290
                             rts/ghc_ffi.h
    
    282 291
                             rts/Adjustor.h
    
    292
    +                        rts/ASANUtils.h
    
    283 293
                             rts/ExecPage.h
    
    284 294
                             rts/BlockSignals.h
    
    285 295
                             rts/Bytecodes.h
    

  • rts/sm/MBlock.c
    ... ... @@ -579,6 +579,8 @@ getMBlocks(uint32_t n)
    579 579
     
    
    580 580
         ret = getCommittedMBlocks(n);
    
    581 581
     
    
    582
    +    __ghc_asan_unpoison_memory_region(ret, (W_)n * MBLOCK_SIZE);
    
    583
    +
    
    582 584
         debugTrace(DEBUG_gc, "allocated %d megablock(s) at %p",n,ret);
    
    583 585
     
    
    584 586
         mblocks_allocated += n;
    
    ... ... @@ -611,6 +613,8 @@ freeMBlocks(void *addr, uint32_t n)
    611 613
     
    
    612 614
         mblocks_allocated -= n;
    
    613 615
     
    
    616
    +    __ghc_asan_poison_memory_region(addr, (W_)n * MBLOCK_SIZE);
    
    617
    +
    
    614 618
         decommitMBlocks(addr, n);
    
    615 619
     }
    
    616 620
     
    

  • testsuite/driver/testglobals.py
    ... ... @@ -189,6 +189,9 @@ class TestConfig:
    189 189
             # Are we running with UndefinedBehaviorSanitizer enabled?
    
    190 190
             self.have_ubsan = False
    
    191 191
     
    
    192
    +        # Are we running with AddressSanitizer enabled?
    
    193
    +        self.have_asan = False
    
    194
    +
    
    192 195
             # Do symbols use leading underscores?
    
    193 196
             self.leading_underscore = False
    
    194 197
     
    

  • testsuite/driver/testlib.py
    ... ... @@ -1093,6 +1093,9 @@ def have_thread_sanitizer( ) -> bool:
    1093 1093
     def have_ubsan( ) -> bool:
    
    1094 1094
         return config.have_ubsan
    
    1095 1095
     
    
    1096
    +def have_asan( ) -> bool:
    
    1097
    +    return config.have_asan
    
    1098
    +
    
    1096 1099
     def gcc_as_cmmp() -> bool:
    
    1097 1100
         return config.cmm_cpp_is_gcc
    
    1098 1101
     
    

  • testsuite/tests/rts/T18623/all.T
    ... ... @@ -8,6 +8,8 @@ test('T18623',
    8 8
          # Recent versions of osx report an error when running `ulimit -v`
    
    9 9
          when(opsys('darwin'), skip),
    
    10 10
          when(arch('powerpc64le'), skip),
    
    11
    +     # ASan can't allocate shadow memory
    
    12
    +     when(have_asan(), skip),
    
    11 13
          cmd_prefix('ulimit -v ' + str(8 * 1024 ** 2) + ' && '),
    
    12 14
          ignore_stdout],
    
    13 15
         run_command,
    

  • testsuite/tests/rts/all.T
    ... ... @@ -105,6 +105,8 @@ def remove_parenthesis(s):
    105 105
         return re.sub(r'\s+\([^)]*\)', '', s)
    
    106 106
     
    
    107 107
     test('outofmem', [ when(opsys('darwin'), skip),
    
    108
    +                   # ASan shadow memory allocation blows up
    
    109
    +                   when(have_asan(), skip),
    
    108 110
                        # this is believed to cause other processes to die
    
    109 111
                        # that happen concurrently while the outofmem test
    
    110 112
                        # runs in CI. As such we'll need to disable it on