From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/kernel32/tests/heap.c | 2 -- dlls/ntdll/heap.c | 29 +++++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 4221fd39c0f..339921b83c3 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -2320,7 +2320,6 @@ static void test_block_layout( HANDLE heap, DWORD global_flags, DWORD heap_flags tmp_flags = 0; ret = pRtlGetUserInfoHeap( heap, 0, ptr0, (void **)&tmp_ptr, &tmp_flags ); ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_ptr == (void *)0xdeadbeef, "got ptr %p\n", tmp_ptr ); todo_wine ok( tmp_flags == 0xa00 || broken(tmp_flags == 0xc00) /* w1064v1507 */, @@ -2335,7 +2334,6 @@ static void test_block_layout( HANDLE heap, DWORD global_flags, DWORD heap_flags tmp_flags = 0; ret = pRtlGetUserInfoHeap( heap, 0, ptr0, (void **)&tmp_ptr, &tmp_flags ); ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_ptr == (void *)0xdeadbee0, "got ptr %p\n", tmp_ptr ); todo_wine ok( tmp_flags == 0xa00 || broken(tmp_flags == 0xc00) /* w1064v1507 */, diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 64d4f6644af..8ebd561dd1c 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1996,12 +1996,33 @@ NTSTATUS WINAPI RtlSetHeapInformation( HANDLE heap, HEAP_INFORMATION_CLASS info_ /*********************************************************************** * RtlGetUserInfoHeap (NTDLL.@) */ -BOOLEAN WINAPI RtlGetUserInfoHeap( HANDLE heap, ULONG flags, void *ptr, void **user_value, ULONG *user_flags ) +BOOLEAN WINAPI RtlGetUserInfoHeap( HANDLE handle, ULONG flags, void *ptr, void **user_value, ULONG *user_flags ) { - FIXME( "heap %p, flags %#x, ptr %p, user_value %p, user_flags %p semi-stub!\n", - heap, flags, ptr, user_value, user_flags ); - *user_value = NULL; + ARENA_LARGE *large = (ARENA_LARGE *)ptr - 1; + struct block *block; + SUBHEAP *subheap; + HEAP *heap; + char *tmp; + + TRACE( "handle %p, flags %#x, ptr %p, user_value %p, user_flags %p semi-stub!\n", + handle, flags, ptr, user_value, user_flags ); + + *user_value = 0; *user_flags = 0; + + if (!(heap = HEAP_GetPtr( handle ))) return TRUE; + + heap_lock( heap, flags ); + if ((block = unsafe_block_from_ptr( heap, ptr, &subheap )) && !subheap) + *user_value = large->user_value; + else if (block) + { + tmp = (char *)block + block_get_size( block ) - block->tail_size + sizeof(void *); + if ((heap_get_flags( heap, flags ) & HEAP_TAIL_CHECKING_ENABLED) || RUNNING_ON_VALGRIND) tmp += ALIGNMENT; + *user_value = *(void **)tmp; + } + heap_unlock( heap, flags ); + return TRUE; }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/kernel32/heap.c | 10 ++++++++-- dlls/kernel32/tests/heap.c | 8 ++++++++ 2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c index df094c94257..c1074e70e2e 100644 --- a/dlls/kernel32/heap.c +++ b/dlls/kernel32/heap.c @@ -47,6 +47,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(globalmem);
static HANDLE systemHeap; /* globally shared heap */
+BOOLEAN WINAPI RtlGetUserInfoHeap( HANDLE handle, ULONG flags, void *ptr, void **user_value, ULONG *user_flags );
/*********************************************************************** * HEAP_CreateSystemHeap @@ -171,7 +172,6 @@ C_ASSERT(sizeof(struct mem_entry) == 2 * sizeof(void *));
struct kernelbase_global_data *kernelbase_global_data;
-#define POINTER_TO_HANDLE( p ) (*(((const HGLOBAL *)( p )) - 2)) /* align the storage needed for the HLOCAL on an 8-byte boundary thus * LocalAlloc/LocalReAlloc'ing with LMEM_MOVEABLE of memory with * size = 8*k, where k=1,2,3,... allocs exactly the given size. @@ -255,6 +255,7 @@ HGLOBAL WINAPI GlobalHandle( const void *ptr ) struct mem_entry *mem; HGLOBAL handle; LPCVOID test; + ULONG flags;
TRACE_(globalmem)( "ptr %p\n", ptr );
@@ -279,7 +280,12 @@ HGLOBAL WINAPI GlobalHandle( const void *ptr ) handle = (HGLOBAL)ptr; /* valid fixed block */ break; } - handle = POINTER_TO_HANDLE( ptr ); + if (!RtlGetUserInfoHeap( GetProcessHeap(), HEAP_NO_SERIALIZE, (char *)ptr - HLOCAL_STORAGE, &handle, &flags )) + { + SetLastError( ERROR_INVALID_HANDLE ); + handle = 0; + } + break; } else handle = (HGLOBAL)ptr;
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 339921b83c3..ec2fe7479ca 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -1494,6 +1494,8 @@ static void test_GlobalAlloc(void) ptr = GlobalLock( mem ); ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); ok( ptr != mem, "got unexpected ptr %p\n", ptr ); + tmp_mem = GlobalHandle( ptr ); + ok( tmp_mem == mem, "GlobalHandle returned unexpected handle\n" ); flags = GlobalFlags( mem ); ok( flags == 1, "GlobalFlags returned %#x, error %lu\n", flags, GetLastError() ); tmp_ptr = GlobalLock( mem ); @@ -1698,6 +1700,8 @@ static void test_GlobalAlloc(void) ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); ret = GlobalUnlock( mem ); ok( ret, "GlobalUnlock failed, error %lu\n", GetLastError() ); + tmp_mem = GlobalHandle( mem ); + ok( tmp_mem == mem, "GlobalHandle returned unexpected handle\n" ); mem = GlobalFree( mem ); ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() );
@@ -1867,6 +1871,8 @@ static void test_LocalAlloc(void) ptr = LocalLock( mem ); ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); ok( ptr != mem, "got unexpected ptr %p\n", ptr ); + tmp_mem = LocalHandle( ptr ); + ok( tmp_mem == mem, "LocalHandle returned unexpected handle\n" ); flags = LocalFlags( mem ); ok( flags == 1, "LocalFlags returned %#x, error %lu\n", flags, GetLastError() ); tmp_ptr = LocalLock( mem ); @@ -2030,6 +2036,8 @@ static void test_LocalAlloc(void) ret = LocalUnlock( mem ); ok( !ret, "LocalUnlock succeeded\n" ); ok( GetLastError() == ERROR_NOT_LOCKED, "got error %lu\n", GetLastError() ); + tmp_mem = LocalHandle( mem ); + ok( tmp_mem == mem, "LocalHandle returned unexpected handle\n" ); mem = LocalFree( mem ); ok( !mem, "LocalFree failed, error %lu\n", GetLastError() );
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/kernel32/heap.c | 30 +++--------------------------- dlls/kernel32/tests/heap.c | 6 ------ dlls/kernelbase/memory.c | 27 +++++++++------------------ 3 files changed, 12 insertions(+), 51 deletions(-)
diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c index c1074e70e2e..e414ad03493 100644 --- a/dlls/kernel32/heap.c +++ b/dlls/kernel32/heap.c @@ -172,13 +172,6 @@ C_ASSERT(sizeof(struct mem_entry) == 2 * sizeof(void *));
struct kernelbase_global_data *kernelbase_global_data;
-/* align the storage needed for the HLOCAL on an 8-byte boundary thus - * LocalAlloc/LocalReAlloc'ing with LMEM_MOVEABLE of memory with - * size = 8*k, where k=1,2,3,... allocs exactly the given size. - * The Minolta DiMAGE Image Viewer heavily relies on this, corrupting - * the output jpeg's > 1 MB if not */ -#define HLOCAL_STORAGE (sizeof(HLOCAL) * 2) - static inline struct mem_entry *unsafe_mem_from_HLOCAL( HLOCAL handle ) { struct mem_entry *mem = CONTAINING_RECORD( handle, struct mem_entry, ptr ); @@ -254,7 +247,6 @@ HGLOBAL WINAPI GlobalHandle( const void *ptr ) { struct mem_entry *mem; HGLOBAL handle; - LPCVOID test; ULONG flags;
TRACE_(globalmem)( "ptr %p\n", ptr ); @@ -275,12 +267,7 @@ HGLOBAL WINAPI GlobalHandle( const void *ptr ) /* will fail. */ if ((ptr = unsafe_ptr_from_HLOCAL( (HLOCAL)ptr ))) { - if (HeapValidate( GetProcessHeap(), HEAP_NO_SERIALIZE, ptr )) - { - handle = (HGLOBAL)ptr; /* valid fixed block */ - break; - } - if (!RtlGetUserInfoHeap( GetProcessHeap(), HEAP_NO_SERIALIZE, (char *)ptr - HLOCAL_STORAGE, &handle, &flags )) + if (!RtlGetUserInfoHeap( GetProcessHeap(), HEAP_NO_SERIALIZE, (void *)ptr, &handle, &flags )) { SetLastError( ERROR_INVALID_HANDLE ); handle = 0; @@ -292,8 +279,7 @@ HGLOBAL WINAPI GlobalHandle( const void *ptr ) /* Now test handle either passed in or retrieved from pointer */ if ((mem = unsafe_mem_from_HLOCAL( handle ))) { - test = mem->ptr; - if (HeapValidate( GetProcessHeap(), HEAP_NO_SERIALIZE, (const char *)test - HLOCAL_STORAGE )) /* obj(-handle) valid arena? */ + if (HeapValidate( GetProcessHeap(), HEAP_NO_SERIALIZE, mem->ptr )) /* obj(-handle) valid arena? */ break; /* valid moveable block */ } handle = 0; @@ -356,14 +342,7 @@ SIZE_T WINAPI GlobalSize( HGLOBAL handle ) }
if ((ptr = unsafe_ptr_from_HLOCAL( handle ))) - { retval = HeapSize( GetProcessHeap(), 0, ptr ); - if (retval == ~(SIZE_T)0) /* It might be a GMEM_MOVEABLE data pointer */ - { - retval = HeapSize( GetProcessHeap(), 0, (char *)ptr - HLOCAL_STORAGE ); - if (retval != ~(SIZE_T)0) retval -= HLOCAL_STORAGE; - } - } else { RtlLockHeap( GetProcessHeap() ); @@ -372,10 +351,7 @@ SIZE_T WINAPI GlobalSize( HGLOBAL handle ) if (!mem->ptr) /* handle case of GlobalAlloc( ??,0) */ retval = 0; else - { - retval = HeapSize( GetProcessHeap(), 0, (char *)mem->ptr - HLOCAL_STORAGE ); - if (retval != ~(SIZE_T)0) retval -= HLOCAL_STORAGE; - } + retval = HeapSize( GetProcessHeap(), 0, mem->ptr ); } else { diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index ec2fe7479ca..4496df35579 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -1400,29 +1400,23 @@ static void test_GlobalAlloc(void) ret = HeapValidate( GetProcessHeap(), 0, entry ); ok( !ret, "HeapValidate succeeded\n" ); ret = HeapValidate( GetProcessHeap(), 0, entry->ptr ); - todo_wine ok( ret, "HeapValidate failed, error %lu\n", GetLastError() ); size = HeapSize( GetProcessHeap(), 0, entry->ptr ); - todo_wine ok( size == alloc_size, "HeapSize returned %Iu\n", size );
tmp_mem = invalid_mem; tmp_flags = 0xdeadbeef; ret = pRtlGetUserInfoHeap( GetProcessHeap(), 0, entry->ptr, (void **)&tmp_mem, &tmp_flags ); ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem == mem, "got user ptr %p\n", tmp_mem ); todo_wine ok( tmp_flags == 0x200, "got user flags %#lx\n", tmp_flags );
ret = pRtlSetUserValueHeap( GetProcessHeap(), 0, entry->ptr, invalid_mem ); - todo_wine ok( ret, "RtlSetUserValueHeap failed, error %lu\n", GetLastError() ); tmp_mem = GlobalHandle( entry->ptr ); - todo_wine ok( tmp_mem == invalid_mem, "GlobalHandle returned unexpected handle\n" ); ret = pRtlSetUserValueHeap( GetProcessHeap(), 0, entry->ptr, mem ); - todo_wine ok( ret, "RtlSetUserValueHeap failed, error %lu\n", GetLastError() );
ptr = GlobalLock( mem ); diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 409b35089e3..16a068f5b5f 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -752,13 +752,6 @@ C_ASSERT(sizeof(struct mem_entry) == 2 * sizeof(void *)); static struct mem_entry *next_free_mem; static struct kernelbase_global_data global_data = {0};
-/* align the storage needed for the HLOCAL on an 8-byte boundary thus - * LocalAlloc/LocalReAlloc'ing with LMEM_MOVEABLE of memory with - * size = 8*k, where k=1,2,3,... allocs exactly the given size. - * The Minolta DiMAGE Image Viewer heavily relies on this, corrupting - * the output jpeg's > 1 MB if not */ -#define HLOCAL_STORAGE (sizeof(HLOCAL) * 2) - static inline struct mem_entry *unsafe_mem_from_HLOCAL( HLOCAL handle ) { struct mem_entry *mem = CONTAINING_RECORD( *(volatile HANDLE *)&handle, struct mem_entry, ptr ); @@ -872,10 +865,9 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size ) if (!size) mem->flags |= MEM_FLAG_DISCARDED; else { - if (!(ptr = HeapAlloc( heap, heap_flags, size + HLOCAL_STORAGE ))) goto failed; + if (!(ptr = HeapAlloc( heap, heap_flags, size ))) goto failed; RtlSetUserValueHeap( heap, heap_flags, ptr, handle ); - *(HLOCAL *)ptr = handle; - mem->ptr = (char *)ptr + HLOCAL_STORAGE; + mem->ptr = ptr; }
TRACE_(globalmem)( "return handle %p, ptr %p\n", handle, mem->ptr ); @@ -907,7 +899,7 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalFree( HLOCAL handle ) } else if ((mem = unsafe_mem_from_HLOCAL( handle ))) { - if (!mem->ptr || HeapFree( heap, HEAP_NO_SERIALIZE, (char *)mem->ptr - HLOCAL_STORAGE )) ret = 0; + if (HeapFree( heap, HEAP_NO_SERIALIZE, mem->ptr )) ret = 0; mem->ptr = NULL; mem->next_free = next_free_mem; next_free_mem = mem; @@ -1026,25 +1018,24 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalReAlloc( HLOCAL handle, SIZE_T size, UINT f /* reallocate a moveable block */ if (size != 0) { - if (size <= INT_MAX - HLOCAL_STORAGE) + if (size <= INT_MAX) { if (mem->ptr) { - if ((ptr = HeapReAlloc( GetProcessHeap(), heap_flags, (char *)mem->ptr - HLOCAL_STORAGE, - size + HLOCAL_STORAGE ))) + if ((ptr = HeapReAlloc( GetProcessHeap(), heap_flags, mem->ptr, size ))) { RtlSetUserValueHeap( GetProcessHeap(), heap_flags, ptr, handle ); - mem->ptr = (char *)ptr + HLOCAL_STORAGE; + mem->ptr = ptr; ret = handle; } } else { - if ((ptr = HeapAlloc( GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE ))) + if ((ptr = HeapAlloc( GetProcessHeap(), heap_flags, size ))) { RtlSetUserValueHeap( GetProcessHeap(), heap_flags, ptr, handle ); *(HLOCAL *)ptr = handle; - mem->ptr = (char *)ptr + HLOCAL_STORAGE; + mem->ptr = ptr; ret = handle; } } @@ -1057,7 +1048,7 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalReAlloc( HLOCAL handle, SIZE_T size, UINT f { if (mem->ptr) { - HeapFree( GetProcessHeap(), 0, (char *)mem->ptr - HLOCAL_STORAGE ); + HeapFree( GetProcessHeap(), 0, mem->ptr ); mem->ptr = NULL; } ret = handle;
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/kernel32/heap.c | 88 ++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 61 deletions(-)
diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c index e414ad03493..2dac1555d8e 100644 --- a/dlls/kernel32/heap.c +++ b/dlls/kernel32/heap.c @@ -313,56 +313,10 @@ HGLOBAL WINAPI GlobalReAlloc( HGLOBAL handle, SIZE_T size, UINT flags )
/*********************************************************************** * GlobalSize (KERNEL32.@) - * - * Get the size of a global memory object. - * - * PARAMS - * handle [I] Handle of the global memory object - * - * RETURNS - * Failure: 0 - * Success: Size in Bytes of the global memory object - * - * NOTES - * When the handle is invalid, last error is set to ERROR_INVALID_HANDLE - * */ SIZE_T WINAPI GlobalSize( HGLOBAL handle ) { - struct mem_entry *mem; - SIZE_T retval; - void *ptr; - - TRACE_(globalmem)( "handle %p\n", handle ); - - if (!((ULONG_PTR)handle >> 16)) - { - SetLastError( ERROR_INVALID_HANDLE ); - return 0; - } - - if ((ptr = unsafe_ptr_from_HLOCAL( handle ))) - retval = HeapSize( GetProcessHeap(), 0, ptr ); - else - { - RtlLockHeap( GetProcessHeap() ); - if ((mem = unsafe_mem_from_HLOCAL( handle ))) - { - if (!mem->ptr) /* handle case of GlobalAlloc( ??,0) */ - retval = 0; - else - retval = HeapSize( GetProcessHeap(), 0, mem->ptr ); - } - else - { - WARN_(globalmem)( "invalid handle %p\n", handle ); - SetLastError( ERROR_INVALID_HANDLE ); - retval = 0; - } - RtlUnlockHeap( GetProcessHeap() ); - } - if (retval == ~(SIZE_T)0) retval = 0; - return retval; + return LocalSize( handle ); }
@@ -513,21 +467,33 @@ SIZE_T WINAPI LocalShrink( HGLOBAL handle, UINT newsize )
/*********************************************************************** * LocalSize (KERNEL32.@) - * - * Get the size of a local memory object. - * - * RETURNS - * Size: Success - * 0: Failure - * - * NOTES - * Windows memory management does not provide a separate local heap - * and global heap. */ -SIZE_T WINAPI LocalSize( - HLOCAL handle /* [in] Handle of memory object */ -) { - return GlobalSize( handle ); +SIZE_T WINAPI LocalSize( HLOCAL handle ) +{ + HANDLE heap = GetProcessHeap(); + struct mem_entry *mem; + SIZE_T ret = 0; + void *ptr; + + TRACE_(globalmem)( "handle %p\n", handle ); + + RtlLockHeap( heap ); + if ((ptr = unsafe_ptr_from_HLOCAL( handle ))) + ret = HeapSize( heap, HEAP_NO_SERIALIZE, ptr ); + else if ((mem = unsafe_mem_from_HLOCAL( handle ))) + { + if (!mem->ptr) ret = 0; + else ret = HeapSize( heap, HEAP_NO_SERIALIZE, mem->ptr ); + } + else + { + WARN_(globalmem)( "invalid handle %p\n", handle ); + SetLastError( ERROR_INVALID_HANDLE ); + } + RtlUnlockHeap( heap ); + + if (ret == ~(SIZE_T)0) return 0; + return ret; }
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/kernel32/heap.c | 91 ++++++++++---------------------------------- 1 file changed, 21 insertions(+), 70 deletions(-)
diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c index 2dac1555d8e..3ba9e139171 100644 --- a/dlls/kernel32/heap.c +++ b/dlls/kernel32/heap.c @@ -236,64 +236,10 @@ BOOL WINAPI GlobalUnlock( HGLOBAL handle )
/*********************************************************************** * GlobalHandle (KERNEL32.@) - * - * Get the handle associated with the pointer to a global memory block. - * - * RETURNS - * Handle: Success - * NULL: Failure */ HGLOBAL WINAPI GlobalHandle( const void *ptr ) { - struct mem_entry *mem; - HGLOBAL handle; - ULONG flags; - - TRACE_(globalmem)( "ptr %p\n", ptr ); - - if (!ptr) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return 0; - } - - RtlLockHeap( GetProcessHeap() ); - __TRY - { - handle = 0; - - /* note that if ptr is a pointer to a block allocated by */ - /* GlobalAlloc with GMEM_MOVEABLE then magic test in HeapValidate */ - /* will fail. */ - if ((ptr = unsafe_ptr_from_HLOCAL( (HLOCAL)ptr ))) - { - if (!RtlGetUserInfoHeap( GetProcessHeap(), HEAP_NO_SERIALIZE, (void *)ptr, &handle, &flags )) - { - SetLastError( ERROR_INVALID_HANDLE ); - handle = 0; - } - break; - } - else handle = (HGLOBAL)ptr; - - /* Now test handle either passed in or retrieved from pointer */ - if ((mem = unsafe_mem_from_HLOCAL( handle ))) - { - if (HeapValidate( GetProcessHeap(), HEAP_NO_SERIALIZE, mem->ptr )) /* obj(-handle) valid arena? */ - break; /* valid moveable block */ - } - handle = 0; - SetLastError( ERROR_INVALID_HANDLE ); - } - __EXCEPT_PAGE_FAULT - { - SetLastError( ERROR_INVALID_HANDLE ); - handle = 0; - } - __ENDTRY - RtlUnlockHeap( GetProcessHeap() ); - - return handle; + return LocalHandle( ptr ); }
/*********************************************************************** @@ -438,23 +384,28 @@ UINT WINAPI LocalFlags( HLOCAL handle )
/*********************************************************************** * LocalHandle (KERNEL32.@) - * - * Get the handle associated with the pointer to a local memory block. - * - * RETURNS - * Handle: Success - * NULL: Failure - * - * NOTES - * Windows memory management does not provide a separate local heap - * and global heap. */ -HLOCAL WINAPI LocalHandle( - LPCVOID ptr /* [in] Address of local memory block */ -) { - return GlobalHandle( ptr ); -} +HLOCAL WINAPI LocalHandle( const void *ptr ) +{ + HLOCAL handle; + ULONG flags; + + TRACE_(globalmem)( "ptr %p\n", ptr );
+ if (!ptr) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + + if (!RtlGetUserInfoHeap( GetProcessHeap(), 0, (void *)ptr, &handle, &flags )) + { + SetLastError( ERROR_INVALID_HANDLE ); + return 0; + } + + return handle; +}
/*********************************************************************** * LocalShrink (KERNEL32.@)
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/kernel32/heap.c | 22 +++++++- dlls/kernel32/tests/heap.c | 15 ------ dlls/kernelbase/memory.c | 108 +++++++++++++------------------------ 3 files changed, 56 insertions(+), 89 deletions(-)
diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c index 3ba9e139171..a2910688e44 100644 --- a/dlls/kernel32/heap.c +++ b/dlls/kernel32/heap.c @@ -48,6 +48,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(globalmem); static HANDLE systemHeap; /* globally shared heap */
BOOLEAN WINAPI RtlGetUserInfoHeap( HANDLE handle, ULONG flags, void *ptr, void **user_value, ULONG *user_flags ); +BOOLEAN WINAPI RtlSetUserValueHeap( HANDLE handle, ULONG flags, void *ptr, void *user_value );
/*********************************************************************** * HEAP_CreateSystemHeap @@ -174,7 +175,7 @@ struct kernelbase_global_data *kernelbase_global_data;
static inline struct mem_entry *unsafe_mem_from_HLOCAL( HLOCAL handle ) { - struct mem_entry *mem = CONTAINING_RECORD( handle, struct mem_entry, ptr ); + struct mem_entry *mem = CONTAINING_RECORD( *(volatile HANDLE *)&handle, struct mem_entry, ptr ); struct kernelbase_global_data *data = kernelbase_global_data; if (((UINT_PTR)handle & ((sizeof(void *) << 1) - 1)) != sizeof(void *)) return NULL; if (mem < data->mem_entries || mem >= data->mem_entries_end) return NULL; @@ -253,7 +254,24 @@ HGLOBAL WINAPI GlobalHandle( const void *ptr ) */ HGLOBAL WINAPI GlobalReAlloc( HGLOBAL handle, SIZE_T size, UINT flags ) { - return LocalReAlloc( handle, size, flags ); + struct mem_entry *mem; + void *ptr; + + if ((mem = unsafe_mem_from_HLOCAL( handle )) && mem->lock) return 0; + if (!(handle = LocalReAlloc( handle, size, flags ))) return 0; + + /* GlobalReAlloc allows changing GMEM_FIXED to GMEM_MOVEABLE with GMEM_MODIFY */ + if ((flags & (GMEM_MOVEABLE | GMEM_MODIFY)) == (GMEM_MOVEABLE | GMEM_MODIFY) && + (ptr = unsafe_ptr_from_HLOCAL( handle ))) + { + if (!(handle = LocalAlloc( flags, 0 ))) return 0; + RtlSetUserValueHeap( GetProcessHeap(), 0, ptr, handle ); + mem = unsafe_mem_from_HLOCAL( handle ); + mem->flags &= ~MEM_FLAG_DISCARDED; + mem->ptr = ptr; + } + + return handle; }
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 4496df35579..90c311b5683 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -1629,9 +1629,7 @@ static void test_GlobalAlloc(void) mem = GlobalAlloc( GMEM_FIXED, 10 ); ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); tmp_mem = GlobalReAlloc( mem, 9, GMEM_MODIFY ); - todo_wine ok( !!tmp_mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); size = GlobalSize( mem ); ok( size == 10, "GlobalSize returned %Iu\n", size ); @@ -1645,9 +1643,7 @@ static void test_GlobalAlloc(void) "got error %lu\n", GetLastError() ); if (tmp_mem) mem = tmp_mem; tmp_mem = GlobalReAlloc( mem, 1024 * 1024, GMEM_MODIFY ); - todo_wine ok( !!tmp_mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); size = GlobalSize( mem ); ok( size == 10, "GlobalSize returned %Iu\n", size ); @@ -1986,9 +1982,7 @@ static void test_LocalAlloc(void) mem = LocalAlloc( LMEM_FIXED, 10 ); ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); tmp_mem = LocalReAlloc( mem, 9, LMEM_MODIFY ); - todo_wine ok( !!tmp_mem, "LocalAlloc failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); size = LocalSize( mem ); ok( size == 10, "LocalSize returned %Iu\n", size ); @@ -2002,9 +1996,7 @@ static void test_LocalAlloc(void) "got error %lu\n", GetLastError() ); if (tmp_mem) mem = tmp_mem; tmp_mem = LocalReAlloc( mem, 1024 * 1024, LMEM_MODIFY ); - todo_wine ok( !!tmp_mem, "LocalAlloc failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); size = LocalSize( mem ); ok( size == 10, "LocalSize returned %Iu\n", size ); @@ -2072,18 +2064,15 @@ static void test_LocalAlloc(void) /* Check that we cannot change LMEM_FIXED to LMEM_MOVEABLE */ mem = LocalReAlloc( mem, 0, LMEM_MODIFY | LMEM_MOVEABLE ); ok( !!mem, "LocalReAlloc failed, error %lu\n", GetLastError() ); - todo_wine ok( mem == ptr, "LocalReAlloc returned unexpected handle\n" ); size = LocalSize( mem ); ok( size == buffer_size, "LocalSize returned %Iu, error %lu\n", size, GetLastError() );
ptr = LocalLock( mem ); ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); - todo_wine ok( ptr == mem, "got unexpected ptr %p\n", ptr ); ret = LocalUnlock( mem ); ok( !ret, "LocalUnlock succeeded, error %lu\n", GetLastError() ); - todo_wine ok( GetLastError() == ERROR_NOT_LOCKED, "got error %lu\n", GetLastError() );
tmp_mem = LocalReAlloc( mem, 2 * buffer_size, LMEM_MOVEABLE | LMEM_ZEROINIT ); @@ -2096,7 +2085,6 @@ static void test_LocalAlloc(void) ok( size >= 2 * buffer_size, "LocalSize returned %Iu, error %lu\n", size, GetLastError() ); ptr = LocalLock( mem ); ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); - todo_wine ok( ptr == mem, "got unexpected ptr %p\n", ptr ); ok( !memcmp( ptr, zero_buffer, buffer_size ), "LocalReAlloc didn't clear memory\n" ); ok( !memcmp( ptr + buffer_size, zero_buffer, buffer_size ), @@ -2105,13 +2093,10 @@ static void test_LocalAlloc(void) tmp_mem = LocalHandle( ptr ); ok( tmp_mem == mem, "LocalHandle returned unexpected handle\n" ); tmp_mem = LocalDiscard( mem ); - todo_wine ok( !!tmp_mem, "LocalDiscard failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem == mem, "LocalDiscard returned unexpected handle\n" ); ret = LocalUnlock( mem ); ok( !ret, "LocalUnlock succeeded, error %lu\n", GetLastError() ); - todo_wine ok( GetLastError() == ERROR_NOT_LOCKED, "got error %lu\n", GetLastError() );
tmp_mem = LocalDiscard( mem ); diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 16a068f5b5f..e24a6f9aad0 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -964,7 +964,8 @@ LPVOID WINAPI DECLSPEC_HOTPATCH LocalLock( HLOCAL handle ) */ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalReAlloc( HLOCAL handle, SIZE_T size, UINT flags ) { - DWORD heap_flags = HEAP_ADD_USER_INFO; + DWORD heap_flags = HEAP_ADD_USER_INFO | HEAP_NO_SERIALIZE; + HANDLE heap = GetProcessHeap(); struct mem_entry *mem; HLOCAL ret = 0; void *ptr; @@ -973,92 +974,55 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalReAlloc( HLOCAL handle, SIZE_T size, UINT f
if (flags & LMEM_ZEROINIT) heap_flags |= HEAP_ZERO_MEMORY;
- RtlLockHeap( GetProcessHeap() ); - if (flags & LMEM_MODIFY) /* modify flags */ + RtlLockHeap( heap ); + if ((ptr = unsafe_ptr_from_HLOCAL( handle ))) { - if (unsafe_ptr_from_HLOCAL( handle ) && (flags & LMEM_MOVEABLE)) - { - /* make a fixed block moveable - * actually only NT is able to do this. But it's soo simple - */ - if (handle == 0) - { - WARN_(globalmem)( "null handle\n" ); - SetLastError( ERROR_NOACCESS ); - } - else - { - size = RtlSizeHeap( GetProcessHeap(), 0, handle ); - ret = LocalAlloc( flags, size ); - ptr = LocalLock( ret ); - memcpy( ptr, handle, size ); - LocalUnlock( ret ); - LocalFree( handle ); - } - } - else if ((mem = unsafe_mem_from_HLOCAL( handle )) && (flags & LMEM_DISCARDABLE)) + if (flags & LMEM_MODIFY) ret = handle; + else { - /* change the flags to make our block "discardable" */ - mem->flags |= LMEM_DISCARDABLE >> 8; - ret = handle; + if (!(flags & LMEM_MOVEABLE)) heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY; + ret = HeapReAlloc( heap, heap_flags, ptr, size ); + if (ret) RtlSetUserValueHeap( heap, heap_flags, ret, ret ); + else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); } - else SetLastError( ERROR_INVALID_PARAMETER ); } - else + else if ((mem = unsafe_mem_from_HLOCAL( handle ))) { - if ((ptr = unsafe_ptr_from_HLOCAL( handle ))) - { - /* reallocate fixed memory */ - if (!(flags & LMEM_MOVEABLE)) heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY; - ret = HeapReAlloc( GetProcessHeap(), heap_flags, ptr, size ); - if (ret) RtlSetUserValueHeap( GetProcessHeap(), heap_flags, ret, ret ); - } - else if ((mem = unsafe_mem_from_HLOCAL( handle ))) + if (!(flags & LMEM_MODIFY)) { - /* reallocate a moveable block */ - if (size != 0) + if (size) { - if (size <= INT_MAX) + if (!mem->ptr) ptr = HeapAlloc( heap, heap_flags, size ); + else ptr = HeapReAlloc( heap, heap_flags, mem->ptr, size ); + + if (!ptr) SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + else { - if (mem->ptr) - { - if ((ptr = HeapReAlloc( GetProcessHeap(), heap_flags, mem->ptr, size ))) - { - RtlSetUserValueHeap( GetProcessHeap(), heap_flags, ptr, handle ); - mem->ptr = ptr; - ret = handle; - } - } - else - { - if ((ptr = HeapAlloc( GetProcessHeap(), heap_flags, size ))) - { - RtlSetUserValueHeap( GetProcessHeap(), heap_flags, ptr, handle ); - *(HLOCAL *)ptr = handle; - mem->ptr = ptr; - ret = handle; - } - } + RtlSetUserValueHeap( heap, heap_flags, ptr, handle ); + mem->flags &= ~MEM_FLAG_DISCARDED; + mem->ptr = ptr; + ret = handle; } - else SetLastError( ERROR_OUTOFMEMORY ); } else { - if (mem->lock == 0) - { - if (mem->ptr) - { - HeapFree( GetProcessHeap(), 0, mem->ptr ); - mem->ptr = NULL; - } - ret = handle; - } - else WARN_(globalmem)( "not freeing memory associated with locked handle\n" ); + HeapFree( heap, heap_flags, mem->ptr ); + mem->flags |= MEM_FLAG_DISCARDED; + mem->lock = 0; + mem->ptr = NULL; + ret = handle; } } - else SetLastError( ERROR_INVALID_HANDLE ); + else if (flags & LMEM_DISCARDABLE) + { + mem->flags |= MEM_FLAG_DISCARDABLE; + ret = handle; + } + else SetLastError( ERROR_INVALID_PARAMETER ); } - RtlUnlockHeap( GetProcessHeap() ); + else SetLastError( ERROR_INVALID_HANDLE ); + RtlUnlockHeap( heap ); + return ret; }