Cheng Shao pushed to branch wip/terrorjack/asan at Glasgow Haskell Compiler / GHC
Commits:
-
666418d6
by Cheng Shao at 2025-12-12T19:44:25+01:00
-
d1606a49
by Cheng Shao at 2025-12-12T19:44:25+01:00
-
367a9e8f
by Cheng Shao at 2025-12-12T19:44:25+01:00
10 changed files:
- hadrian/doc/flavours.md
- hadrian/src/Flavour.hs
- rts/.ubsan-suppressions
- rts/include/Stg.h
- + rts/include/rts/ASANUtils.h
- rts/rts.cabal
- rts/sm/MBlock.c
- testsuite/driver/testglobals.py
- testsuite/driver/testlib.py
- testsuite/tests/rts/T18623/all.T
Changes:
| ... | ... | @@ -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>
|
| ... | ... | @@ -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"
|
| 1 | +# libraries/bytestring/cbits/is-valid-utf8.c:66:14: runtime load of misaligned address 0x7ae45206f112 for type 'const uint64_t *' (aka 'const unsigned long *'), which requires 8 byte alignment
|
|
| 2 | +alignment:libraries/bytestring/cbits/is-valid-utf8.c
|
|
| 3 | + |
|
| 1 | 4 | # libraries/text/cbits/measure_off.c:50:39: runtime left shift of 1 by 31 places cannot be represented in type 'int'
|
| 2 | 5 | shift-base:libraries/text/cbits/measure_off.c
|
| 3 | 6 |
| ... | ... | @@ -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
|
| 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 | +} |
| ... | ... | @@ -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
|
| ... | ... | @@ -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 |
| ... | ... | @@ -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 |
| ... | ... | @@ -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 |
| ... | ... | @@ -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,
|