From: Bernhard Übelacker bernhardu@mailbox.org
A llvm-mingw built winver.exe with ASan enabled shows below error when exiting the application.
This seems to be caused by libc++ using register_onexit_function before ASan has all function hooks in place, therefore allocates memory with plain calloc function.
On process exit ASan uses in asan_allocator.cpp/Deallocate the function HeapValidate, which fails if msvcrt does not use the heap returned by GetProcessHeap(). --- dlls/msvcr100/tests/msvcr100.c | 15 +++++++++++++++ dlls/msvcr110/tests/msvcr110.c | 15 +++++++++++++++ dlls/msvcrt/heap.c | 6 ++++++ dlls/msvcrt/tests/heap.c | 17 +++++++++++++++++ dlls/ucrtbase/tests/misc.c | 17 +++++++++++++++++ 5 files changed, 70 insertions(+)
diff --git a/dlls/msvcr100/tests/msvcr100.c b/dlls/msvcr100/tests/msvcr100.c index 7bde5c7935d..c8ecc53b16a 100644 --- a/dlls/msvcr100/tests/msvcr100.c +++ b/dlls/msvcr100/tests/msvcr100.c @@ -239,6 +239,8 @@ static size_t (__cdecl *p___strncnt)(const char*, size_t);
static int (__cdecl *p_strcmp)(const char *, const char *); static int (__cdecl *p_strncmp)(const char *, const char *, size_t); +static void* (__cdecl *p_calloc)(size_t,size_t); +static void (__cdecl *p_free)(void*);
/* make sure we use the correct errno */ #undef errno @@ -282,6 +284,8 @@ static BOOL init(void)
SET(p_strcmp, "strcmp"); SET(p_strncmp, "strncmp"); + SET(p_calloc, "calloc"); + SET(p_free, "free");
if(sizeof(void*) == 8) { /* 64-bit initialization */ SET(pSpinWait_ctor_yield, "??0?$_SpinWait@$00@details@Concurrency@@QEAA@P6AXXZ@Z"); @@ -1152,6 +1156,16 @@ static void test_strcmp(void) ok( ret == 0, "wrong ret %d\n", ret ); }
+static void test_HeapValidate(void) +{ + void *ptr; + + ptr = p_calloc(1, 1); + ok(ptr != NULL, "got %p\n", ptr); + ok(!HeapValidate(GetProcessHeap(), 0, ptr), "HeapValidate unexpectedly succeeded\n"); + p_free(ptr); +} + START_TEST(msvcr100) { if (!init()) @@ -1173,4 +1187,5 @@ START_TEST(msvcr100) test_setlocale(); test___strncnt(); test_strcmp(); + test_HeapValidate(); } diff --git a/dlls/msvcr110/tests/msvcr110.c b/dlls/msvcr110/tests/msvcr110.c index 35ba370bb49..2848d67bd8e 100644 --- a/dlls/msvcr110/tests/msvcr110.c +++ b/dlls/msvcr110/tests/msvcr110.c @@ -54,6 +54,8 @@ static _Context* (__cdecl *p__Context__CurrentContext)(_Context*);
static int (__cdecl *p_strcmp)(const char *, const char *); static int (__cdecl *p_strncmp)(const char *, const char *, size_t); +static void* (__cdecl *p_calloc)(size_t,size_t); +static void (__cdecl *p_free)(void*);
#define SETNOFAIL(x,y) x = (void*)GetProcAddress(module,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) @@ -89,6 +91,8 @@ static BOOL init(void)
SET(p_strcmp, "strcmp"); SET(p_strncmp, "strncmp"); + SET(p_calloc, "calloc"); + SET(p_free, "free");
return TRUE; } @@ -307,6 +311,16 @@ static void test_strcmp(void) ok( ret == 0, "wrong ret %d\n", ret ); }
+static void test_HeapValidate(void) +{ + void *ptr; + + ptr = p_calloc(1, 1); + ok(ptr != NULL, "got %p\n", ptr); + ok(HeapValidate(GetProcessHeap(), 0, ptr), "HeapValidate unexpectedly failed\n"); + p_free(ptr); +} + START_TEST(msvcr110) { if (!init()) return; @@ -315,4 +329,5 @@ START_TEST(msvcr110) test___strncnt(); test_CurrentContext(); test_strcmp(); + test_HeapValidate(); } diff --git a/dlls/msvcrt/heap.c b/dlls/msvcrt/heap.c index bf06c37e2c5..a82f308165b 100644 --- a/dlls/msvcrt/heap.c +++ b/dlls/msvcrt/heap.c @@ -829,13 +829,19 @@ int CDECL wmemcpy_s(wchar_t *dest, size_t numberOfElements,
BOOL msvcrt_init_heap(void) { +#if _MSVCR_VER >= 110 + heap = GetProcessHeap(); +#else heap = HeapCreate(0, 0, 0); +#endif return heap != NULL; }
void msvcrt_destroy_heap(void) { +#if _MSVCR_VER >= 110 HeapDestroy(heap); +#endif if(sb_heap) HeapDestroy(sb_heap); } diff --git a/dlls/msvcrt/tests/heap.c b/dlls/msvcrt/tests/heap.c index e6de728f2b7..ea6021f717a 100644 --- a/dlls/msvcrt/tests/heap.c +++ b/dlls/msvcrt/tests/heap.c @@ -523,10 +523,27 @@ static void test_calloc(void) free(ptr); }
+static void test_HeapValidate(void) +{ + /* use function pointers to bypass gcc builtins */ + void* (__cdecl *p_calloc)(size_t,size_t); + void (__cdecl *p_free)(void*); + void *ptr; + + p_calloc = (void *)GetProcAddress( GetModuleHandleA("msvcrt.dll"), "calloc"); + p_free = (void *)GetProcAddress( GetModuleHandleA("msvcrt.dll"), "free"); + + ptr = p_calloc(1, 1); + ok(ptr != NULL, "got %p\n", ptr); + ok(!HeapValidate(GetProcessHeap(), 0, ptr), "HeapValidate unexpectedly succeeded\n"); + p_free(ptr); +} + START_TEST(heap) { test_aligned(); test_sbheap(); test_malloc(); test_calloc(); + test_HeapValidate(); } diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c index ff1ed20f2f8..72afcdc07fe 100644 --- a/dlls/ucrtbase/tests/misc.c +++ b/dlls/ucrtbase/tests/misc.c @@ -1706,6 +1706,22 @@ static void test_gmtime64(void) tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec); }
+static void test_HeapValidate(void) +{ + /* use function pointers to bypass gcc builtins */ + void* (__cdecl *p_calloc)(size_t,size_t); + void (__cdecl *p_free)(void*); + void *ptr; + + p_calloc = (void *)GetProcAddress( GetModuleHandleA("ucrtbase.dll"), "calloc"); + p_free = (void *)GetProcAddress( GetModuleHandleA("ucrtbase.dll"), "free"); + + ptr = p_calloc(1, 1); + ok(ptr != NULL, "got %p\n", ptr); + ok(HeapValidate(GetProcessHeap(), 0, ptr), "HeapValidate unexpectedly failed\n"); + p_free(ptr); +} + START_TEST(misc) { int arg_c; @@ -1752,4 +1768,5 @@ START_TEST(misc) test_rewind_i386_abi(); #endif test_gmtime64(); + test_HeapValidate(); }