From: Piotr Caban Subject: msvcrt: Don't use default process heap Message-Id: <535662D7.4000301@codeweavers.com> Date: Tue, 22 Apr 2014 14:38:47 +0200 This patch fixes following bugs: http://bugs.winehq.org/show_bug.cgi?id=34698 http://bugs.winehq.org/show_bug.cgi?id=36043 in both cases the applications are broken. Battlefield 1942 accesses already freed memory and expects that it was not overwritten. QQGame2011 uses LocalAlloc incorrectly and overwrites data on heap. I'm not sure how we should deal with these bugs. I've decided to write this patch because native msvcrt is not using default process heap, it also happens to hide/fix the bugs. --- dlls/msvcrt/heap.c | 40 ++++++++++++++++++++++++++-------------- dlls/msvcrt/main.c | 8 +++++++- dlls/msvcrt/msvcrt.h | 2 ++ 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/dlls/msvcrt/heap.c b/dlls/msvcrt/heap.c index 0b960f9..0cac3fe 100644 --- a/dlls/msvcrt/heap.c +++ b/dlls/msvcrt/heap.c @@ -38,6 +38,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); ((((DWORD_PTR)((char *)ptr + alignment + sizeof(void *) + offset)) & \ ~(alignment - 1)) - offset)) +static HANDLE heap; typedef int (CDECL *MSVCRT_new_handler_func)(MSVCRT_size_t size); @@ -59,7 +60,7 @@ void* CDECL MSVCRT_operator_new(MSVCRT_size_t size) do { - retval = HeapAlloc(GetProcessHeap(), 0, size); + retval = HeapAlloc(heap, 0, size); if(retval) { TRACE("(%ld) returning %p\n", size, retval); @@ -94,7 +95,7 @@ void* CDECL MSVCRT_operator_new_dbg(MSVCRT_size_t size, int type, const char *fi void CDECL MSVCRT_operator_delete(void *mem) { TRACE("(%p)\n", mem); - HeapFree(GetProcessHeap(), 0, mem); + HeapFree(heap, 0, mem); } @@ -166,7 +167,7 @@ int CDECL _callnewh(MSVCRT_size_t size) */ void* CDECL _expand(void* mem, MSVCRT_size_t size) { - return HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, mem, size); + return HeapReAlloc(heap, HEAP_REALLOC_IN_PLACE_ONLY, mem, size); } /********************************************************************* @@ -174,7 +175,7 @@ void* CDECL _expand(void* mem, MSVCRT_size_t size) */ int CDECL _heapchk(void) { - if (!HeapValidate( GetProcessHeap(), 0, NULL)) + if (!HeapValidate( heap, 0, NULL)) { msvcrt_set_errno(GetLastError()); return MSVCRT__HEAPBADNODE; @@ -187,7 +188,7 @@ int CDECL _heapchk(void) */ int CDECL _heapmin(void) { - if (!HeapCompact( GetProcessHeap(), 0 )) + if (!HeapCompact( heap, 0 )) { if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) msvcrt_set_errno(GetLastError()); @@ -209,7 +210,7 @@ int CDECL _heapwalk(struct MSVCRT__heapinfo* next) phe.wFlags = next->_useflag == MSVCRT__USEDENTRY ? PROCESS_HEAP_ENTRY_BUSY : 0; if (phe.lpData && phe.wFlags & PROCESS_HEAP_ENTRY_BUSY && - !HeapValidate( GetProcessHeap(), 0, phe.lpData )) + !HeapValidate( heap, 0, phe.lpData )) { UNLOCK_HEAP; msvcrt_set_errno(GetLastError()); @@ -218,7 +219,7 @@ int CDECL _heapwalk(struct MSVCRT__heapinfo* next) do { - if (!HeapWalk( GetProcessHeap(), &phe )) + if (!HeapWalk( heap, &phe )) { UNLOCK_HEAP; if (GetLastError() == ERROR_NO_MORE_ITEMS) @@ -267,11 +268,11 @@ int CDECL _heapadd(void* mem, MSVCRT_size_t size) } /********************************************************************* - * _heapadd (MSVCRT.@) + * _get_heap_handle (MSVCRT.@) */ MSVCRT_intptr_t CDECL _get_heap_handle(void) { - return (MSVCRT_intptr_t)GetProcessHeap(); + return (MSVCRT_intptr_t)heap; } /********************************************************************* @@ -279,7 +280,7 @@ MSVCRT_intptr_t CDECL _get_heap_handle(void) */ MSVCRT_size_t CDECL _msize(void* mem) { - MSVCRT_size_t size = HeapSize(GetProcessHeap(),0,mem); + MSVCRT_size_t size = HeapSize(heap,0,mem); if (size == ~(MSVCRT_size_t)0) { WARN(":Probably called with non wine-allocated memory, ret = -1\n"); @@ -309,7 +310,7 @@ size_t CDECL _aligned_msize(void *p, MSVCRT_size_t alignment, MSVCRT_size_t offs */ void* CDECL MSVCRT_calloc(MSVCRT_size_t size, MSVCRT_size_t count) { - return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count ); + return HeapAlloc( heap, HEAP_ZERO_MEMORY, size * count ); } /********************************************************************* @@ -317,7 +318,7 @@ void* CDECL MSVCRT_calloc(MSVCRT_size_t size, MSVCRT_size_t count) */ void CDECL MSVCRT_free(void* ptr) { - HeapFree(GetProcessHeap(),0,ptr); + HeapFree(heap,0,ptr); } /********************************************************************* @@ -325,7 +326,7 @@ void CDECL MSVCRT_free(void* ptr) */ void* CDECL MSVCRT_malloc(MSVCRT_size_t size) { - void *ret = HeapAlloc(GetProcessHeap(),0,size); + void *ret = HeapAlloc(heap,0,size); if (!ret) *MSVCRT__errno() = MSVCRT_ENOMEM; return ret; @@ -337,7 +338,7 @@ void* CDECL MSVCRT_malloc(MSVCRT_size_t size) void* CDECL MSVCRT_realloc(void* ptr, MSVCRT_size_t size) { if (!ptr) return MSVCRT_malloc(size); - if (size) return HeapReAlloc(GetProcessHeap(), 0, ptr, size); + if (size) return HeapReAlloc(heap, 0, ptr, size); MSVCRT_free(ptr); return NULL; } @@ -715,3 +716,14 @@ int CDECL MSVCRT_strncpy_s(char *dest, MSVCRT_size_t numberOfElements, dest[0] = '\0'; return MSVCRT_EINVAL; } + +BOOL msvcrt_init_heap(void) +{ + heap = HeapCreate(0, 0, 0); + return heap != NULL; +} + +void msvcrt_destroy_heap(void) +{ + HeapDestroy(heap); +} diff --git a/dlls/msvcrt/main.c b/dlls/msvcrt/main.c index 08c1f65..5a3bba7 100644 --- a/dlls/msvcrt/main.c +++ b/dlls/msvcrt/main.c @@ -98,12 +98,17 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { case DLL_PROCESS_ATTACH: msvcrt_init_exception(hinstDLL); - if (!msvcrt_init_tls()) + if(!msvcrt_init_heap()) + return FALSE; + if(!msvcrt_init_tls()) { + msvcrt_destroy_heap(); return FALSE; + } msvcrt_init_mt_locks(); if(!msvcrt_init_locale()) { msvcrt_free_mt_locks(); msvcrt_free_tls_mem(); + msvcrt_destroy_heap(); return FALSE; } msvcrt_init_math(); @@ -133,6 +138,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) if (!msvcrt_free_tls()) return FALSE; MSVCRT__free_locale(MSVCRT_locale); + msvcrt_destroy_heap(); TRACE("finished process free\n"); break; case DLL_THREAD_DETACH: diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 0989ba8..2a83b32 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -274,6 +274,8 @@ extern void msvcrt_free_args(void) DECLSPEC_HIDDEN; extern void msvcrt_init_signals(void) DECLSPEC_HIDDEN; extern void msvcrt_free_signals(void) DECLSPEC_HIDDEN; extern void msvcrt_free_popen_data(void) DECLSPEC_HIDDEN; +extern BOOL msvcrt_init_heap(void) DECLSPEC_HIDDEN; +extern void msvcrt_destroy_heap(void) DECLSPEC_HIDDEN; extern unsigned msvcrt_create_io_inherit_block(WORD*, BYTE**) DECLSPEC_HIDDEN;