Skip to content

Crash on macOS generating MSL with sanitizers #2606

@abbaswasim

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions