Inspired by @pachde’s VS Code debugging info, and prior work on the subject from @Richie and others, I’ve been actually setting up my IDE for Rack development rather than using the printf-and-pray approach I’ve gotten used to on little personal plugins.
Debugging Rack itself was working fine. When I started to bring in plugins, though (building against Rack, not the SDK), things went south. I was getting a bunch of SIGTRAP
s down in ntdll!RtlSetProcessPreferredUILanguages
as soon as the plugin’s first basic_string
was getting deallocated (which happens in different places on load-from-JSON and creation in the module browser, but there’s a sample call stack below if anyone’s curious). Things seemed to be going south when the ISO/GCC bits/new_allocator.h
was handing over to msvcrt!free
, so it felt like a library incompatibility.
-exec handle SIGTRAP nostop
“worked”, in the sense that I could continue, but it’s obviously not ideal.
This happened in exactly the same way with both Fundamental and my own plugins; however (this is the big clue!) it didn’t happen with the Core plugins, which get linked into Rack directly. I couldn’t identify any compilation option difference between Rack and the external plugins, but as a first step I removed LDFLAGS += -static-libstdc++
in the ARCH_WIN
section of plugin.mk
and recompiled my plugin, and it worked! No SIGTRAP
s, gdb
working as expected.
But I still feel a bit weird about this.
First, I don’t have an explanation for why static linking was causing whatever incompatibility was leading to the SIGTRAP
s–I’m compiling Rack and the plugins at the same time and they seem to be getting the same options, and I would expect fewer such issues with static linking anyway. Obviously I can change the makefile manually since I’m recompiling Rack anyway but it’s an uncomfortable feeling!
Second, as I was looking for some explanation for this, I found that the exact bugfix (plus a corresponding change for ARCH_LIN
) was considered for Rack v2.6.4 here but reverted just before it came out. @Vortico and team might not have been considering it for the same reasons, of course, and I presume there’s a good reason it was reverted–still, all very weird.
I’m going to get back to sequencer design now but am happy to help if anyone wants to dig deeper into this. (Rack 2.6.4, gcc 15.2.0, gdb 16.3, updated VS Code on Win10, by the way.)
Sample call stack for the SIGTRAP
s I was getting for static linking:
Thread 1 received signal SIGTRAP, Trace/breakpoint trap.
0x00007ff88cb9a8d7 in ntdll!RtlSetProcessPreferredUILanguages () from C:\WINDOWS\SYSTEM32\ntdll.dll
ntdll.dll!ntdll!RtlSetProcessPreferredUILanguages (Unknown Source:0)
ntdll.dll!ntdll!RtlValidateHeap (Unknown Source:0)
ntdll.dll!ntdll!RtlSizeHeap (Unknown Source:0)
ntdll.dll!ntdll!RtlAllocateHeap (Unknown Source:0)
ntdll.dll!ntdll!RtlFreeHeap (Unknown Source:0)
msvcrt.dll!msvcrt!free (Unknown Source:0)
plugin.dll!std::__new_allocator<char>::deallocate(std::__new_allocator<char> * const this, char * __p, std::__new_allocator<char>::size_type __n) ({msys2}\mingw64\include\c++\15.2.0\bits\new_allocator.h:156)
plugin.dll!std::allocator_traits<std::allocator<char> >::deallocate(std::allocator_traits<std::allocator<char> >::allocator_type & __a, std::allocator_traits<std::allocator<char> >::pointer __p, std::allocator_traits<std::allocator<char> >::size_type __n) ({msys2}\mingw64\include\c++\15.2.0\bits\alloc_traits.h:649)
plugin.dll!std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_destroy(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > * const this, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::size_type __size) ({msys2}\mingw64\include\c++\15.2.0\bits\basic_string.h:305)
plugin.dll!std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_dispose(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > * const this) ({msys2}\mingw64\include\c++\15.2.0\bits\basic_string.h:299)
plugin.dll!std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > * const this) ({msys2}\mingw64\include\c++\15.2.0\bits\basic_string.h:896)
plugin.dll!Functor::Functor(Functor * const this, Functor * const this@entry) ({devel}\Rack\plugins\Functor\src\Functor.cpp:345)
plugin.dll!rack::createModel<Functor, FunctorWidget>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)::TModel::createModule()(TModel * const this) ({devel}\Rack\include\helpers.hpp:27)
libRack.dll!rack::engine::Engine::fromJson(rack::engine::Engine * const this, json_t * rootJ) ({devel}\Rack\src\engine\Engine.cpp:1302)
libRack.dll!rack::patch::Manager::fromJson(rack::patch::Manager * const this, rack::patch::Manager * const this@entry, json_t * rootJ, json_t * rootJ@entry) ({devel}\Rack\src\patch.cpp:552)
libRack.dll!rack::patch::Manager::loadAutosave(rack::patch::Manager * const this, rack::patch::Manager * const this@entry) ({devel}\Rack\src\patch.cpp:381)
libRack.dll!rack::patch::Manager::launch(rack::patch::Manager * const this, std::string pathArg) ({devel}\Rack\src\patch.cpp:79)
main(int argc, char ** argv) ({devel}\Rack\adapters\standalone.cpp:260)