Skip to content

Crash on macOS generating MSL with sanitizers #2606

Description

@abbaswasim

Every time I run my code with address and undefined behaviour sanitisers. I get a crash in random places usually in Spirv-Cross and it doesn't go further. An example of this is below. It has taken me a a while to work this out as this is working fine in normal conditions. The reason is there is a stack-overflow happening in SPIRV-Cross's recursive MSL codegen on worker threads only. ChatGPT says.

Under ASan each stack frame is larger, and std::thread workers typically get a much smaller default stack than the main thread, so deep recursion in spirv_cross::CompilerGLSL::emit_block_chain* / CompilerMSL::to_function_args exhausts it.

I tested this theory, below is a reproducer and steps to build and run in parallel vs non-parallel modes. This happens in one of my shaders test.frag with a ridiculously long nested if/else if statements.

I guess it's probably too much to ask to remove recursions, however this means in some cases sanitisers can't be used because of this. The demo will run on linux but I can't reproduce the issue. It's MacOs specific.

Reproducer is https://github.com/abbaswasim/spv_test git clone with submodules and then:

Run in serial, works fine:
./build.sh -p false

Run in parallel, results in SO:
./build.sh -p true

There is also an spv_test_pthreads.cpp that you can see to understand how using pthreads and increasing the stack size helps.

AddressSanitizer:DEADLYSIGNAL
AddressSanitizer=================================================================
:DEADLYSIGNAL
==25550==ERROR: AddressSanitizer: stack-overflow on address 0x00016fa73de0 (pc 0x00010538b2b4 bp 0x00016fa74660 sp 0x00016fa73da0 T1)
    #0 0x00010538b2b4 in printf_common(void*, char const*, char*)+0xfc (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1b2b4)
    #1 0x00010538bebc in vsprintf+0x64 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1bebc)
    #2 0x00010538c6f4 in sprintf+0x38 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1c6f4)
    #3 0x0001020fe980 in spirv_cross::convert_to_string(float, char) spirv_common.hpp:284
    #4 0x000101ec1dd4 in spirv_cross::CompilerGLSL::format_float(float) const spirv_glsl.cpp:20235
    #5 0x000101ec4dc0 in spirv_cross::CompilerGLSL::convert_float_to_string(spirv_cross::SPIRConstant const&, unsigned int, unsigned int) spirv_glsl.cpp:6383
    #6 0x000101ecbffc in spirv_cross::CompilerGLSL::constant_expression_vector(spirv_cross::SPIRConstant const&, unsigned int) spirv_glsl.cpp:6607
    #7 0x000101e3e8c8 in spirv_cross::CompilerGLSL::constant_expression(spirv_cross::SPIRConstant const&, bool, bool) spirv_glsl.cpp:6209
    #8 0x000101e67c90 in spirv_cross::CompilerGLSL::to_expression(unsigned int, bool) spirv_glsl.cpp:5641
    #9 0x000101e8ac3c in spirv_cross::CompilerGLSL::to_unpacked_expression(unsigned int, bool) spirv_glsl.cpp:5348
    #10 0x000101e92324 in spirv_cross::CompilerGLSL::to_enclosed_unpacked_expression(unsigned int, bool) spirv_glsl.cpp:5353
    #11 0x000101ee13d4 in spirv_cross::CompilerGLSL::emit_binary_op(unsigned int, unsigned int, unsigned int, unsigned int, char const*) spirv_glsl.cpp:7093
    #12 0x000101fc413c in spirv_cross::CompilerGLSL::emit_instruction(spirv_cross::Instruction const&) spirv_glsl.cpp:13640
    #13 0x00010061eac8 in spirv_cross::CompilerMSL::emit_instruction(spirv_cross::Instruction const&) spirv_msl.cpp:10700
    #14 0x000101f7a6f0 in spirv_cross::CompilerGLSL::emit_block_instructions(spirv_cross::SPIRBlock&) spirv_glsl.cpp:12190
    #15 0x0001020cf568 in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18426
    #16 0x0001020b3548 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18267
    #17 0x0001020b9bb4 in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17811
    #18 0x0001020bb99c in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, unsigned int, spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17840
    #19 0x0001020d161c in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18497
    #20 0x0001020b3548 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18267
    #21 0x0001020b9bb4 in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17811
    #22 0x0001020bbb8c in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, unsigned int, spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17847
    #23 0x0001020d161c in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18497
    #24 0x0001020b3548 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18267
    #25 0x0001020b9bb4 in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17811
    #26 0x0001020bbb8c in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, unsigned int, spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17847
    #27 0x0001020d161c in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18497
    #28 0x0001020b3548 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18267
    #29 0x0001020b9bb4 in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17811
    #30 0x0001020bbb8c in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, unsigned int, spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17847
    #31 0x0001020d161c in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18497
    #32 0x0001020b3548 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18267
    #33 0x0001020b9bb4 in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17811
    #34 0x0001020bbb8c in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, unsigned int, spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17847
    #35 0x0001020d161c in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18497
    #36 0x0001020b3548 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18267
    #37 0x0001020b9bb4 in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17811
    #38 0x0001020bbb8c in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, unsigned int, spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17847
    #39 0x0001020d161c in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18497
    #40 0x0001020b3548 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18267
    #41 0x0001020b9bb4 in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17811
    #42 0x0001020bbb8c in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, unsigned int, spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17847
    #43 0x0001020d161c in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18497
    #44 0x0001020b3548 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18267
    #45 0x0001020b9bb4 in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17811
    #46 0x0001020bbb8c in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, unsigned int, spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17847
    #47 0x0001020d161c in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18497
    #48 0x0001020b3548 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18267
    #49 0x0001020b9bb4 in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17811
    #50 0x0001020bbb8c in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, unsigned int, spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17847
    #51 0x0001020d161c in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18497
    #52 0x0001020b3548 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18267
    #53 0x0001020b9bb4 in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17811
    #54 0x0001020bbb8c in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, unsigned int, spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17847
    #55 0x0001020d161c in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18497
    #56 0x0001020b3548 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18267
    #57 0x0001020b9bb4 in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17811
    #58 0x0001020bbb8c in spirv_cross::CompilerGLSL::branch(spirv_cross::TypedID<(spirv_cross::Types)6>, unsigned int, spirv_cross::TypedID<(spirv_cross::Types)6>, spirv_cross::TypedID<(spirv_cross::Types)6>) spirv_glsl.cpp:17847
    #59 0x0001020d161c in spirv_cross::CompilerGLSL::emit_block_chain_inner(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18497
    #60 0x0001020b36b4 in spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock&) spirv_glsl.cpp:18272
    #61 0x000101ddbbbc in spirv_cross::CompilerGLSL::emit_function(spirv_cross::SPIRFunction&, spirv_cross::Bitset const&) spirv_glsl.cpp:17585
    #62 0x000101dd838c in spirv_cross::CompilerGLSL::emit_function(spirv_cross::SPIRFunction&, spirv_cross::Bitset const&) spirv_glsl.cpp:17465
    #63 0x0001004328b4 in spirv_cross::CompilerMSL::compile() spirv_msl.cpp:1851
    #64 0x0001003aa2cc in (anonymous namespace)::compile_spirv_to_msl(std::__1::vector<unsigned int, std::__1::allocator<unsigned int>> const&) spv_test.cpp:153
    #65 0x0001003a9514 in main::$_0::operator()(unsigned long) const spv_test.cpp:251
    #66 0x0001003a927c in void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()::operator()() const spv_test.cpp:177
    #67 0x0001003a90bc in decltype(std::declval<main::$_0 const&>()()) std::__1::__invoke[abi:ne200100]<void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()>(main::$_0 const&) invoke.h:179
    #68 0x0001003a8fb4 in void std::__1::__thread_execute[abi:ne200100]<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()>(std::__1::tuple<main::$_0 const&, void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()>&, std::__1::__tuple_indices<>) thread.h:205
    #69 0x0001003a81e4 in void* std::__1::__thread_proxy[abi:ne200100]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()>>(void*) thread.h:214
    #70 0x0001053aa418 in asan_thread_start(void*)+0x4c (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3a418)
    #71 0x00018e1ffc04 in _pthread_start+0x84 (libsystem_pthread.dylib:arm64e+0x6c04)
    #72 0x00018e1faba4 in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1ba4)

SUMMARY: AddressSanitizer: stack-overflow spirv_common.hpp:284 in spirv_cross::convert_to_string(float, char)
Thread T1 created by T0 here:
    #0 0x0001053a59f8 in pthread_create+0x5c (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x359f8)
    #1 0x0001003a7fac in std::__1::__libcpp_thread_create[abi:ne200100](_opaque_pthread_t**, void* (*)(void*), void*) pthread.h:182
    #2 0x0001003a7c24 in std::__1::thread::thread<void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'(), 0>(main::$_0 const&) thread.h:224
    #3 0x0001003a7984 in std::__1::thread::thread<void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'(), 0>(main::$_0 const&) thread.h:219
    #4 0x0001003a7920 in main::$_0 const&* std::__1::construct_at[abi:ne200100]<std::__1::thread, void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'(), std::__1::thread*>(main::$_0 const&*, void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()&&) construct_at.h:40
    #5 0x0001003a788c in main::$_0 const&* std::__1::__construct_at[abi:ne200100]<std::__1::thread, void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'(), std::__1::thread*>(main::$_0 const&*, void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()&&) construct_at.h:48
    #6 0x0001003a71fc in void std::__1::allocator_traits<std::__1::allocator<std::__1::thread>>::construct[abi:ne200100]<std::__1::thread, void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'(), void, 0>(std::__1::allocator<std::__1::thread>&, main::$_0 const&*, void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()&&) allocator_traits.h:318
    #7 0x0001003a6a78 in void std::__1::vector<std::__1::thread, std::__1::allocator<std::__1::thread>>::__construct_one_at_end[abi:ne200100]<void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()>(void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()&&) vector.h:742
    #8 0x0001003a192c in std::__1::thread& std::__1::vector<std::__1::thread, std::__1::allocator<std::__1::thread>>::emplace_back<void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()>(void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const::'lambda'()&&) vector.h:1133
    #9 0x00010039515c in void (anonymous namespace)::JobSystem::run<main::$_0 const&>(main::$_0 const&) const spv_test.cpp:177
    #10 0x000100392400 in main spv_test.cpp:268
    #11 0x00018de35d50  (<unknown module>)

==25550==ABORTING

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions