mimalloc icon indicating copy to clipboard operation
mimalloc copied to clipboard

abort() in vsnprintf with MIMALLOC_VERBOSE=1, threads, and setlocale (Windows)

Open vaintroub opened this issue 2 years ago • 3 comments

On Windows, If MIMALLOC_VERBOSE=1 environment variable is set, and a thread is created after setlocale(), then thread initialization code crashes with stacktrace below. Apparently, it seems that ucrtbase.dll is expecting/missing some thread-local locale-related variable, when its vsnprintf() is called. Also, debug CRT does not abort, only optimized version does.

I can reproduce with the below code, compiled RelWithDebInfo or Release (or MinSizeRel), with mimalloc malloc override is used.

#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <locale.h>

unsigned int __stdcall thread_func(void*)
{
	printf("In second thread...\n");
	return 0;
}

int main()
{
	HANDLE hThread;
	unsigned int threadID;

	setlocale(LC_ALL, "en_US.UTF8");
	hThread = (HANDLE)_beginthreadex(NULL, 0, &thread_func, NULL, 0, &threadID);
	WaitForSingleObject(hThread, INFINITE);
	CloseHandle(hThread);
}

Stacktrace:


1 ucrtbase.dll!abort 2 ucrtbase.dll!__crt_cached_ptd_host::update_locale_slow 3 ucrtbase.dll!__crt_stdio_output::output_processor<char,__crt_stdio_output::string_output_adapter,__crt_stdio_output::standard_base<char,__crt_stdio_output::string_output_adapter>>::process 4 ucrtbase.dll!common_vsprintf<__crt_stdio_output::standard_base,char> 5 ucrtbase.dll!__stdio_common_vsprintf 6 [Inline Frame] mimalloc.dll!vsnprintf 7 mimalloc.dll!mi_vfprintf 8 mimalloc.dll!_mi_verbose_message 9 mimalloc.dll!mi_reserve_os_memory_ex 10 mimalloc.dll!mi_arena_reserve 11 mimalloc.dll!_mi_arena_alloc_aligned 12 mimalloc.dll!mi_segment_os_alloc 13 mimalloc.dll!mi_segment_alloc 14 mimalloc.dll!mi_segment_reclaim_or_alloc 15 mimalloc.dll!mi_segments_page_alloc 16 mimalloc.dll!_mi_segment_page_alloc 17 mimalloc.dll!mi_page_fresh_alloc 18 mimalloc.dll!mi_page_queue_find_free_ex 19 [Inline Frame] mimalloc.dll!mi_find_free_page 20 mimalloc.dll!mi_find_page 21 mimalloc.dll!_mi_malloc_generic 22 mimalloc.dll!mi_heap_calloc 23 ucrtbase.dll!DllMainDispatch 24 ntdll.dll!LdrpCallInitRoutine 25 ntdll.dll!LdrpInitializeThread 26 ntdll.dll!_LdrpInitialize 27 ntdll.dll!LdrpInitializeInternal 28 ntdll.dll!LdrInitializeThunk

Looking at the stacktrace, it seems that ucrtbase.dll's function __stdio_common_vsprintf is called inside ucrtbase.dll's DllMain function ucrtbase.dll!DllMainDispatch(). Not sure how safe that is. Perhaps it tries to use thread local storage which is not initialized yet. An alternative could be a self-written locale-unaware minimal version of vsnprintf, or using _vsnprintf exported function by ntdll.dll.

mimalloc_bug.zip

vaintroub avatar Jun 21 '23 18:06 vaintroub

This issue seems will be fixed in the next release: #740

portsip avatar Jun 22 '23 13:06 portsip

@portsip , thanks. #740 is still open, but now there is a repro for @daanx at least

vaintroub avatar Jun 22 '23 16:06 vaintroub

You can check the dev branch, there has the commits for this issue, but not merge to master yet.

portsip avatar Jun 22 '23 17:06 portsip