Commit 3c9d2cba authored by Rémi Bernon's avatar Rémi Bernon Committed by Alexandre Julliard

kernelbase: Allocate HLOCAL / HGLOBAL from a static handle table.

Sharing the table pointers through KernelBaseGetGlobalData to check for handle validity in kernel32, and as native does it. Signed-off-by: 's avatarRémi Bernon <rbernon@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 981283a5
...@@ -151,10 +151,17 @@ BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ ) ...@@ -151,10 +151,17 @@ BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
struct mem_entry struct mem_entry
{ {
WORD magic; union
void *ptr; {
BYTE flags; struct
BYTE lock; {
WORD magic;
void *ptr;
BYTE flags;
BYTE lock;
};
void *next_free;
};
}; };
#include "poppack.h" #include "poppack.h"
...@@ -173,7 +180,9 @@ struct kernelbase_global_data *kernelbase_global_data; ...@@ -173,7 +180,9 @@ struct kernelbase_global_data *kernelbase_global_data;
static inline struct mem_entry *unsafe_mem_from_HLOCAL( HLOCAL handle ) 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( handle, struct mem_entry, ptr );
struct kernelbase_global_data *data = kernelbase_global_data;
if (!((ULONG_PTR)handle & 2)) return NULL; if (!((ULONG_PTR)handle & 2)) return NULL;
if (mem < data->mem_entries || mem >= data->mem_entries_end) return NULL;
if (mem->magic != MAGIC_LOCAL_USED) return NULL; if (mem->magic != MAGIC_LOCAL_USED) return NULL;
return mem; return mem;
} }
...@@ -276,8 +285,7 @@ HGLOBAL WINAPI GlobalHandle( const void *ptr ) ...@@ -276,8 +285,7 @@ HGLOBAL WINAPI GlobalHandle( const void *ptr )
if ((mem = unsafe_mem_from_HLOCAL( handle ))) if ((mem = unsafe_mem_from_HLOCAL( handle )))
{ {
test = mem->ptr; test = mem->ptr;
if (HeapValidate( GetProcessHeap(), HEAP_NO_SERIALIZE, (const char *)test - HLOCAL_STORAGE ) && /* obj(-handle) valid arena? */ if (HeapValidate( GetProcessHeap(), HEAP_NO_SERIALIZE, (const char *)test - HLOCAL_STORAGE )) /* obj(-handle) valid arena? */
HeapValidate( GetProcessHeap(), HEAP_NO_SERIALIZE, mem )) /* intern valid arena? */
break; /* valid moveable block */ break; /* valid moveable block */
} }
handle = 0; handle = 0;
......
...@@ -290,15 +290,11 @@ static void test_GlobalAlloc(void) ...@@ -290,15 +290,11 @@ static void test_GlobalAlloc(void)
SetLastError( 0xdeadbeef ); SetLastError( 0xdeadbeef );
mem = GlobalAlloc( GMEM_MOVEABLE | GMEM_DISCARDABLE, 0 ); mem = GlobalAlloc( GMEM_MOVEABLE | GMEM_DISCARDABLE, 0 );
todo_wine
ok( !mem, "GlobalAlloc succeeded\n" ); ok( !mem, "GlobalAlloc succeeded\n" );
todo_wine
ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() );
SetLastError( 0xdeadbeef ); SetLastError( 0xdeadbeef );
mem = LocalAlloc( LMEM_MOVEABLE | LMEM_DISCARDABLE, 0 ); mem = LocalAlloc( LMEM_MOVEABLE | LMEM_DISCARDABLE, 0 );
todo_wine
ok( !mem, "LocalAlloc succeeded\n" ); ok( !mem, "LocalAlloc succeeded\n" );
todo_wine
ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() );
mem = GlobalAlloc( GMEM_DISCARDABLE, 0 ); mem = GlobalAlloc( GMEM_DISCARDABLE, 0 );
...@@ -417,7 +413,6 @@ static void test_GlobalAlloc(void) ...@@ -417,7 +413,6 @@ static void test_GlobalAlloc(void)
tmp_mem = GlobalFree( mem ); tmp_mem = GlobalFree( mem );
ok( !tmp_mem, "GlobalFree failed, error %lu\n", GetLastError() ); ok( !tmp_mem, "GlobalFree failed, error %lu\n", GetLastError() );
ok( !!entry->flags, "got unexpected flags %#Ix\n", entry->flags ); ok( !!entry->flags, "got unexpected flags %#Ix\n", entry->flags );
todo_wine_if(sizeof(void *) == 4)
ok( !((UINT_PTR)entry->flags & sizeof(void *)), "got unexpected ptr align\n" ); ok( !((UINT_PTR)entry->flags & sizeof(void *)), "got unexpected ptr align\n" );
todo_wine_if(sizeof(void *) == 4) todo_wine_if(sizeof(void *) == 4)
ok( !((UINT_PTR)entry->flags & (sizeof(void *) - 1)), "got unexpected ptr align\n" ); ok( !((UINT_PTR)entry->flags & (sizeof(void *) - 1)), "got unexpected ptr align\n" );
...@@ -787,15 +782,11 @@ static void test_LocalAlloc(void) ...@@ -787,15 +782,11 @@ static void test_LocalAlloc(void)
SetLastError( 0xdeadbeef ); SetLastError( 0xdeadbeef );
mem = LocalAlloc( LMEM_MOVEABLE | LMEM_DISCARDABLE, 0 ); mem = LocalAlloc( LMEM_MOVEABLE | LMEM_DISCARDABLE, 0 );
todo_wine
ok( !mem, "LocalAlloc succeeded\n" ); ok( !mem, "LocalAlloc succeeded\n" );
todo_wine
ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() );
SetLastError( 0xdeadbeef ); SetLastError( 0xdeadbeef );
mem = GlobalAlloc( GMEM_MOVEABLE | GMEM_DISCARDABLE, 0 ); mem = GlobalAlloc( GMEM_MOVEABLE | GMEM_DISCARDABLE, 0 );
todo_wine
ok( !mem, "GlobalAlloc succeeded\n" ); ok( !mem, "GlobalAlloc succeeded\n" );
todo_wine
ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() );
mem = LocalAlloc( LMEM_DISCARDABLE, 0 ); mem = LocalAlloc( LMEM_DISCARDABLE, 0 );
......
...@@ -589,15 +589,30 @@ struct kernelbase_global_data ...@@ -589,15 +589,30 @@ struct kernelbase_global_data
struct mem_entry struct mem_entry
{ {
WORD magic; union
void *ptr; {
BYTE flags; struct
BYTE lock; {
WORD magic;
void *ptr;
BYTE flags;
BYTE lock;
};
void *next_free;
};
}; };
#include "poppack.h" #include "poppack.h"
static struct kernelbase_global_data kernelbase_global_data = {0}; #define MAX_MEM_HANDLES 0x10000
static struct mem_entry mem_entries[MAX_MEM_HANDLES];
static struct mem_entry *next_free_mem = mem_entries;
static struct kernelbase_global_data kernelbase_global_data =
{
.mem_entries = mem_entries,
.mem_entries_end = mem_entries + MAX_MEM_HANDLES,
};
#define MAGIC_LOCAL_USED 0x5342 #define MAGIC_LOCAL_USED 0x5342
/* align the storage needed for the HLOCAL on an 8-byte boundary thus /* align the storage needed for the HLOCAL on an 8-byte boundary thus
...@@ -610,7 +625,9 @@ static struct kernelbase_global_data kernelbase_global_data = {0}; ...@@ -610,7 +625,9 @@ static struct kernelbase_global_data kernelbase_global_data = {0};
static inline struct mem_entry *unsafe_mem_from_HLOCAL( HLOCAL handle ) 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( handle, struct mem_entry, ptr );
struct kernelbase_global_data *data = &kernelbase_global_data;
if (!((ULONG_PTR)handle & 2)) return NULL; if (!((ULONG_PTR)handle & 2)) return NULL;
if (mem < data->mem_entries || mem >= data->mem_entries_end) return NULL;
if (mem->magic != MAGIC_LOCAL_USED) return NULL; if (mem->magic != MAGIC_LOCAL_USED) return NULL;
return mem; return mem;
} }
...@@ -666,8 +683,10 @@ HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalFree( HLOCAL handle ) ...@@ -666,8 +683,10 @@ HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalFree( HLOCAL handle )
*/ */
HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size ) HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size )
{ {
HANDLE heap = GetProcessHeap();
struct mem_entry *mem; struct mem_entry *mem;
DWORD heap_flags = 0; DWORD heap_flags = 0;
HLOCAL handle;
void *ptr; void *ptr;
TRACE_(globalmem)( "flags %#x, size %#Ix\n", flags, size ); TRACE_(globalmem)( "flags %#x, size %#Ix\n", flags, size );
...@@ -676,36 +695,44 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size ) ...@@ -676,36 +695,44 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size )
if (!(flags & LMEM_MOVEABLE)) /* pointer */ if (!(flags & LMEM_MOVEABLE)) /* pointer */
{ {
ptr = HeapAlloc( GetProcessHeap(), heap_flags, size ); ptr = HeapAlloc( heap, heap_flags, size );
TRACE_(globalmem)( "return %p\n", ptr ); TRACE_(globalmem)( "return %p\n", ptr );
return ptr; return ptr;
} }
if (size > INT_MAX - HLOCAL_STORAGE) RtlLockHeap( heap );
if ((mem = next_free_mem) < mem_entries || mem >= mem_entries + MAX_MEM_HANDLES)
mem = NULL;
else
{ {
SetLastError( ERROR_OUTOFMEMORY ); if (!mem->next_free) next_free_mem++;
return 0; else next_free_mem = mem->next_free;
mem->next_free = NULL;
} }
if (!(mem = HeapAlloc( GetProcessHeap(), 0, sizeof(*mem) ))) return 0; RtlUnlockHeap( heap );
if (!mem) goto failed;
handle = HLOCAL_from_mem( mem );
mem->magic = MAGIC_LOCAL_USED; mem->magic = MAGIC_LOCAL_USED;
mem->flags = flags >> 8; mem->flags = flags >> 8;
mem->lock = 0; mem->lock = 0;
mem->ptr = NULL;
if (size) if (size)
{ {
if (!(ptr = HeapAlloc(GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE ))) if (!(ptr = HeapAlloc( heap, heap_flags, size + HLOCAL_STORAGE ))) goto failed;
{ *(HLOCAL *)ptr = handle;
HeapFree( GetProcessHeap(), 0, mem );
return 0;
}
*(HLOCAL *)ptr = HLOCAL_from_mem( mem );
mem->ptr = (char *)ptr + HLOCAL_STORAGE; mem->ptr = (char *)ptr + HLOCAL_STORAGE;
} }
else mem->ptr = NULL;
TRACE_(globalmem)( "return handle %p, ptr %p\n", HLOCAL_from_mem( mem ), mem->ptr ); TRACE_(globalmem)( "return handle %p, ptr %p\n", handle, mem->ptr );
return HLOCAL_from_mem( mem ); return handle;
failed:
if (mem) LocalFree( handle );
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return 0;
} }
...@@ -714,52 +741,32 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size ) ...@@ -714,52 +741,32 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size )
*/ */
HLOCAL WINAPI DECLSPEC_HOTPATCH LocalFree( HLOCAL handle ) HLOCAL WINAPI DECLSPEC_HOTPATCH LocalFree( HLOCAL handle )
{ {
HANDLE heap = GetProcessHeap();
struct mem_entry *mem; struct mem_entry *mem;
HLOCAL ret; HLOCAL ret = handle;
void *ptr; void *ptr;
TRACE_(globalmem)( "handle %p\n", handle ); TRACE_(globalmem)( "handle %p\n", handle );
RtlLockHeap( GetProcessHeap() ); RtlLockHeap( heap );
__TRY if ((ptr = unsafe_ptr_from_HLOCAL( handle )))
{ {
ret = 0; if (HeapFree( heap, HEAP_NO_SERIALIZE, ptr )) ret = 0;
if ((ptr = unsafe_ptr_from_HLOCAL( handle )))
{
if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, ptr ))
{
SetLastError( ERROR_INVALID_HANDLE );
ret = handle;
}
}
else /* HANDLE */
{
if ((mem = unsafe_mem_from_HLOCAL( handle )))
{
mem->magic = 0xdead;
if (mem->ptr)
{
if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, (char *)mem->ptr - HLOCAL_STORAGE ))
ret = handle;
}
if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, mem )) ret = handle;
}
else
{
WARN_(globalmem)( "invalid handle %p\n", handle );
SetLastError( ERROR_INVALID_HANDLE );
ret = handle;
}
}
} }
__EXCEPT_PAGE_FAULT else if ((mem = unsafe_mem_from_HLOCAL( handle )))
{
if (!mem->ptr || HeapFree( heap, HEAP_NO_SERIALIZE, (char *)mem->ptr - HLOCAL_STORAGE )) ret = 0;
mem->ptr = NULL;
mem->next_free = next_free_mem;
next_free_mem = mem;
}
RtlUnlockHeap( heap );
if (ret)
{ {
WARN_(globalmem)( "invalid handle %p\n", handle ); WARN_(globalmem)( "invalid handle %p\n", handle );
SetLastError( ERROR_INVALID_HANDLE ); SetLastError( ERROR_INVALID_HANDLE );
ret = handle;
} }
__ENDTRY
RtlUnlockHeap( GetProcessHeap() );
return ret; return ret;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment