DaemonEngine / Daemon

The Dæmon game engine. With some bits of ioq3 and XreaL.
https://unvanquished.net
BSD 3-Clause "New" or "Revised" License
298 stars 61 forks source link

Static destruction race with audio handles #422

Open slipher opened 3 years ago

slipher commented 3 years ago

Some problem during shutdown was caught by the MSVC debug iterators, with the following stack trace:

daemon.exe!std::vector<int,std::allocator<int>>::_Orphan_range(int * _First, int * _Last) Line 1717
daemon.exe!std::vector<int,std::allocator<int>>::_Emplace_back_with_unused_capacity<int const &>(const int & <_Val_0>) Line 689
daemon.exe!std::vector<int,std::allocator<int>>::emplace_back<int const &>(const int & <_Val_0>) Line 705
daemon.exe!std::vector<int,std::allocator<int>>::push_back(const int & _Val) Line 718
daemon.exe!Audio::HandledResource<Audio::Sample>::~HandledResource<Audio::Sample>() Line 82
daemon.exe!Audio::Sample::~Sample() Line 45
daemon.exe!Audio::Sample::`scalar deleting destructor'(unsigned int)
daemon.exe!std::_Destroy_in_place<Audio::Sample>(Audio::Sample & _Obj) Line 279
daemon.exe!std::_Ref_count_obj2<Audio::Sample>::_Destroy() Line 1582
daemon.exe!std::_Ref_count_base::_Decref() Line 644
daemon.exe!std::_Ptr_base<Audio::Sample>::_Decref() Line 878
daemon.exe!std::shared_ptr<Audio::Sample>::~shared_ptr<Audio::Sample>() Line 1170
daemon.exe!Audio::HandledResource<Audio::Sample>::handleRecord_t::~handleRecord_t()
daemon.exe!Audio::HandledResource<Audio::Sample>::handleRecord_t::`scalar deleting destructor'(unsigned int)
daemon.exe!std::_Default_allocator_traits<std::allocator<Audio::HandledResource<Audio::Sample>::handleRecord_t>>::destroy<Audio::HandledResource<Audio::Sample>::handleRecord_t>(std::allocator<Audio::HandledResource<Audio::Sample>::handleRecord_t> & __formal, Audio::HandledResource<Audio::Sample>::handleRecord_t * const _Ptr) Line 707
daemon.exe!std::_Destroy_range<std::allocator<Audio::HandledResource<Audio::Sample>::handleRecord_t>>(Audio::HandledResource<Audio::Sample>::handleRecord_t * _First, Audio::HandledResource<Audio::Sample>::handleRecord_t * const _Last, std::allocator<Audio::HandledResource<Audio::Sample>::handleRecord_t> & _Al) Line 968
daemon.exe!std::vector<Audio::HandledResource<Audio::Sample>::handleRecord_t,std::allocator<Audio::HandledResource<Audio::Sample>::handleRecord_t>>::_Destroy(Audio::HandledResource<Audio::Sample>::handleRecord_t * _First, Audio::HandledResource<Audio::Sample>::handleRecord_t * _Last) Line 1613
daemon.exe!std::vector<Audio::HandledResource<Audio::Sample>::handleRecord_t,std::allocator<Audio::HandledResource<Audio::Sample>::handleRecord_t>>::_Tidy() Line 1696
daemon.exe!std::vector<Audio::HandledResource<Audio::Sample>::handleRecord_t,std::allocator<Audio::HandledResource<Audio::Sample>::handleRecord_t>>::~vector<Audio::HandledResource<Audio::Sample>::handleRecord_t,std::allocator<Audio::HandledResource<Audio::Sample>::handleRecord_t>>() Line 675
daemon.exe!`dynamic atexit destructor for 'Audio::HandledResource<Audio::Sample>::handles''()
ucrtbased.dll!000007feb6775107()
ucrtbased.dll!000007feb6774b15()
ucrtbased.dll!000007feb6774c4a()
ucrtbased.dll!000007feb67752b1()
ucrtbased.dll!000007feb6774481()
ucrtbased.dll!000007feb677432d()
ucrtbased.dll!000007feb677439a()
ucrtbased.dll!000007feb6774614()
ucrtbased.dll!000007feb67749a6()
daemon.exe!Sys::OSExit(int exitCode) Line 348
daemon.exe!Sys::Quit(Str::BasicStringRef<char> message) Line 298
daemon.exe!Sys::QuitCmd::Run(const Cmd::Args & args) Line 306
daemon.exe!Cmd::ExecuteCommand(Str::BasicStringRef<char> command, bool parseCvars, Cmd::Environment * env) Line 216
daemon.exe!Cmd::ExecuteCommandBuffer() Line 94
daemon.exe!Com_Frame() Line 1010
daemon.exe!Application::ClientApplication::Frame() Line 85
daemon.exe!Application::Frame() Line 74
daemon.exe!SDL_main(int argc, char * * argv) Line 688
daemon.exe!main(int argc, char * * argv) Line 140
daemon.exe!WinMain(HINSTANCE__ * hInst, HINSTANCE__ * hPrev, char * szCmdLine, int sw) Line 179
daemon.exe!invoke_main() Line 107
daemon.exe!__scrt_common_main_seh() Line 288
daemon.exe!__scrt_common_main() Line 331
daemon.exe!WinMainCRTStartup() Line 17
kernel32.dll!0000000076ff556d()
ntdll.dll!000000007725372d()

My opinion about static destructors is that it's best to skip them. Shutdown finishes much faster if you don't run all the destructors. I've been thinking we could have a variable like common.pedanticShutdown if you want to execute all of them (for leak checking or something), and otherwise do a quick exit. This could be applied to (non-DLL?) VMs as well as the engine.

illwieckz commented 3 years ago

common.pedanticShutdown would be good!

Also I have noticed the engine seems to reload the VFS after having asked to quit… right before quitting. Probably returning from game to main menu before quitting or something like that.

slipher commented 3 years ago

Also I have noticed the engine seems to reload the VFS after having asked to quit… right before quitting.

Yeah, I should finish up #201 which is kind of connected to this.