Unsolved SIGSEGV in QCoreApplication destructor "QCoreApplicationPrivate::eventDispatcher->closingDown();". What can it be?
-
Hi!
I get SIGSEGV when closing down my QT application, in the QCoreApplication destructor.
I installed debug symbols (am on Ubuntu) and get that it is on line 917:
"QCoreApplicationPrivate::eventDispatcher->closingDown();"
I've tried and failed to find more info on what I could be doing wrong - any tips?
Thank you!
-
Please provide a stack trace of the crash.
-
Hi, here it is!
[Switching to Thread 0x7ffff6e77680 (LWP 239376)] 0x0000000000000001 in ?? () (gdb) bt #0 0x0000000000000001 in ?? () #1 0x00007fffee217a0b in QCoreApplication::~QCoreApplication (this=0x7fffd0000b60, __in_chrg=<optimised out>) at kernel/qcoreapplication.cpp:917 #2 0x00007fffee217bed in QCoreApplication::~QCoreApplication (this=0x7fffd0000b60, __in_chrg=<optimised out>) at kernel/qcoreapplication.cpp:892 #3 0x00007fffee7543ea in std::default_delete<QCoreApplication>::operator() (this=0x555555bbb730, __ptr=0x7fffd0000b60) at /usr/include/c++/9/bits/unique_ptr.h:81 #4 0x00007fffee75385e in std::unique_ptr<QCoreApplication, std::default_delete<QCoreApplication> >::~unique_ptr (this=0x555555bbb730, __in_chrg=<optimised out>) at /usr/include/c++/9/bits/unique_ptr.h:292 #5 0x00007fffee7533bc in CApplicationLoopThread::~CApplicationLoopThread (this=0x555555bbb6b0, __in_chrg=<optimised out>) at src/vstmain.h:42 #6 0x00007fffee751dba in CLlconVST::~CLlconVST (this=0x555555bbb5c0, __in_chrg=<optimised out>) at src/vstmain.cpp:85 #7 0x00007fffee751de6 in CLlconVST::~CLlconVST (this=0x555555bbb5c0, __in_chrg=<optimised out>) at src/vstmain.cpp:88 #8 0x00007fffee71378e in AudioEffect::dispatchEffectClass (e=0x555555bbb5f0, opCode=1, index=0, value=0, ptr=0x0, opt=0) at ../vstsdk2.4/public.sdk/source/vst2.x/audioeffect.cpp:28 #9 0x00005555557227c6 in sushi::vst2::Vst2xWrapper::_vst_dispatcher (this=0x555555bb6630, opcode=1, index=0, value=0, ptr=0x0, opt=0) at /home/ilias/workspaces/sushi-develop/src/library/vst2x/vst2x_wrapper.h:151 #10 0x00005555557212a1 in sushi::vst2::Vst2xWrapper::_cleanup (this=0x555555bb6630) at /home/ilias/workspaces/sushi-develop/src/library/vst2x/vst2x_wrapper.cpp:268 #11 0x000055555571fadb in sushi::vst2::Vst2xWrapper::~Vst2xWrapper (this=0x555555bb6630, __in_chrg=<optimised out>) at /home/ilias/workspaces/sushi-develop/src/library/vst2x/vst2x_wrapper.cpp:47 #12 0x000055555561f287 in __gnu_cxx::new_allocator<sushi::vst2::Vst2xWrapper>::destroy<sushi::vst2::Vst2xWrapper> (this=0x555555bb6630, __p=0x555555bb6630) at /usr/include/c++/9/ext/new_allocator.h:153 #13 0x000055555561ee7f in std::allocator_traits<std::allocator<sushi::vst2::Vst2xWrapper> >::destroy<sushi::vst2::Vst2xWrapper> (__a=..., __p=0x555555bb6630) at /usr/include/c++/9/bits/alloc_traits.h:497 #14 0x000055555561e763 in std::_Sp_counted_ptr_inplace<sushi::vst2::Vst2xWrapper, std::allocator<sushi::vst2::Vst2xWrapper>, (__gnu_cxx::_Lock_policy)2>::_M_dispose ( this=0x555555bb6620) at /usr/include/c++/9/bits/shared_ptr_base.h:557 #15 0x00005555555cba14 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x555555bb6620) at /usr/include/c++/9/bits/shared_ptr_base.h:155 #16 0x00005555555cb2c3 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x555555bb9380, __in_chrg=<optimised out>) at /usr/include/c++/9/bits/shared_ptr_base.h:730 #17 0x00005555555feca6 in std::__shared_ptr<sushi::Processor, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0x555555bb9378, __in_chrg=<optimised out>) at /usr/include/c++/9/bits/shared_ptr_base.h:1169 #18 0x00005555555fecc6 in std::shared_ptr<sushi::Processor>::~shared_ptr (this=0x555555bb9378, __in_chrg=<optimised out>) at /usr/include/c++/9/bits/shared_ptr.h:103 #19 0x000055555561469a in std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> >::~pair ( this=0x555555bb9358, __in_chrg=<optimised out>) at /usr/include/c++/9/bits/stl_pair.h:208 #20 0x00005555556146ca in __gnu_cxx::new_allocator<std::__detail::_Hash_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> >, true> >::destroy<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> > > (this=0x7ffff62ed068, __p=0x555555bb9358) at /usr/include/c++/9/ext/new_allocator.h:153 #21 0x00005555556111b3 in std::allocator_traits<std::allocator<std::__detail::_Hash_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> >, true> > >::destroy<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> > > (__a=..., __p=0x555555bb9358) at /usr/include/c++/9/bits/alloc_traits.h:497 #22 0x000055555560c6cf in std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> >, true> > >::_M_deallocate_node (this=0x7ffff62ed068, __n=0x555555bb9350) at /usr/include/c++/9/bits/hashtable_policy.h:2102 #23 0x0000555555609ed0 in std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> >, true> > >::_M_deallocate_nodes (this=0x7ffff62ed068, __n=0x555555baeda0) at /usr/include/c++/9/bits/hashtable_policy.h:2124 #24 0x00005555556051ce in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> > >, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::clear (this=0x7ffff62ed068) at /usr/include/c++/9/bits/hashtable.h:2028 #25 0x00005555556008d8 in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> > >, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::~_Hashtable (this=0x7ffff62ed068, __in_chrg=<optimised out>) at /usr/include/c++/9/bits/hashtable.h:1352 #26 0x00005555555fe614 in std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::shared_ptr<sushi::Processor>, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::shared_ptr<sushi::Processor> > > >::~unordered_map (this=0x7ffff62ed068, __in_chrg=<optimised out>) at /usr/include/c++/9/bits/unordered_map.h:102 #27 0x00005555555fe96e in sushi::engine::ProcessorContainer::~ProcessorContainer (this=0x7ffff62ed060, __in_chrg=<optimised out>) at /home/ilias/workspaces/sushi-develop/src/engine/processor_container.h:37 #28 0x00005555555f5a0f in sushi::engine::AudioEngine::~AudioEngine (this=0x7ffff62ed040, __in_chrg=<optimised out>) at /home/ilias/workspaces/sushi-develop/src/engine/audio_engine.cpp:120 #29 0x00005555555f5a4e in sushi::engine::AudioEngine::~AudioEngine (this=0x7ffff62ed040, __in_chrg=<optimised out>) at /home/ilias/workspaces/sushi-develop/src/engine/audio_engine.cpp:128 #30 0x00005555555c4266 in std::default_delete<sushi::engine::AudioEngine>::operator() (this=0x7fffffffd950, __ptr=0x7ffff62ed040) at /usr/include/c++/9/bits/unique_ptr.h:81 #31 0x00005555555c2176 in std::unique_ptr<sushi::engine::AudioEngine, std::default_delete<sushi::engine::AudioEngine> >::~unique_ptr (this=0x7fffffffd950, __in_chrg=<optimised out>) at /usr/include/c++/9/bits/unique_ptr.h:292 #32 0x00005555555bd603 in main (argc=4, argv=0x7fffffffdd50) at /home/ilias/workspaces/sushi-develop/src/main.cpp:291
It happens following a SIGINT to the application, which causes it to start shutting down and destroying things.
There's another QT class running a thread which listens for UDP packets, nothing in particular in that stacktrace:
[Switching to thread 14 (Thread 0x7fffe16c6700 (LWP 239394))] #0 0x00007ffff7dae6c2 in __libc_recvfrom (fd=33, buf=0x7fffd006d090, len=20000, flags=0, addr=..., addrlen=0x7fffe16c5d2c) at ../sysdeps/unix/sysv/linux/recvfrom.c:27 27 ../sysdeps/unix/sysv/linux/recvfrom.c: No such file or directory. (gdb) bt #0 0x00007ffff7dae6c2 in __libc_recvfrom (fd=33, buf=0x7fffd006d090, len=20000, flags=0, addr=..., addrlen=0x7fffe16c5d2c) at ../sysdeps/unix/sysv/linux/recvfrom.c:27 #1 0x00007fffee745bc7 in CSocket::OnDataReceived (this=0x7fffd0009a10) at src/socket.cpp:173 #2 0x00007fffee729db3 in CSocketThread::run (this=0x7fffd00099f0) at src/socket.h:206 #3 0x00007fffee04d9d2 in QThreadPrivate::start (arg=0x7fffd00099f0) at thread/qthread_unix.cpp:361 #4 0x00007ffff7da3609 in start_thread (arg=<optimised out>) at pthread_create.c:477 #5 0x00007ffff74a1293 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
-
@IliasElk said in SIGSEGV in QCoreApplication destructor "QCoreApplicationPrivate::eventDispatcher->closingDown();". What can it be?:
It happens following a SIGINT to the application, which causes it to start shutting down and destroying things.
How? Would you post the signal handler as well?
Note that the signals may come through a different thread (a system one) and there's only a handful of things you can actually execute from the signal handler.
-
Thanks!
It's a non-QT application, which loads the one containing the QCoreApplication as a plugin.
Signal handler is:
bool exit_flag = false; bool exit_condition() {return exit_flag;} std::condition_variable exit_notifier; void sigint_handler([[maybe_unused]] int sig) { exit_flag = true; exit_notifier.notify_one(); }
Which notifies the main() method to de-allocate and exit:
(...) std::mutex m; td::unique_lock<std::mutex> lock(m); exit_notifier.wait(lock, exit_condition); (...)
Because QCoreApplication was taking over the signal handler, I restore it to my own in the plugin:
sigint_handler = signal ( SIGINT, SIG_DFL ); (...Create QCoreApplication and start it in separate thread...) auto previous = signal ( SIGINT, sigint_handler );
This is necessary, since the plugin should work in any host, not just mine, and I cannot have it take over handling SIGINT, as per this thread.
EDIT:
I realized you mean the QT Signal handler, doh.
class CSignalBase; class CSignalHandler : public QObject { Q_OBJECT friend class CSignalBase; friend class CSignalHandlerSingleton; public: static CSignalHandler* getSingletonP(); bool emitSignal ( int ); public slots: void OnSocketNotify ( int socket ); signals: void HandledSignal ( int sigNum ); private: QScopedPointer<CSignalBase> pSignalBase; explicit CSignalHandler(); ~CSignalHandler() override; }; // ---------------------------------------------------------- class CSignalBase { Q_DISABLE_COPY ( CSignalBase ) public: static CSignalBase* withSignalHandler ( CSignalHandler* ); virtual ~CSignalBase(); virtual QReadWriteLock* getLock() const = 0; QSet<int> sHandledSigNums; protected: CSignalBase ( CSignalHandler* ); CSignalHandler* pSignalHandler; template <typename T> static T *getSelf() { return static_cast<T*>( CSignalHandler::getSingletonP()->pSignalBase.data() ); } }; class CSignalUnix : public CSignalBase { public: CSignalUnix ( CSignalHandler* ); ~CSignalUnix() override; virtual QReadWriteLock* getLock() const override; private: QSocketNotifier* socketNotifier = nullptr; bool setSignalHandled ( int sigNum, bool state ); static int socketPair[2]; static void signalHandler ( int sigNum ); };
class CSignalHandlerSingleton : public CSignalHandler { public: inline CSignalHandlerSingleton() : CSignalHandler() {} }; Q_GLOBAL_STATIC ( CSignalHandlerSingleton, singleton ) CSignalHandler::CSignalHandler() : pSignalBase ( CSignalBase::withSignalHandler ( this ) ) {} CSignalHandler::~CSignalHandler() = default; CSignalHandler* CSignalHandler::getSingletonP() { return singleton; } bool CSignalHandler::emitSignal ( int sigNum ) { return QMetaObject::invokeMethod( singleton, "HandledSignal", Qt::QueuedConnection, Q_ARG( int, sigNum ) ); } void CSignalHandler::OnSocketNotify( int socket ) { int sigNum; if ( ::read ( socket, &sigNum, sizeof ( int ) ) == sizeof ( int ) ) { emitSignal ( sigNum ); } } // ---------------------------------------------------------- CSignalBase::CSignalBase ( CSignalHandler* pSignalHandler ) : pSignalHandler ( pSignalHandler ) { } CSignalBase::~CSignalBase() = default; CSignalBase* CSignalBase::withSignalHandler ( CSignalHandler* pSignalHandler ) { return new CSignalUnix ( pSignalHandler ); } int CSignalUnix::socketPair[2]; CSignalUnix::CSignalUnix ( CSignalHandler* nPSignalHandler ) : CSignalBase ( nPSignalHandler ) { if ( ::socketpair ( AF_UNIX, SOCK_STREAM, 0, socketPair ) == 0 ) { socketNotifier = new QSocketNotifier ( socketPair[ 1 ], QSocketNotifier::Read ); QObject::connect ( socketNotifier, &QSocketNotifier::activated, nPSignalHandler, &CSignalHandler::OnSocketNotify ); socketNotifier->setEnabled ( true ); setSignalHandled ( SIGUSR1, true ); setSignalHandled ( SIGUSR2, true ); setSignalHandled ( SIGINT, true ); setSignalHandled ( SIGTERM, true ); } } CSignalUnix::~CSignalUnix() { setSignalHandled ( SIGUSR1, false ); setSignalHandled ( SIGUSR2, false ); setSignalHandled ( SIGINT, false ); setSignalHandled ( SIGTERM, false ); } QReadWriteLock* CSignalUnix::getLock() const { return nullptr; } bool CSignalUnix::setSignalHandled ( int sigNum, bool state ) { struct sigaction sa; sigemptyset ( &sa.sa_mask ); if ( state ) { sa.sa_handler = CSignalUnix::signalHandler; sa.sa_flags = SA_RESTART; } else { sa.sa_handler = SIG_DFL; sa.sa_flags = 0; } return ::sigaction ( sigNum, &sa, nullptr ) == 0; } void CSignalUnix::signalHandler ( int sigNum ) { const auto res = ::write ( socketPair[ 0 ], &sigNum, sizeof ( int ) ); Q_UNUSED ( res ); }
-
Well, this is rather more involved than initially expected.
@IliasElk said in SIGSEGV in QCoreApplication destructor "QCoreApplicationPrivate::eventDispatcher->closingDown();". What can it be?:
Because QCoreApplication was taking over the signal handler, I restore it to my own in the plugin:
Qt doesn't install signal handlers, I'm pretty sure, so I think you're mistaken.
since the plugin should work in any host
Running the
QCoreApplication
in a thread different than main is not possible on macos, so you need to reconsider your design.Additional notes:
Q_GLOBAL_STATIC
is a bad idea, it creates an object on-demand, you don't want this here. You shouldn't allocate memory in the signal handler. Instead initialize the object(s) inmain
where you have determinism (similarly you allocate memory in theCSignalHandler
constructor).I think you're overengineering it. Your code looks way too complicated for what it's supposed to do. Why can't you realize all of this with one single
QObject
? -
Thank you!
The code is from a long-running open-source program (Jamulus) which I'm experimentally porting to a plugin format, the signal handler is actually not my code but from Jamulus.
With that said of course I should take ownership and address the errors inherited, it's super useful that you point them out!
The SIGINT signal handler stopped responding after instantiating the QCoreApplication so it must be doing something to it no? Fetching and re-setting it resolved the issue for SIGINT.
Regardless, if the QCoreApplication HAS to be in main in Mac OS, then it cannot be in a plugin where this cannot be guaranteed, that's a shame that QT precludes being used in plugins for non-QT hosts.
Unless it is possible to use QT without a QCoreApplication, but that doesn't seem to be the case.
I greatly appreciate your help!
Best,
Ilias. -
@IliasElk said in SIGSEGV in QCoreApplication destructor "QCoreApplicationPrivate::eventDispatcher->closingDown();". What can it be?:
The SIGINT signal handler stopped responding after instantiating the QCoreApplication so it must be doing something to it no? Fetching and re-setting it resolved the issue for SIGINT.
Well, I imagine it's something about the user code. Possibly the
QueuedConnection
call I spotted somewhere may be irresponsive.Regardless, if the QCoreApplication HAS to be in main in Mac OS, then it cannot be in a plugin where this cannot be guaranteed, that's a shame that QT precludes being used in plugins for non-QT hosts.
That's a limitation of the platform. Nothing Qt can do about it. The main event loop integration is mandated to be in the main thread on macos.