-
Type:
Task
-
Resolution: Fixed
-
Priority:
Major - P3
-
Affects Version/s: None
-
Component/s: None
-
None
-
Fully Compatible
-
Dev Tools 2019-03-11, Dev Tools 2019-03-25, Dev Tools 2019-04-08
-
12
-
None
-
3
-
None
-
None
-
None
-
None
-
None
-
None
We currently experience spurious crashes of unittests on Windows debug builds with exit code C0000005 / -1073741819 Windows Access Violation even though we returned 0 from main().
The reason is that we don't shutdown various subsystems cleanly before returning from main causing races between new threads starting up and instantiating thread_locals that allocates memory while we're tearing down the debug CRT.
Even "single threaded" unittests have this problem because certain Windows API's like CertCreateCertificateChainEngine uses the Windows thread pool which may spawn new threads at any time.
There's two possible solutions:
1. quickExit instead of returning from main, at least on Windows debug
2. Attempt to use the same cleanup path as embedded for unittests and find&fix the problematic systems.
Below is an example of a shutdown crash like this:
Main thread:
ntdll.dll!NtWaitForSingleObject() Unknown ntdll.dll!LdrpDrainWorkQueue() Unknown ntdll.dll!LdrpLoadDllInternal() Unknown ntdll.dll!LdrpLoadDll() Unknown ntdll.dll!LdrLoadDll() Unknown KERNELBASE.dll!LoadLibraryExW() Unknown shard_registry_test.exe!try_load_library_from_system_directory(const wchar_t * const name) Line 199 C++ shard_registry_test.exe!try_get_module(const `anonymous-namespace'::module_id id) Line 238 C++ > shard_registry_test.exe!try_get_first_available_module(const `anonymous-namespace'::module_id * const first, const `anonymous-namespace'::module_id * const last) Line 271 C++ shard_registry_test.exe!try_get_proc_address_from_first_available_module(const char * const name, const `anonymous-namespace'::module_id * const first_module_id, const `anonymous-namespace'::module_id * const last_module_id) Line 289 C++ shard_registry_test.exe!try_get_function(const `anonymous-namespace'::function_id id, const char * const name, const `anonymous-namespace'::module_id * const first_module_id, const `anonymous-namespace'::module_id * const last_module_id) Line 326 C++ shard_registry_test.exe!try_get_AppPolicyGetProcessTerminationMethod() Line 377 C++ shard_registry_test.exe!__acrt_AppPolicyGetProcessTerminationMethodInternal(AppPolicyProcessTerminationMethod * policy) Line 737 C++ shard_registry_test.exe!`__acrt_get_process_end_policy'::`2'::process_end_policy_properties::appmodel_get_policy(AppPolicyProcessTerminationMethod * appmodelPolicy) Line 81 C++ shard_registry_test.exe!get_win_policy<`__acrt_get_process_end_policy'::`2'::process_end_policy_properties>(AppPolicyProcessTerminationMethod defaultValue) Line 26 C++ shard_registry_test.exe!__acrt_get_process_end_policy() Line 85 C++ shard_registry_test.exe!should_call_terminate_process() Line 112 C++ shard_registry_test.exe!exit_or_terminate_process(const unsigned int return_code) Line 134 C++ shard_registry_test.exe!common_exit(const int return_code, const _crt_exit_cleanup_mode cleanup_mode, const _crt_exit_return_mode return_mode) Line 282 C++ shard_registry_test.exe!exit(int return_code) Line 294 C++ shard_registry_test.exe!__scrt_common_main_seh() Line 297 C++ shard_registry_test.exe!__scrt_common_main() Line 331 C++ shard_registry_test.exe!mainCRTStartup() Line 17 C++ kernel32.dll!BaseThreadInitThunk() Unknown ntdll.dll!RtlUserThreadStart() Unknown
Windows thread pool thread:
ntdll.dll!RtlpWaitOnCriticalSection() Unknown ntdll.dll!RtlpEnterCriticalSectionContended() Unknown ntdll.dll!RtlEnterCriticalSection() Unknown shard_registry_test.exe!__acrt_lock(__acrt_lock_id _Lock) Line 55 C++ shard_registry_test.exe!heap_alloc_dbg_internal(const unsigned __int64 size, const int block_use, const char * const file_name, const int line_number) Line 309 C++ shard_registry_test.exe!heap_alloc_dbg(const unsigned __int64 size, const int block_use, const char * const file_name, const int line_number) Line 450 C++ shard_registry_test.exe!_malloc_dbg(unsigned __int64 size, int block_use, const char * file_name, int line_number) Line 496 C++ shard_registry_test.exe!malloc(unsigned __int64 size) Line 27 C++ > shard_registry_test.exe!operator new(unsigned __int64 size) Line 35 C++ [Inline Frame] shard_registry_test.exe!std::allocator<std::_Container_proxy>::allocate(const unsigned __int64) Line 997 C++ [Inline Frame] shard_registry_test.exe!std::_Deque_alloc<std::_Deque_base_types<std::function<void __cdecl(void)>,std::allocator<std::function<void __cdecl(void)> > > >::_Alloc_proxy() Line 787 C++ [Inline Frame] shard_registry_test.exe!std::_Deque_alloc<std::_Deque_base_types<std::function<void __cdecl(void)>,std::allocator<std::function<void __cdecl(void)> > > >::{ctor}() Line 731 C++ [Inline Frame] shard_registry_test.exe!std::deque<std::function<void __cdecl(void)>,std::allocator<std::function<void __cdecl(void)> > >::{ctor}() Line 929 C++ shard_registry_test.exe!`dynamic initializer for 'mongo::transport::ServiceExecutorSynchronous::_localWorkQueue''() Line 56 C++ shard_registry_test.exe!__dyn_tls_init(void * __formal, unsigned long dwReason, void * __formal) Line 96 C++ ntdll.dll!LdrpCallInitRoutine() Unknown ntdll.dll!LdrpCallTlsInitializers() Unknown ntdll.dll!LdrpInitializeThread() Unknown ntdll.dll!_LdrpInitialize() Unknown ntdll.dll!LdrInitializeThunk() Unknown