GCC + ASan debug builds: runtime SEGV in sha256_sse4::Transform on CPUs without SHA-NI #34881

issue deadmanoz openend this issue on March 20, 2026
  1. deadmanoz commented at 1:42 pm on March 20, 2026: contributor

    Building Bitcoin Core with GCC + ASan in debug mode (CMAKE_BUILD_TYPE=Debug) causes an immediate SEGV on startup on CPUs without SHA-NI. The crash happens inside sha256_sse4::Transform during SHA256AutoDetect()’s self-test, before the node does anything else.

    This only affects CPUs that use the SSE4 SHA256 code path (those without SHA-NI). The existing no_sanitize("address") workaround in sha256_sse4.cpp only covers Clang (#30097, #32437) - GCC is not handled.

    I hit this while running the peer-observer/infra-library NixOS VM test suite (context), which builds Bitcoin Core with GCC and ASan enabled.

    Crash trace

    Excerpt from my original reproduction (NixOS, GCC 13.3.0):

     0AddressSanitizer:DEADLYSIGNAL
     1=================================================================
     2==680269==ERROR: AddressSanitizer: SEGV on unknown address 0x00006a09e607 (pc 0x55c20e591c00 bp 0x7fff925f4380 sp 0x7fff925f4250 T0)
     3==680269==The signal is caused by a WRITE memory access.
     4    [#0](/bitcoin-bitcoin/0/) 0x55c20e591c00 in sha256_sse4::Transform(unsigned int*, unsigned char const*, unsigned long) /home/deadmanoz/bitcoin/src/crypto/sha256_sse4.cpp:54
     5    [#1](/bitcoin-bitcoin/1/) 0x55c20e58dfb2 in SelfTest /home/deadmanoz/bitcoin/src/crypto/sha256.cpp:538
     6    [#2](/bitcoin-bitcoin/2/) 0x55c20e58ea47 in SHA256AutoDetect[abi:cxx11](sha256_implementation::UseImplementation) /home/deadmanoz/bitcoin/src/crypto/sha256.cpp:688
     7    [#3](/bitcoin-bitcoin/3/) 0x55c20b3fb220 in operator() /home/deadmanoz/bitcoin/src/kernel/context.cpp:19
     8    ...
     9    [#14](/bitcoin-bitcoin/14/) 0x55c20b235126 in AppInit /home/deadmanoz/bitcoin/src/bitcoind.cpp:199
    10    [#15](/bitcoin-bitcoin/15/) 0x55c20b2366bb in main /home/deadmanoz/bitcoin/src/bitcoind.cpp:283
    11
    12SUMMARY: AddressSanitizer: SEGV /home/deadmanoz/bitcoin/src/crypto/sha256_sse4.cpp:54 in sha256_sse4::Transform(unsigned int*, unsigned char const*, unsigned long)
    13==680269==ABORTING
    

    How to reproduce

    On a CPU without SHA-NI:

    0cmake -B build -G Ninja \
    1  -DCMAKE_C_COMPILER=gcc \
    2  -DCMAKE_CXX_COMPILER=g++ \
    3  -DCMAKE_BUILD_TYPE=Debug \
    4  -DSANITIZERS=address
    5cmake --build build --target test_bitcoin -j$(nproc)
    6./build/bin/test_bitcoin --run_test=crypto_tests  # SEGV
    

    On CPUs with SHA-NI, first force the SSE4 path. This patches SHA256AutoDetect() to skip SHA-NI detection, so the function falls through to sha256_sse4::Transform where the bug lives:

    0sed -i 's/have_x86_shani = (ebx >> 29) & 1;/have_x86_shani = false;/' src/crypto/sha256.cpp
    

    Release builds have not been observed to trigger the crash.

    Tested configurations

    Reproduced across four configurations on three machines (GCC 13, 14, and 15) (Haswell CPUs without SHA-NI, NixOS and Ubuntu 24.04):

    CPU GCC OS Crash?
    Xeon E5-2620 v3 (Haswell) 13.3.0 (Nix) NixOS Yes
    Xeon E5-2620 v3 (Haswell) 13.3.0 (Ubuntu) Ubuntu 24.04 Yes
    Xeon E5-2620 v3 (Haswell) 14.3.0 (Nix) NixOS Yes
    Haswell (QEMU) 15.2.0 (Nix) NixOS Yes

    A CI matrix across GCC 13/14 confirms the pattern:

    Configuration Before fix After fix
    Debug + address (GCC 13, 14) SEGV Pass
    Debug + address,undefined (GCC 13, 14) SEGV Pass
    Release + address (GCC 13, 14) Pass Pass
    Release + address,undefined (GCC 13, 14) Pass Pass

    What’s happening

    In upstream master, the no_sanitize("address") attribute in sha256_sse4.cpp (lines 16-26) is wrapped in #if defined(__clang__). GCC skips that block entirely, so ASan instruments the function. ASan’s instrumentation is incompatible with this inline assembly in the failing configuration.

    The same no_sanitize("address") attribute works for both compilers. The only difference is how each compiler detects that ASan is active: Clang uses __has_feature(address_sanitizer), GCC uses __SANITIZE_ADDRESS__.

    Suggested fix

    Branch: fix/gcc-asan-sha256-sse4-only (PR to follow)

    Add a GCC branch to the existing guard:

    0#if defined(__clang__)
    1  #if __has_feature(address_sanitizer)
    2    __attribute__((no_sanitize("address")))
    3  #endif
    4#elif defined(__GNUC__) && defined(__SANITIZE_ADDRESS__)
    5  __attribute__((no_sanitize("address")))
    6#endif
    7void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)
    8{
    

    Branch: fix/gcc-asan-check-h (separate PR, pending feedback on whether this is worth including?)

    In upstream master, src/util/check.h has a similar gap for GCC < 14. The ASAN_POISON_MEMORY_REGION / ASAN_UNPOISON_MEMORY_REGION macros are gated by __has_feature(address_sanitizer), which GCC < 14 doesn’t support. On those versions, the macros silently become no-ops, and the pool allocator’s manual ASan poisoning (#32581) is inactive.

    GCC 14+ added __has_feature, so this only affects GCC 13 and older. The fix adds __SANITIZE_ADDRESS__ as a fallback:

    0#if defined(__has_feature)
    1#    if __has_feature(address_sanitizer)
    2#       include <sanitizer/asan_interface.h>
    3#    endif
    4#elif defined(__SANITIZE_ADDRESS__)
    5#    include <sanitizer/asan_interface.h>
    6#endif
    

    CI coverage comment

    Bitcoin Core’s CI only tests ASan with Clang. If GCC + ASan testing is not a goal, these fixes are still worth considering for consistency - downstream projects building with GCC + ASan (such as NixOS-based test infrastructure) will otherwise hit the crash or silently lose pool allocator coverage.

    • #29801 - Compilation failure with -O0 + -fsanitize=address due to inline asm
    • #31913 - build: x86 afl++ ASan build broken "error: inline assembly requires more registers than available"
    • #30097 - crypto: disable asan for sha256_sse4 with clang and -O0
    • #32437 - crypto: disable ASan for sha256_sse4 with Clang
    • llvm/llvm-project#92182 - clang: "expected relocatable expression" when compiling large inline asm with -O0 and address sanitizer


deadmanoz


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-03-31 12:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me