Unittests on Windows debug can crash after returning from main()

XMLWordPrintableJSON

    • Type: Task
    • Resolution: Fixed
    • Priority: Major - P3
    • 4.1.10
    • 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
      

            Assignee:
            Henrik Edin
            Reporter:
            Henrik Edin
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: