From: Zhiyi Zhang zzhang@codeweavers.com
React Native applications need a real kernel handle from NtAllocateReserveObject(). NtAllocateReserveObject() pre-allocates memory for objects to deal with low memory situations. Due to no APIs in Wine actually uses NtAllocateReserveObject(), for now no memory is reserved. --- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/signal_arm64ec.c | 1 + dlls/ntdll/tests/om.c | 1 - dlls/ntdll/unix/server.c | 25 +++++++ dlls/wow64/syscall.c | 17 +++++ include/winternl.h | 7 ++ server/directory.c | 2 + server/object.c | 145 ++++++++++++++++++++++++++++++++++++ server/object.h | 2 + server/protocol.def | 9 +++ 10 files changed, 209 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 1234205cf1a..5fe8dcc4a0b 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -145,6 +145,7 @@ @ stdcall -syscall NtAlertThread(long) @ stdcall -syscall NtAlertThreadByThreadId(ptr) @ stdcall -syscall NtAllocateLocallyUniqueId(ptr) +@ stdcall -syscall NtAllocateReserveObject(ptr long long) # @ stub NtAllocateUserPhysicalPages @ stdcall -syscall NtAllocateUuids(ptr ptr ptr ptr) @ stdcall -syscall NtAllocateVirtualMemory(long ptr long ptr long long) diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c index 65eaf010e4d..438dfe8d439 100644 --- a/dlls/ntdll/signal_arm64ec.c +++ b/dlls/ntdll/signal_arm64ec.c @@ -251,6 +251,7 @@ DEFINE_SYSCALL(NtAlertResumeThread, (HANDLE handle, ULONG *count)) DEFINE_SYSCALL(NtAlertThread, (HANDLE handle)) DEFINE_SYSCALL(NtAlertThreadByThreadId, (HANDLE tid)) DEFINE_SYSCALL(NtAllocateLocallyUniqueId, (LUID *luid)) +DEFINE_SYSCALL(NtAllocateReserveObject, (HANDLE *handle, const OBJECT_ATTRIBUTES *attr, MEMORY_RESERVE_OBJECT_TYPE type)) DEFINE_SYSCALL(NtAllocateUuids, (ULARGE_INTEGER *time, ULONG *delta, ULONG *sequence, UCHAR *seed)) DEFINE_WRAPPED_SYSCALL(NtAllocateVirtualMemory, (HANDLE process, PVOID *ret, ULONG_PTR zero_bits, SIZE_T *size_ptr, ULONG type, ULONG protect)) DEFINE_WRAPPED_SYSCALL(NtAllocateVirtualMemoryEx, (HANDLE process, PVOID *ret, SIZE_T *size_ptr, ULONG type, ULONG protect, MEM_EXTENDED_PARAMETER *parameters, ULONG count)) diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index 61847e40887..1b6cabb0528 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -2401,7 +2401,6 @@ static void test_object_types(void) break; }
- todo_wine_if(!lstrcmpW( tests[i].name, L"IoCompletionReserve" ) || !lstrcmpW( tests[i].name, L"UserApcReserve" )) ok( j < ARRAY_SIZE(all_types), "type %s not found\n", debugstr_w(tests[i].name) ); } for (j = 0; j < ARRAY_SIZE(all_types); j++) diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index f3ffd99c3fc..f03d008e2ae 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -1719,6 +1719,31 @@ void server_init_thread( void *entry_point, BOOL *suspend ) close( reply_pipe ); }
+NTSTATUS WINAPI NtAllocateReserveObject( HANDLE *handle, const OBJECT_ATTRIBUTES *attr, + MEMORY_RESERVE_OBJECT_TYPE type ) +{ + struct object_attributes *objattr; + unsigned int ret; + data_size_t len; + + TRACE("(%p, %p, %d)\n", handle, attr, type); + + *handle = 0; + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + + SERVER_START_REQ( allocate_reserve_object ) + { + req->type = type; + wine_server_add_data( req, objattr, len ); + if (!(ret = wine_server_call( req ))) + *handle = wine_server_ptr_handle( reply->handle ); + } + SERVER_END_REQ; + + free( objattr ); + return ret; +} +
/****************************************************************************** * NtDuplicateObject diff --git a/dlls/wow64/syscall.c b/dlls/wow64/syscall.c index fc60ae37816..add5c6b9ed7 100644 --- a/dlls/wow64/syscall.c +++ b/dlls/wow64/syscall.c @@ -424,6 +424,23 @@ NTSTATUS WINAPI wow64_NtAllocateLocallyUniqueId( UINT *args ) return NtAllocateLocallyUniqueId( luid ); }
+/********************************************************************** + * wow64_NtAllocateReserveObject + */ +NTSTATUS WINAPI wow64_NtAllocateReserveObject( UINT *args ) +{ + ULONG *handle_ptr = get_ptr( &args ); + OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args ); + MEMORY_RESERVE_OBJECT_TYPE type = get_ulong( &args ); + NTSTATUS status; + + struct object_attr64 attr; + HANDLE handle = 0; + + status = NtAllocateReserveObject( &handle, objattr_32to64_redirect( &attr, attr32 ), type); + put_handle( handle_ptr, handle ); + return status; +}
/********************************************************************** * wow64_NtAllocateUuids diff --git a/include/winternl.h b/include/winternl.h index 4f24a921bb1..53f11b18486 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -2553,6 +2553,12 @@ typedef struct _KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 { UCHAR Data[1]; } KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, *PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64;
+typedef enum _MEMORY_RESERVE_OBJECT_TYPE +{ + MemoryReserveObjectTypeUserApc, + MemoryReserveObjectTypeIoCompletion +} MEMORY_RESERVE_OBJECT_TYPE, PMEMORY_RESERVE_OBJECT_TYPE; + #ifndef __OBJECT_ATTRIBUTES_DEFINED__ #define __OBJECT_ATTRIBUTES_DEFINED__ typedef struct _OBJECT_ATTRIBUTES { @@ -4441,6 +4447,7 @@ NTSYSAPI NTSTATUS WINAPI NtAlertResumeThread(HANDLE,PULONG); NTSYSAPI NTSTATUS WINAPI NtAlertThread(HANDLE ThreadHandle); NTSYSAPI NTSTATUS WINAPI NtAlertThreadByThreadId(HANDLE); NTSYSAPI NTSTATUS WINAPI NtAllocateLocallyUniqueId(PLUID lpLuid); +NTSYSAPI NTSTATUS WINAPI NtAllocateReserveObject(HANDLE *handle,const OBJECT_ATTRIBUTES *attr,MEMORY_RESERVE_OBJECT_TYPE type); NTSYSAPI NTSTATUS WINAPI NtAllocateUuids(PULARGE_INTEGER,PULONG,PULONG,PUCHAR); NTSYSAPI NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE,PVOID*,ULONG_PTR,SIZE_T*,ULONG,ULONG); NTSYSAPI NTSTATUS WINAPI NtAllocateVirtualMemoryEx(HANDLE,PVOID*,SIZE_T*,ULONG,ULONG,MEM_EXTENDED_PARAMETER*,ULONG); diff --git a/server/directory.c b/server/directory.c index b3f055dfd01..b37ec969a9e 100644 --- a/server/directory.c +++ b/server/directory.c @@ -161,6 +161,8 @@ static struct type_descr *types[] = &file_type, &mapping_type, &key_type, + &apc_reserve_type, + &completion_reserve_type, };
static void object_type_dump( struct object *obj, int verbose ) diff --git a/server/object.c b/server/object.c index 1a3bff65969..04f334ffcf5 100644 --- a/server/object.c +++ b/server/object.c @@ -41,6 +41,8 @@ #include "thread.h" #include "unicode.h" #include "security.h" +#include "handle.h" +#include "request.h"
struct namespace @@ -62,6 +64,90 @@ struct type_descr no_type = }, };
+struct reserve +{ + struct object obj; /* object header */ + int type; /* reserve object type. See MEMORY_RESERVE_OBJECT_TYPE */ + /* BYTE *memory */; /* reserved memory */ +}; + +static const WCHAR apc_reserve_type_name[] = {'U','s','e','r','A','p','c','R','e','s','e','r','v','e'}; +static const WCHAR completion_reserve_name[] = {'I','o','C','o','m','p','l','e','t','i','o','n','R','e','s','e','r','v','e'}; + +struct type_descr apc_reserve_type = +{ + { apc_reserve_type_name, sizeof(apc_reserve_type_name) }, /* name */ + STANDARD_RIGHTS_REQUIRED | 0x3, /* valid_access */ + { /* mapping */ + STANDARD_RIGHTS_READ | 0x1, + STANDARD_RIGHTS_WRITE | 0x2, + STANDARD_RIGHTS_EXECUTE, + STANDARD_RIGHTS_REQUIRED | 0x3 + }, +}; + +struct type_descr completion_reserve_type = +{ + { completion_reserve_name, sizeof(completion_reserve_name) }, /* name */ + STANDARD_RIGHTS_REQUIRED | 0x3, /* valid_access */ + { /* mapping */ + STANDARD_RIGHTS_READ | 0x1, + STANDARD_RIGHTS_WRITE | 0x2, + STANDARD_RIGHTS_EXECUTE, + STANDARD_RIGHTS_REQUIRED | 0x3 + }, +}; + +static void dump_reserve( struct object *obj, int verbose ); + +static const struct object_ops apc_reserve_ops = +{ + sizeof(struct reserve), /* size */ + &apc_reserve_type, /* type */ + dump_reserve, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + default_get_full_name, /* get_full_name */ + no_lookup_name, /* lookup_name */ + directory_link_name, /* link_name */ + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ +}; + +static const struct object_ops completion_reserve_ops = +{ + sizeof(struct reserve), /* size */ + &completion_reserve_type, /* type */ + dump_reserve, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + default_get_full_name, /* get_full_name */ + no_lookup_name, /* lookup_name */ + directory_link_name, /* link_name */ + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ +}; + #ifdef DEBUG_OBJECTS static struct list object_list = LIST_INIT(object_list);
@@ -729,3 +815,62 @@ int no_close_handle( struct object *obj, struct process *process, obj_handle_t h void no_destroy( struct object *obj ) { } + +static void dump_reserve( struct object *obj, int verbose ) +{ + struct reserve *reserve = (struct reserve *) obj; + + assert( obj->ops == &apc_reserve_ops || obj->ops == &completion_reserve_ops ); + fprintf( stderr, "reserve type=%d\n", reserve->type); +} + +struct reserve *create_reserve( struct object *root, const struct unicode_str *name, + unsigned int attr, int type, const struct security_descriptor *sd ) +{ + struct reserve *reserve; + + if (name->len) + { + set_error( STATUS_OBJECT_NAME_INVALID ); + return NULL; + } + + if (type == MemoryReserveObjectTypeUserApc) + { + reserve = create_named_object( root, &apc_reserve_ops, name, attr, sd ); + } + else if (type == MemoryReserveObjectTypeIoCompletion) + { + reserve = create_named_object( root, &completion_reserve_ops, name, attr, sd ); + } + else + { + set_error( STATUS_INVALID_PARAMETER ); + return NULL; + } + + if (reserve && get_error() != STATUS_OBJECT_NAME_EXISTS) reserve->type = type; + + return reserve; +} + +/* Allocate a reserve object for pre-allocating memory for object types */ +DECL_HANDLER(allocate_reserve_object) +{ + struct unicode_str name; + struct object *root; + const struct security_descriptor *sd; + const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root ); + struct reserve *reserve; + + if (!objattr) return; + + if ((reserve = create_reserve( root, &name, objattr->attributes, req->type, sd ))) + { + reply->handle = alloc_handle_no_access_check( current->process, reserve, GENERIC_READ | GENERIC_WRITE, + objattr->attributes ); + release_object( reserve ); + } + + if (root) release_object( root ); +} diff --git a/server/object.h b/server/object.h index e35edfa68f4..6222e3352ed 100644 --- a/server/object.h +++ b/server/object.h @@ -331,6 +331,8 @@ extern struct type_descr completion_type; extern struct type_descr file_type; extern struct type_descr mapping_type; extern struct type_descr key_type; +extern struct type_descr apc_reserve_type; +extern struct type_descr completion_reserve_type;
#define KEYEDEVENT_WAIT 0x0001 #define KEYEDEVENT_WAKE 0x0002 diff --git a/server/protocol.def b/server/protocol.def index c6af7379f17..a4f25e805f8 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1254,6 +1254,15 @@ typedef struct @END
+/* Allocate a reserve object for pre-allocating memory for object types */ +@REQ(allocate_reserve_object) + int type; /* reserve object type. See MEMORY_RESERVE_OBJECT_TYPE */ + VARARG(objattr,object_attributes); /* object attributes */ +@REPLY + obj_handle_t handle; /* reserve object handle */ +@END + + /* Test if two handles refer to the same object */ @REQ(compare_objects) obj_handle_t first; /* first object handle */