[Git][ghc/ghc][wip/terrorjack/asan] 3 commits: rts: add is-valid-utf8.c to .ubsan-suppressions
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 rts: add is-valid-utf8.c to .ubsan-suppressions - - - - - d1606a49 by Cheng Shao at 2025-12-12T19:44:25+01:00 hadrian: add support for building with AddressSanitizer This patch adds a +asan flavour transformer to hadrian to build all stage1+ C/C++ code with AddressBehaviorSanitizer. This is particularly useful to catch out-of-bounds and use-after-free bugs in the RTS codebase. export ASAN_OPTIONS=detect_leaks=false:handle_segv=0:handle_sigfpe=0:verify_asan_link_order=false - - - - - 367a9e8f by Cheng Shao at 2025-12-12T19:44:25+01:00 rts: add ASAN poisoning to mblock allocator - - - - - 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: ===================================== hadrian/doc/flavours.md ===================================== @@ -242,6 +242,10 @@ The supported transformers are listed below: <td><code>ubsan</code></td> <td>Build all stage1+ C/C++ code with UndefinedBehaviorSanitizer support</td> </tr> + <tr> + <td><code>asan</code></td> + <td>Build all stage1+ C/C++ code with AddressSanitizer support</td> + </tr> <tr> <td><code>llvm</code></td> <td>Use GHC's LLVM backend (`-fllvm`) for all stage1+ compilation.</td> ===================================== hadrian/src/Flavour.hs ===================================== @@ -8,6 +8,7 @@ module Flavour , splitSections , enableThreadSanitizer , enableUBSan + , enableASan , enableLateCCS , enableHashUnitIds , enableDebugInfo, enableTickyGhc @@ -56,6 +57,7 @@ flavourTransformers = M.fromList , "thread_sanitizer" =: enableThreadSanitizer False , "thread_sanitizer_cmm" =: enableThreadSanitizer True , "ubsan" =: enableUBSan + , "asan" =: enableASan , "llvm" =: viaLlvmBackend , "profiled_ghc" =: enableProfiledGhc , "no_dynamic_ghc" =: disableDynamicGhcPrograms @@ -303,6 +305,28 @@ enableUBSan = builder Testsuite ? arg "--config=have_ubsan=True" ] +-- | Build all stage1+ C/C++ code with AddressSanitizer support: +-- https://clang.llvm.org/docs/AddressSanitizer.html +enableASan :: Flavour -> Flavour +enableASan = + addArgs $ + notStage0 + ? mconcat + [ package rts + ? builder (Cabal Flags) + ? arg "+asan" + <> (needSharedLibSAN ? arg "+shared-libsan"), + builder (Ghc CompileHs) ? arg "-optc-fsanitize=address", + builder (Ghc CompileCWithGhc) ? arg "-optc-fsanitize=address", + builder (Ghc CompileCppWithGhc) ? arg "-optcxx-fsanitize=address", + builder (Ghc LinkHs) + ? arg "-optc-fsanitize=address" + <> arg "-optl-fsanitize=address" + <> (needSharedLibSAN ? arg "-optl-shared-libsan"), + builder (Cc CompileC) ? arg "-fsanitize=address", + builder Testsuite ? arg "--config=have_asan=True" + ] + -- | Use the LLVM backend in stages 1 and later. viaLlvmBackend :: Flavour -> Flavour viaLlvmBackend = addArgs $ notStage0 ? builder Ghc ? arg "-fllvm" ===================================== rts/.ubsan-suppressions ===================================== @@ -1,3 +1,6 @@ +# 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 +alignment:libraries/bytestring/cbits/is-valid-utf8.c + # libraries/text/cbits/measure_off.c:50:39: runtime left shift of 1 by 31 places cannot be represented in type 'int' shift-base:libraries/text/cbits/measure_off.c ===================================== rts/include/Stg.h ===================================== @@ -335,6 +335,7 @@ external prototype return neither of these types to workaround #11395. #include "stg/MachRegsForHost.h" #include "stg/Regs.h" #include "stg/Ticky.h" +#include "rts/ASANUtils.h" #include "rts/TSANUtils.h" #if IN_STG_CODE ===================================== rts/include/rts/ASANUtils.h ===================================== @@ -0,0 +1,33 @@ +#pragma once + +#if defined(__SANITIZE_ADDRESS__) +#define ASAN_ENABLED +#elif defined(__has_feature) +#if __has_feature(address_sanitizer) +#define ASAN_ENABLED +#endif +#endif + +#if defined(ASAN_ENABLED) +#include <sanitizer/asan_interface.h> +#define USED_IF_ASAN +#else +#include <stdlib.h> +#define USED_IF_ASAN __attribute__((unused)) +#endif + +static inline void +__ghc_asan_poison_memory_region(void const volatile *addr USED_IF_ASAN, + size_t size USED_IF_ASAN) { +#if defined(ASAN_ENABLED) + __asan_poison_memory_region(addr, size); +#endif +} + +static inline void +__ghc_asan_unpoison_memory_region(void const volatile *addr USED_IF_ASAN, + size_t size USED_IF_ASAN) { +#if defined(ASAN_ENABLED) + __asan_unpoison_memory_region(addr, size); +#endif +} ===================================== rts/rts.cabal ===================================== @@ -97,6 +97,12 @@ flag ubsan UndefinedBehaviorSanitizer. default: False manual: True +flag asan + description: + Link with -fsanitize=address, to be enabled when building with + AddressSanitizer. + default: False + manual: True flag shared-libsan description: Link with -shared-libsan, to guarantee only one copy of the @@ -216,6 +222,9 @@ library if flag(ubsan) ld-options: -fsanitize=undefined + if flag(asan) + ld-options: -fsanitize=address + if flag(shared-libsan) ld-options: -shared-libsan @@ -280,6 +289,7 @@ library -- ^ generated rts/ghc_ffi.h rts/Adjustor.h + rts/ASANUtils.h rts/ExecPage.h rts/BlockSignals.h rts/Bytecodes.h ===================================== rts/sm/MBlock.c ===================================== @@ -579,6 +579,8 @@ getMBlocks(uint32_t n) ret = getCommittedMBlocks(n); + __ghc_asan_unpoison_memory_region(ret, (W_)n * MBLOCK_SIZE); + debugTrace(DEBUG_gc, "allocated %d megablock(s) at %p",n,ret); mblocks_allocated += n; @@ -611,6 +613,8 @@ freeMBlocks(void *addr, uint32_t n) mblocks_allocated -= n; + __ghc_asan_poison_memory_region(addr, (W_)n * MBLOCK_SIZE); + decommitMBlocks(addr, n); } ===================================== testsuite/driver/testglobals.py ===================================== @@ -189,6 +189,9 @@ class TestConfig: # Are we running with UndefinedBehaviorSanitizer enabled? self.have_ubsan = False + # Are we running with AddressSanitizer enabled? + self.have_asan = False + # Do symbols use leading underscores? self.leading_underscore = False ===================================== testsuite/driver/testlib.py ===================================== @@ -1093,6 +1093,9 @@ def have_thread_sanitizer( ) -> bool: def have_ubsan( ) -> bool: return config.have_ubsan +def have_asan( ) -> bool: + return config.have_asan + def gcc_as_cmmp() -> bool: return config.cmm_cpp_is_gcc ===================================== testsuite/tests/rts/T18623/all.T ===================================== @@ -8,6 +8,8 @@ test('T18623', # Recent versions of osx report an error when running `ulimit -v` when(opsys('darwin'), skip), when(arch('powerpc64le'), skip), + # ASan can't allocate shadow memory + when(have_asan(), skip), cmd_prefix('ulimit -v ' + str(8 * 1024 ** 2) + ' && '), ignore_stdout], run_command, View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/65d3d03ff36402792b432915071d937... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/65d3d03ff36402792b432915071d937... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Cheng Shao (@TerrorJack)