From 84a4219719a71ce921c88e0bfaec343ccd865c33 Mon Sep 17 00:00:00 2001 From: WINDROID-EMU <45230455+WINDROID-EMU@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:32:03 -0300 Subject: [PATCH 1/5] Update print statement from 'Hello' to 'Goodbye' Banjo Recompile --- dlls/combase/combase.c | 4844 ++++++++++++++++++++-------------------- 1 file changed, 2377 insertions(+), 2467 deletions(-) diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index b3a1c9bd8fc4..753641646b98 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -21,10 +21,10 @@ #include "ntstatus.h" #define WIN32_NO_STATUS #define USE_COM_CONTEXT_DEF -#include "objbase.h" #include "ctxtcall.h" -#include "oleauto.h" #include "dde.h" +#include "objbase.h" +#include "oleauto.h" #include "winternl.h" #include "combase_private.h" @@ -39,2909 +39,2847 @@ static ULONG_PTR global_options[COMGLB_PROPERTIES_RESERVED3 + 1]; /* Ole32 exports */ extern void WINAPI DestroyRunningObjectTable(void); -extern HRESULT WINAPI Ole32DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj); +extern HRESULT WINAPI Ole32DllGetClassObject(REFCLSID rclsid, REFIID riid, + void **obj); /* - * Number of times CoInitialize is called. It is decreased every time CoUninitialize is called. When it hits 0, the COM libraries are freed + * Number of times CoInitialize is called. It is decreased every time + * CoUninitialize is called. When it hits 0, the COM libraries are freed */ static LONG com_lockcount; static LONG com_server_process_refcount; -struct comclassredirect_data -{ - ULONG size; - ULONG flags; - DWORD model; - GUID clsid; - GUID alias; - GUID clsid2; - GUID tlbid; - ULONG name_len; - ULONG name_offset; - ULONG progid_len; - ULONG progid_offset; - ULONG clrdata_len; - ULONG clrdata_offset; - DWORD miscstatus; - DWORD miscstatuscontent; - DWORD miscstatusthumbnail; - DWORD miscstatusicon; - DWORD miscstatusdocprint; +struct comclassredirect_data { + ULONG size; + ULONG flags; + DWORD model; + GUID clsid; + GUID alias; + GUID clsid2; + GUID tlbid; + ULONG name_len; + ULONG name_offset; + ULONG progid_len; + ULONG progid_offset; + ULONG clrdata_len; + ULONG clrdata_offset; + DWORD miscstatus; + DWORD miscstatuscontent; + DWORD miscstatusthumbnail; + DWORD miscstatusicon; + DWORD miscstatusdocprint; }; -struct ifacepsredirect_data -{ - ULONG size; - DWORD mask; - GUID iid; - ULONG nummethods; - GUID tlbid; - GUID base; - ULONG name_len; - ULONG name_offset; +struct ifacepsredirect_data { + ULONG size; + DWORD mask; + GUID iid; + ULONG nummethods; + GUID tlbid; + GUID base; + ULONG name_len; + ULONG name_offset; }; -struct progidredirect_data -{ - ULONG size; - DWORD reserved; - ULONG clsid_offset; +struct progidredirect_data { + ULONG size; + DWORD reserved; + ULONG clsid_offset; }; -struct init_spy -{ - struct list entry; - IInitializeSpy *spy; - unsigned int id; +struct init_spy { + struct list entry; + IInitializeSpy *spy; + unsigned int id; }; -struct registered_ps -{ - struct list entry; - IID iid; - CLSID clsid; +struct registered_ps { + struct list entry; + IID iid; + CLSID clsid; }; static struct list registered_proxystubs = LIST_INIT(registered_proxystubs); static CRITICAL_SECTION cs_registered_ps; -static CRITICAL_SECTION_DEBUG psclsid_cs_debug = -{ - 0, 0, &cs_registered_ps, - { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") } -}; -static CRITICAL_SECTION cs_registered_ps = { &psclsid_cs_debug, -1, 0, 0, 0, 0 }; - -struct registered_class -{ - struct list entry; - CLSID clsid; - OXID apartment_id; - IUnknown *object; - DWORD clscontext; - DWORD flags; - unsigned int cookie; - unsigned int rpcss_cookie; +static CRITICAL_SECTION_DEBUG psclsid_cs_debug = { + 0, + 0, + &cs_registered_ps, + {&psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList}, + 0, + 0, + {(DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list")}}; +static CRITICAL_SECTION cs_registered_ps = {&psclsid_cs_debug, -1, 0, 0, 0, 0}; + +struct registered_class { + struct list entry; + CLSID clsid; + OXID apartment_id; + IUnknown *object; + DWORD clscontext; + DWORD flags; + unsigned int cookie; + unsigned int rpcss_cookie; }; static struct list registered_classes = LIST_INIT(registered_classes); static CRITICAL_SECTION registered_classes_cs; -static CRITICAL_SECTION_DEBUG registered_classes_cs_debug = -{ - 0, 0, ®istered_classes_cs, - { ®istered_classes_cs_debug.ProcessLocksList, ®istered_classes_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": registered_classes_cs") } -}; -static CRITICAL_SECTION registered_classes_cs = { ®istered_classes_cs_debug, -1, 0, 0, 0, 0 }; - -IUnknown * com_get_registered_class_object(const struct apartment *apt, REFCLSID rclsid, DWORD clscontext) -{ - struct registered_class *cur; - IUnknown *object = NULL; - - EnterCriticalSection(®istered_classes_cs); - - LIST_FOR_EACH_ENTRY(cur, ®istered_classes, struct registered_class, entry) - { - if ((apt->oxid == cur->apartment_id) && - (clscontext & cur->clscontext) && - IsEqualGUID(&cur->clsid, rclsid)) - { - object = cur->object; - IUnknown_AddRef(cur->object); - break; - } - } - - LeaveCriticalSection(®istered_classes_cs); - - return object; -} - -static struct init_spy *get_spy_entry(struct tlsdata *tlsdata, unsigned int id) -{ - struct init_spy *spy; - - LIST_FOR_EACH_ENTRY(spy, &tlsdata->spies, struct init_spy, entry) - { - if (id == spy->id && spy->spy) - return spy; - } - - return NULL; -} - -static NTSTATUS create_key(HKEY *retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr) -{ - NTSTATUS status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL); - - if (status == STATUS_OBJECT_NAME_NOT_FOUND) - { - HANDLE subkey; - WCHAR *buffer = attr->ObjectName->Buffer; - DWORD pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); - UNICODE_STRING str; - OBJECT_ATTRIBUTES attr2 = *attr; - - while (i < len && buffer[i] != '\\') i++; - if (i == len) return status; - - attr2.ObjectName = &str; - - while (i < len) - { - str.Buffer = buffer + pos; - str.Length = (i - pos) * sizeof(WCHAR); - status = NtCreateKey(&subkey, access, &attr2, 0, NULL, 0, NULL); - if (attr2.RootDirectory != attr->RootDirectory) NtClose(attr2.RootDirectory); - if (status) return status; - attr2.RootDirectory = subkey; - while (i < len && buffer[i] == '\\') i++; - pos = i; - while (i < len && buffer[i] != '\\') i++; - } - str.Buffer = buffer + pos; - str.Length = (i - pos) * sizeof(WCHAR); - status = NtCreateKey((HANDLE *)retkey, access, &attr2, 0, NULL, 0, NULL); - if (attr2.RootDirectory != attr->RootDirectory) NtClose(attr2.RootDirectory); - } - return status; +static CRITICAL_SECTION_DEBUG registered_classes_cs_debug = { + 0, + 0, + ®istered_classes_cs, + {®istered_classes_cs_debug.ProcessLocksList, + ®istered_classes_cs_debug.ProcessLocksList}, + 0, + 0, + {(DWORD_PTR)(__FILE__ ": registered_classes_cs")}}; +static CRITICAL_SECTION registered_classes_cs = { + ®istered_classes_cs_debug, -1, 0, 0, 0, 0}; + +IUnknown *com_get_registered_class_object(const struct apartment *apt, + REFCLSID rclsid, DWORD clscontext) { + struct registered_class *cur; + IUnknown *object = NULL; + + EnterCriticalSection(®istered_classes_cs); + + LIST_FOR_EACH_ENTRY(cur, ®istered_classes, struct registered_class, + entry) { + if ((apt->oxid == cur->apartment_id) && (clscontext & cur->clscontext) && + IsEqualGUID(&cur->clsid, rclsid)) { + object = cur->object; + IUnknown_AddRef(cur->object); + break; + } + } + + LeaveCriticalSection(®istered_classes_cs); + + return object; +} + +static struct init_spy *get_spy_entry(struct tlsdata *tlsdata, + unsigned int id) { + struct init_spy *spy; + + LIST_FOR_EACH_ENTRY(spy, &tlsdata->spies, struct init_spy, entry) { + if (id == spy->id && spy->spy) + return spy; + } + + return NULL; +} + +static NTSTATUS create_key(HKEY *retkey, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr) { + NTSTATUS status = + NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL); + + if (status == STATUS_OBJECT_NAME_NOT_FOUND) { + HANDLE subkey; + WCHAR *buffer = attr->ObjectName->Buffer; + DWORD pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); + UNICODE_STRING str; + OBJECT_ATTRIBUTES attr2 = *attr; + + while (i < len && buffer[i] != '\\') + i++; + if (i == len) + return status; + + attr2.ObjectName = &str; + + while (i < len) { + str.Buffer = buffer + pos; + str.Length = (i - pos) * sizeof(WCHAR); + status = NtCreateKey(&subkey, access, &attr2, 0, NULL, 0, NULL); + if (attr2.RootDirectory != attr->RootDirectory) + NtClose(attr2.RootDirectory); + if (status) + return status; + attr2.RootDirectory = subkey; + while (i < len && buffer[i] == '\\') + i++; + pos = i; + while (i < len && buffer[i] != '\\') + i++; + } + str.Buffer = buffer + pos; + str.Length = (i - pos) * sizeof(WCHAR); + status = NtCreateKey((HANDLE *)retkey, access, &attr2, 0, NULL, 0, NULL); + if (attr2.RootDirectory != attr->RootDirectory) + NtClose(attr2.RootDirectory); + } + return status; } static HKEY classes_root_hkey; -static HKEY create_classes_root_hkey(DWORD access) -{ - HKEY hkey, ret = 0; - OBJECT_ATTRIBUTES attr; - UNICODE_STRING name = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Classes"); - - attr.Length = sizeof(attr); - attr.RootDirectory = 0; - attr.ObjectName = &name; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - - if (create_key( &hkey, access, &attr )) return 0; - TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey ); - - if (!(access & KEY_WOW64_64KEY)) - { - if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 ))) - ret = hkey; - else - NtClose( hkey ); /* somebody beat us to it */ - } +static HKEY create_classes_root_hkey(DWORD access) { + HKEY hkey, ret = 0; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING name = + RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Classes"); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &name; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + if (create_key(&hkey, access, &attr)) + return 0; + TRACE("%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey); + + if (!(access & KEY_WOW64_64KEY)) { + if (!(ret = InterlockedCompareExchangePointer((void **)&classes_root_hkey, + hkey, 0))) + ret = hkey; else - ret = hkey; - return ret; + NtClose(hkey); /* somebody beat us to it */ + } else + ret = hkey; + return ret; } static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access); -static LSTATUS create_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey) -{ - OBJECT_ATTRIBUTES attr; - UNICODE_STRING nameW; - - if (!(hkey = get_classes_root_hkey(hkey, access))) - return ERROR_INVALID_HANDLE; - - attr.Length = sizeof(attr); - attr.RootDirectory = hkey; - attr.ObjectName = &nameW; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - RtlInitUnicodeString( &nameW, name ); - - return RtlNtStatusToDosError(create_key(retkey, access, &attr)); -} - -static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access) -{ - HKEY ret = hkey; - const BOOL is_win64 = sizeof(void*) > sizeof(int); - const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); - - if (hkey == HKEY_CLASSES_ROOT && - ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey))) - ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY)); - if (force_wow32 && ret && ret == classes_root_hkey) - { - access &= ~KEY_WOW64_32KEY; - if (create_classes_key(classes_root_hkey, L"Wow6432Node", access, &hkey)) - return 0; - ret = hkey; - } - - return ret; -} - -static LSTATUS open_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey) -{ - OBJECT_ATTRIBUTES attr; - UNICODE_STRING nameW; - - if (!(hkey = get_classes_root_hkey(hkey, access))) - return ERROR_INVALID_HANDLE; - - attr.Length = sizeof(attr); - attr.RootDirectory = hkey; - attr.ObjectName = &nameW; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - RtlInitUnicodeString( &nameW, name ); - - return RtlNtStatusToDosError(NtOpenKey((HANDLE *)retkey, access, &attr)); -} - -HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, HKEY *subkey) -{ - static const WCHAR clsidW[] = L"CLSID\\"; - WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(clsidW) - 1]; - LONG res; - HKEY key; - - lstrcpyW(path, clsidW); - StringFromGUID2(clsid, path + lstrlenW(clsidW), CHARS_IN_GUID); - res = open_classes_key(HKEY_CLASSES_ROOT, path, access, &key); - if (res == ERROR_FILE_NOT_FOUND) - return REGDB_E_CLASSNOTREG; - else if (res != ERROR_SUCCESS) - return REGDB_E_READREGDB; - - if (!keyname) - { - *subkey = key; - return S_OK; - } +static LSTATUS create_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, + HKEY *retkey) { + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW; + + if (!(hkey = get_classes_root_hkey(hkey, access))) + return ERROR_INVALID_HANDLE; + + attr.Length = sizeof(attr); + attr.RootDirectory = hkey; + attr.ObjectName = &nameW; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString(&nameW, name); + + return RtlNtStatusToDosError(create_key(retkey, access, &attr)); +} + +static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access) { + HKEY ret = hkey; + const BOOL is_win64 = sizeof(void *) > sizeof(int); + const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); + + if (hkey == HKEY_CLASSES_ROOT && + ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey))) + ret = + create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY)); + if (force_wow32 && ret && ret == classes_root_hkey) { + access &= ~KEY_WOW64_32KEY; + if (create_classes_key(classes_root_hkey, L"Wow6432Node", access, &hkey)) + return 0; + ret = hkey; + } + + return ret; +} + +static LSTATUS open_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, + HKEY *retkey) { + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW; + + if (!(hkey = get_classes_root_hkey(hkey, access))) + return ERROR_INVALID_HANDLE; + + attr.Length = sizeof(attr); + attr.RootDirectory = hkey; + attr.ObjectName = &nameW; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString(&nameW, name); + + return RtlNtStatusToDosError(NtOpenKey((HANDLE *)retkey, access, &attr)); +} + +HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, + HKEY *subkey) { + static const WCHAR clsidW[] = L"CLSID\\"; + WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(clsidW) - 1]; + LONG res; + HKEY key; + + lstrcpyW(path, clsidW); + StringFromGUID2(clsid, path + lstrlenW(clsidW), CHARS_IN_GUID); + res = open_classes_key(HKEY_CLASSES_ROOT, path, access, &key); + if (res == ERROR_FILE_NOT_FOUND) + return REGDB_E_CLASSNOTREG; + else if (res != ERROR_SUCCESS) + return REGDB_E_READREGDB; + + if (!keyname) { + *subkey = key; + return S_OK; + } - res = open_classes_key(key, keyname, access, subkey); - RegCloseKey(key); - if (res == ERROR_FILE_NOT_FOUND) - return REGDB_E_KEYMISSING; - else if (res != ERROR_SUCCESS) - return REGDB_E_READREGDB; + res = open_classes_key(key, keyname, access, subkey); + RegCloseKey(key); + if (res == ERROR_FILE_NOT_FOUND) + return REGDB_E_KEYMISSING; + else if (res != ERROR_SUCCESS) + return REGDB_E_READREGDB; - return S_OK; + return S_OK; } /* open HKCR\\AppId\\{string form of appid clsid} key */ -HRESULT open_appidkey_from_clsid(REFCLSID clsid, REGSAM access, HKEY *subkey) -{ - static const WCHAR appidkeyW[] = L"AppId\\"; - DWORD res; - WCHAR buf[CHARS_IN_GUID]; - WCHAR keyname[ARRAY_SIZE(appidkeyW) + CHARS_IN_GUID]; - DWORD size; - HKEY hkey; - DWORD type; - HRESULT hr; +HRESULT open_appidkey_from_clsid(REFCLSID clsid, REGSAM access, HKEY *subkey) { + static const WCHAR appidkeyW[] = L"AppId\\"; + DWORD res; + WCHAR buf[CHARS_IN_GUID]; + WCHAR keyname[ARRAY_SIZE(appidkeyW) + CHARS_IN_GUID]; + DWORD size; + HKEY hkey; + DWORD type; + HRESULT hr; + + /* read the AppID value under the class's key */ + hr = open_key_for_clsid(clsid, NULL, access, &hkey); + if (FAILED(hr)) + return hr; - /* read the AppID value under the class's key */ - hr = open_key_for_clsid(clsid, NULL, access, &hkey); - if (FAILED(hr)) - return hr; + size = sizeof(buf); + res = RegQueryValueExW(hkey, L"AppId", NULL, &type, (LPBYTE)buf, &size); + RegCloseKey(hkey); + if (res == ERROR_FILE_NOT_FOUND) + return REGDB_E_KEYMISSING; + else if (res != ERROR_SUCCESS || type != REG_SZ) + return REGDB_E_READREGDB; - size = sizeof(buf); - res = RegQueryValueExW(hkey, L"AppId", NULL, &type, (LPBYTE)buf, &size); - RegCloseKey(hkey); - if (res == ERROR_FILE_NOT_FOUND) - return REGDB_E_KEYMISSING; - else if (res != ERROR_SUCCESS || type!=REG_SZ) - return REGDB_E_READREGDB; - - lstrcpyW(keyname, appidkeyW); - lstrcatW(keyname, buf); - res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey); - if (res == ERROR_FILE_NOT_FOUND) - return REGDB_E_KEYMISSING; - else if (res != ERROR_SUCCESS) - return REGDB_E_READREGDB; + lstrcpyW(keyname, appidkeyW); + lstrcatW(keyname, buf); + res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey); + if (res == ERROR_FILE_NOT_FOUND) + return REGDB_E_KEYMISSING; + else if (res != ERROR_SUCCESS) + return REGDB_E_READREGDB; - return S_OK; + return S_OK; } /*********************************************************************** * InternalIsProcessInitialized (combase.@) */ -BOOL WINAPI InternalIsProcessInitialized(void) -{ - struct apartment *apt; +BOOL WINAPI InternalIsProcessInitialized(void) { + struct apartment *apt; - if (!(apt = apartment_get_current_or_mta())) - return FALSE; - apartment_release(apt); + if (!(apt = apartment_get_current_or_mta())) + return FALSE; + apartment_release(apt); - return TRUE; + return TRUE; } /*********************************************************************** * InternalTlsAllocData (combase.@) */ -HRESULT WINAPI InternalTlsAllocData(struct tlsdata **data) -{ - if (!(*data = calloc(1, sizeof(**data)))) - return E_OUTOFMEMORY; +HRESULT WINAPI InternalTlsAllocData(struct tlsdata **data) { + if (!(*data = calloc(1, sizeof(**data)))) + return E_OUTOFMEMORY; - list_init(&(*data)->spies); - NtCurrentTeb()->ReservedForOle = *data; + list_init(&(*data)->spies); + NtCurrentTeb()->ReservedForOle = *data; - return S_OK; + return S_OK; } -static void com_cleanup_tlsdata(void) -{ - struct tlsdata *tlsdata = NtCurrentTeb()->ReservedForOle; - struct init_spy *cursor, *cursor2; +static void com_cleanup_tlsdata(void) { + struct tlsdata *tlsdata = NtCurrentTeb()->ReservedForOle; + struct init_spy *cursor, *cursor2; - if (!tlsdata) - return; + if (!tlsdata) + return; - if (tlsdata->apt) - apartment_release(tlsdata->apt); - if (tlsdata->implicit_mta_cookie) - apartment_decrement_mta_usage(tlsdata->implicit_mta_cookie); + if (tlsdata->apt) + apartment_release(tlsdata->apt); + if (tlsdata->implicit_mta_cookie) + apartment_decrement_mta_usage(tlsdata->implicit_mta_cookie); - if (tlsdata->errorinfo) - IErrorInfo_Release(tlsdata->errorinfo); - if (tlsdata->state) - IUnknown_Release(tlsdata->state); + if (tlsdata->errorinfo) + IErrorInfo_Release(tlsdata->errorinfo); + if (tlsdata->state) + IUnknown_Release(tlsdata->state); - LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &tlsdata->spies, struct init_spy, entry) - { - list_remove(&cursor->entry); - if (cursor->spy) - IInitializeSpy_Release(cursor->spy); - free(cursor); - } + LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &tlsdata->spies, struct init_spy, + entry) { + list_remove(&cursor->entry); + if (cursor->spy) + IInitializeSpy_Release(cursor->spy); + free(cursor); + } - if (tlsdata->context_token) - IObjContext_Release(tlsdata->context_token); + if (tlsdata->context_token) + IObjContext_Release(tlsdata->context_token); - free(tlsdata); - NtCurrentTeb()->ReservedForOle = NULL; + free(tlsdata); + NtCurrentTeb()->ReservedForOle = NULL; } -struct global_options -{ - IGlobalOptions IGlobalOptions_iface; - LONG refcount; +struct global_options { + IGlobalOptions IGlobalOptions_iface; + LONG refcount; }; -static inline struct global_options *impl_from_IGlobalOptions(IGlobalOptions *iface) -{ - return CONTAINING_RECORD(iface, struct global_options, IGlobalOptions_iface); +static inline struct global_options * +impl_from_IGlobalOptions(IGlobalOptions *iface) { + return CONTAINING_RECORD(iface, struct global_options, IGlobalOptions_iface); } -static HRESULT WINAPI global_options_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv) -{ - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv); +static HRESULT WINAPI global_options_QueryInterface(IGlobalOptions *iface, + REFIID riid, void **ppv) { + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv); - if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid)) - { - *ppv = iface; - } - else - { - *ppv = NULL; - return E_NOINTERFACE; - } + if (IsEqualGUID(&IID_IGlobalOptions, riid) || + IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = iface; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } - IUnknown_AddRef((IUnknown *)*ppv); - return S_OK; + IUnknown_AddRef((IUnknown *)*ppv); + return S_OK; } -static ULONG WINAPI global_options_AddRef(IGlobalOptions *iface) -{ - struct global_options *options = impl_from_IGlobalOptions(iface); - LONG refcount = InterlockedIncrement(&options->refcount); +static ULONG WINAPI global_options_AddRef(IGlobalOptions *iface) { + struct global_options *options = impl_from_IGlobalOptions(iface); + LONG refcount = InterlockedIncrement(&options->refcount); - TRACE("%p, refcount %ld.\n", iface, refcount); + TRACE("%p, refcount %ld.\n", iface, refcount); - return refcount; + return refcount; } -static ULONG WINAPI global_options_Release(IGlobalOptions *iface) -{ - struct global_options *options = impl_from_IGlobalOptions(iface); - LONG refcount = InterlockedDecrement(&options->refcount); +static ULONG WINAPI global_options_Release(IGlobalOptions *iface) { + struct global_options *options = impl_from_IGlobalOptions(iface); + LONG refcount = InterlockedDecrement(&options->refcount); - TRACE("%p, refcount %ld.\n", iface, refcount); + TRACE("%p, refcount %ld.\n", iface, refcount); - if (!refcount) - free(options); + if (!refcount) + free(options); - return refcount; + return refcount; } -static HRESULT WINAPI global_options_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value) -{ - FIXME("%p, %u, %Ix.\n", iface, property, value); +static HRESULT WINAPI global_options_Set(IGlobalOptions *iface, + GLOBALOPT_PROPERTIES property, + ULONG_PTR value) { + FIXME("%p, %u, %Ix.\n", iface, property, value); - return S_OK; + return S_OK; } -static HRESULT WINAPI global_options_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value) -{ - TRACE("%p, %u, %p.\n", iface, property, value); +static HRESULT WINAPI global_options_Query(IGlobalOptions *iface, + GLOBALOPT_PROPERTIES property, + ULONG_PTR *value) { + TRACE("%p, %u, %p.\n", iface, property, value); - if (property < COMGLB_EXCEPTION_HANDLING || property > COMGLB_PROPERTIES_RESERVED3) - return E_INVALIDARG; + if (property < COMGLB_EXCEPTION_HANDLING || + property > COMGLB_PROPERTIES_RESERVED3) + return E_INVALIDARG; - *value = global_options[property]; + *value = global_options[property]; - return S_OK; + return S_OK; } -static const IGlobalOptionsVtbl global_options_vtbl = -{ - global_options_QueryInterface, - global_options_AddRef, - global_options_Release, - global_options_Set, - global_options_Query -}; +static const IGlobalOptionsVtbl global_options_vtbl = { + global_options_QueryInterface, global_options_AddRef, + global_options_Release, global_options_Set, global_options_Query}; -static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) -{ - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv); +static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, + REFIID riid, void **ppv) { + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv); - if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) - { - *ppv = iface; - return S_OK; - } + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) { + *ppv = iface; + return S_OK; + } - *ppv = NULL; - return E_NOINTERFACE; + *ppv = NULL; + return E_NOINTERFACE; } -static ULONG WINAPI class_factory_AddRef(IClassFactory *iface) -{ - return 2; -} +static ULONG WINAPI class_factory_AddRef(IClassFactory *iface) { return 2; } -static ULONG WINAPI class_factory_Release(IClassFactory *iface) -{ - return 1; -} +static ULONG WINAPI class_factory_Release(IClassFactory *iface) { return 1; } -static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL fLock) -{ - TRACE("%d\n", fLock); +static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, + BOOL fLock) { + TRACE("%d\n", fLock); - return S_OK; + return S_OK; } -static HRESULT WINAPI global_options_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) -{ - struct global_options *object; - HRESULT hr; +static HRESULT WINAPI global_options_CreateInstance(IClassFactory *iface, + IUnknown *outer, + REFIID riid, void **ppv) { + struct global_options *object; + HRESULT hr; - TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), ppv); + TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), ppv); - if (outer) - return E_INVALIDARG; + if (outer) + return E_INVALIDARG; - if (!(object = malloc(sizeof(*object)))) - return E_OUTOFMEMORY; - object->IGlobalOptions_iface.lpVtbl = &global_options_vtbl; - object->refcount = 1; + if (!(object = malloc(sizeof(*object)))) + return E_OUTOFMEMORY; + object->IGlobalOptions_iface.lpVtbl = &global_options_vtbl; + object->refcount = 1; - hr = IGlobalOptions_QueryInterface(&object->IGlobalOptions_iface, riid, ppv); - IGlobalOptions_Release(&object->IGlobalOptions_iface); - return hr; + hr = IGlobalOptions_QueryInterface(&object->IGlobalOptions_iface, riid, ppv); + IGlobalOptions_Release(&object->IGlobalOptions_iface); + return hr; } -static const IClassFactoryVtbl global_options_factory_vtbl = -{ - class_factory_QueryInterface, - class_factory_AddRef, - class_factory_Release, - global_options_CreateInstance, - class_factory_LockServer -}; +static const IClassFactoryVtbl global_options_factory_vtbl = { + class_factory_QueryInterface, class_factory_AddRef, class_factory_Release, + global_options_CreateInstance, class_factory_LockServer}; -static IClassFactory global_options_factory = { &global_options_factory_vtbl }; +static IClassFactory global_options_factory = {&global_options_factory_vtbl}; -static HRESULT get_builtin_class_factory(REFCLSID rclsid, REFIID riid, void **obj) -{ - if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions)) - return IClassFactory_QueryInterface(&global_options_factory, riid, obj); - return E_UNEXPECTED; +static HRESULT get_builtin_class_factory(REFCLSID rclsid, REFIID riid, + void **obj) { + if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions)) + return IClassFactory_QueryInterface(&global_options_factory, riid, obj); + return E_UNEXPECTED; } /*********************************************************************** * FreePropVariantArray (combase.@) */ -HRESULT WINAPI FreePropVariantArray(ULONG count, PROPVARIANT *rgvars) -{ - ULONG i; - - TRACE("%lu, %p.\n", count, rgvars); - - if (!rgvars) - return E_INVALIDARG; - - for (i = 0; i < count; ++i) - PropVariantClear(&rgvars[i]); - +HRESULT WINAPI FreePropVariantArray(ULONG count, PROPVARIANT *rgvars) { + ULONG i; + + TRACE("%lu, %p.\n", count, rgvars); + + if (!rgvars) + return E_INVALIDARG; + + for (i = 0; i < count; ++i) + PropVariantClear(&rgvars[i]); + + return S_OK; +} + +static HRESULT propvar_validatetype(VARTYPE vt) { + switch (vt) { + case VT_EMPTY: + case VT_NULL: + case VT_I1: + case VT_I2: + case VT_I4: + case VT_I8: + case VT_R4: + case VT_R8: + case VT_CY: + case VT_DATE: + case VT_BSTR: + case VT_ERROR: + case VT_BOOL: + case VT_DECIMAL: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_UI8: + case VT_INT: + case VT_UINT: + case VT_LPSTR: + case VT_LPWSTR: + case VT_FILETIME: + case VT_BLOB: + case VT_DISPATCH: + case VT_UNKNOWN: + case VT_STREAM: + case VT_STORAGE: + case VT_STREAMED_OBJECT: + case VT_STORED_OBJECT: + case VT_BLOB_OBJECT: + case VT_CF: + case VT_CLSID: + case VT_I1 | VT_VECTOR: + case VT_I2 | VT_VECTOR: + case VT_I4 | VT_VECTOR: + case VT_I8 | VT_VECTOR: + case VT_R4 | VT_VECTOR: + case VT_R8 | VT_VECTOR: + case VT_CY | VT_VECTOR: + case VT_DATE | VT_VECTOR: + case VT_BSTR | VT_VECTOR: + case VT_ERROR | VT_VECTOR: + case VT_BOOL | VT_VECTOR: + case VT_VARIANT | VT_VECTOR: + case VT_UI1 | VT_VECTOR: + case VT_UI2 | VT_VECTOR: + case VT_UI4 | VT_VECTOR: + case VT_UI8 | VT_VECTOR: + case VT_LPSTR | VT_VECTOR: + case VT_LPWSTR | VT_VECTOR: + case VT_FILETIME | VT_VECTOR: + case VT_CF | VT_VECTOR: + case VT_CLSID | VT_VECTOR: + case VT_ARRAY | VT_I1: + case VT_ARRAY | VT_UI1: + case VT_ARRAY | VT_I2: + case VT_ARRAY | VT_UI2: + case VT_ARRAY | VT_I4: + case VT_ARRAY | VT_UI4: + case VT_ARRAY | VT_INT: + case VT_ARRAY | VT_UINT: + case VT_ARRAY | VT_R4: + case VT_ARRAY | VT_R8: + case VT_ARRAY | VT_CY: + case VT_ARRAY | VT_DATE: + case VT_ARRAY | VT_BSTR: + case VT_ARRAY | VT_BOOL: + case VT_ARRAY | VT_DECIMAL: + case VT_ARRAY | VT_DISPATCH: + case VT_ARRAY | VT_UNKNOWN: + case VT_ARRAY | VT_ERROR: + case VT_ARRAY | VT_VARIANT: return S_OK; + } + WARN("Bad type %d\n", vt); + return STG_E_INVALIDPARAMETER; } -static HRESULT propvar_validatetype(VARTYPE vt) -{ - switch (vt) - { - case VT_EMPTY: - case VT_NULL: - case VT_I1: - case VT_I2: - case VT_I4: - case VT_I8: - case VT_R4: - case VT_R8: - case VT_CY: - case VT_DATE: - case VT_BSTR: - case VT_ERROR: - case VT_BOOL: - case VT_DECIMAL: - case VT_UI1: - case VT_UI2: - case VT_UI4: - case VT_UI8: - case VT_INT: - case VT_UINT: - case VT_LPSTR: - case VT_LPWSTR: - case VT_FILETIME: - case VT_BLOB: - case VT_DISPATCH: - case VT_UNKNOWN: - case VT_STREAM: - case VT_STORAGE: - case VT_STREAMED_OBJECT: - case VT_STORED_OBJECT: - case VT_BLOB_OBJECT: - case VT_CF: - case VT_CLSID: - case VT_I1|VT_VECTOR: - case VT_I2|VT_VECTOR: - case VT_I4|VT_VECTOR: - case VT_I8|VT_VECTOR: - case VT_R4|VT_VECTOR: - case VT_R8|VT_VECTOR: - case VT_CY|VT_VECTOR: - case VT_DATE|VT_VECTOR: - case VT_BSTR|VT_VECTOR: - case VT_ERROR|VT_VECTOR: - case VT_BOOL|VT_VECTOR: - case VT_VARIANT|VT_VECTOR: - case VT_UI1|VT_VECTOR: - case VT_UI2|VT_VECTOR: - case VT_UI4|VT_VECTOR: - case VT_UI8|VT_VECTOR: - case VT_LPSTR|VT_VECTOR: - case VT_LPWSTR|VT_VECTOR: - case VT_FILETIME|VT_VECTOR: - case VT_CF|VT_VECTOR: - case VT_CLSID|VT_VECTOR: - case VT_ARRAY|VT_I1: - case VT_ARRAY|VT_UI1: - case VT_ARRAY|VT_I2: - case VT_ARRAY|VT_UI2: - case VT_ARRAY|VT_I4: - case VT_ARRAY|VT_UI4: - case VT_ARRAY|VT_INT: - case VT_ARRAY|VT_UINT: - case VT_ARRAY|VT_R4: - case VT_ARRAY|VT_R8: - case VT_ARRAY|VT_CY: - case VT_ARRAY|VT_DATE: - case VT_ARRAY|VT_BSTR: - case VT_ARRAY|VT_BOOL: - case VT_ARRAY|VT_DECIMAL: - case VT_ARRAY|VT_DISPATCH: - case VT_ARRAY|VT_UNKNOWN: - case VT_ARRAY|VT_ERROR: - case VT_ARRAY|VT_VARIANT: - return S_OK; - } - WARN("Bad type %d\n", vt); - return STG_E_INVALIDPARAMETER; -} - -static void propvar_free_cf_array(ULONG count, CLIPDATA *data) -{ - ULONG i; - for (i = 0; i < count; ++i) - CoTaskMemFree(data[i].pClipData); +static void propvar_free_cf_array(ULONG count, CLIPDATA *data) { + ULONG i; + for (i = 0; i < count; ++i) + CoTaskMemFree(data[i].pClipData); } /*********************************************************************** * PropVariantClear (combase.@) */ -HRESULT WINAPI PropVariantClear(PROPVARIANT *pvar) -{ - HRESULT hr; +HRESULT WINAPI PropVariantClear(PROPVARIANT *pvar) { + HRESULT hr; - TRACE("%p.\n", pvar); + TRACE("%p.\n", pvar); - if (!pvar) - return S_OK; - - hr = propvar_validatetype(pvar->vt); - if (FAILED(hr)) - { - memset(pvar, 0, sizeof(*pvar)); - return hr; - } + if (!pvar) + return S_OK; - switch (pvar->vt) - { - case VT_EMPTY: - case VT_NULL: - case VT_I1: - case VT_I2: - case VT_I4: - case VT_I8: - case VT_R4: - case VT_R8: - case VT_CY: - case VT_DATE: - case VT_ERROR: - case VT_BOOL: - case VT_DECIMAL: - case VT_UI1: - case VT_UI2: - case VT_UI4: - case VT_UI8: - case VT_INT: - case VT_UINT: - case VT_FILETIME: + hr = propvar_validatetype(pvar->vt); + if (FAILED(hr)) { + memset(pvar, 0, sizeof(*pvar)); + return hr; + } + + switch (pvar->vt) { + case VT_EMPTY: + case VT_NULL: + case VT_I1: + case VT_I2: + case VT_I4: + case VT_I8: + case VT_R4: + case VT_R8: + case VT_CY: + case VT_DATE: + case VT_ERROR: + case VT_BOOL: + case VT_DECIMAL: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_UI8: + case VT_INT: + case VT_UINT: + case VT_FILETIME: + break; + case VT_DISPATCH: + case VT_UNKNOWN: + case VT_STREAM: + case VT_STREAMED_OBJECT: + case VT_STORAGE: + case VT_STORED_OBJECT: + if (pvar->pStream) + IStream_Release(pvar->pStream); + break; + case VT_CLSID: + case VT_LPSTR: + case VT_LPWSTR: + /* pick an arbitrary typed pointer - we don't care about the type + * as we are just freeing it */ + CoTaskMemFree(pvar->puuid); + break; + case VT_BLOB: + case VT_BLOB_OBJECT: + CoTaskMemFree(pvar->blob.pBlobData); + break; + case VT_BSTR: + SysFreeString(pvar->bstrVal); + break; + case VT_CF: + if (pvar->pclipdata) { + propvar_free_cf_array(1, pvar->pclipdata); + CoTaskMemFree(pvar->pclipdata); + } + break; + default: + if (pvar->vt & VT_VECTOR) { + ULONG i; + + switch (pvar->vt & ~VT_VECTOR) { + case VT_VARIANT: + FreePropVariantArray(pvar->capropvar.cElems, pvar->capropvar.pElems); break; - case VT_DISPATCH: - case VT_UNKNOWN: - case VT_STREAM: - case VT_STREAMED_OBJECT: - case VT_STORAGE: - case VT_STORED_OBJECT: - if (pvar->pStream) - IStream_Release(pvar->pStream); + case VT_CF: + propvar_free_cf_array(pvar->caclipdata.cElems, pvar->caclipdata.pElems); break; - case VT_CLSID: - case VT_LPSTR: - case VT_LPWSTR: - /* pick an arbitrary typed pointer - we don't care about the type - * as we are just freeing it */ - CoTaskMemFree(pvar->puuid); + case VT_BSTR: + for (i = 0; i < pvar->cabstr.cElems; i++) + SysFreeString(pvar->cabstr.pElems[i]); break; - case VT_BLOB: - case VT_BLOB_OBJECT: - CoTaskMemFree(pvar->blob.pBlobData); + case VT_LPSTR: + for (i = 0; i < pvar->calpstr.cElems; i++) + CoTaskMemFree(pvar->calpstr.pElems[i]); break; - case VT_BSTR: - SysFreeString(pvar->bstrVal); + case VT_LPWSTR: + for (i = 0; i < pvar->calpwstr.cElems; i++) + CoTaskMemFree(pvar->calpwstr.pElems[i]); break; - case VT_CF: - if (pvar->pclipdata) - { - propvar_free_cf_array(1, pvar->pclipdata); - CoTaskMemFree(pvar->pclipdata); - } - break; - default: - if (pvar->vt & VT_VECTOR) - { - ULONG i; - - switch (pvar->vt & ~VT_VECTOR) - { - case VT_VARIANT: - FreePropVariantArray(pvar->capropvar.cElems, pvar->capropvar.pElems); - break; - case VT_CF: - propvar_free_cf_array(pvar->caclipdata.cElems, pvar->caclipdata.pElems); - break; - case VT_BSTR: - for (i = 0; i < pvar->cabstr.cElems; i++) - SysFreeString(pvar->cabstr.pElems[i]); - break; - case VT_LPSTR: - for (i = 0; i < pvar->calpstr.cElems; i++) - CoTaskMemFree(pvar->calpstr.pElems[i]); - break; - case VT_LPWSTR: - for (i = 0; i < pvar->calpwstr.cElems; i++) - CoTaskMemFree(pvar->calpwstr.pElems[i]); - break; - } - if (pvar->vt & ~VT_VECTOR) - { - /* pick an arbitrary VT_VECTOR structure - they all have the same - * memory layout */ - CoTaskMemFree(pvar->capropvar.pElems); - } - } - else if (pvar->vt & VT_ARRAY) - hr = SafeArrayDestroy(pvar->parray); - else - { - WARN("Invalid/unsupported type %d\n", pvar->vt); - hr = STG_E_INVALIDPARAMETER; - } + } + if (pvar->vt & ~VT_VECTOR) { + /* pick an arbitrary VT_VECTOR structure - they all have the same + * memory layout */ + CoTaskMemFree(pvar->capropvar.pElems); + } + } else if (pvar->vt & VT_ARRAY) + hr = SafeArrayDestroy(pvar->parray); + else { + WARN("Invalid/unsupported type %d\n", pvar->vt); + hr = STG_E_INVALIDPARAMETER; } + } - memset(pvar, 0, sizeof(*pvar)); - return hr; + memset(pvar, 0, sizeof(*pvar)); + return hr; } /*********************************************************************** * PropVariantCopy (combase.@) */ -HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, const PROPVARIANT *pvarSrc) -{ - ULONG len; - HRESULT hr; - - TRACE("%p, %p vt %04x.\n", pvarDest, pvarSrc, pvarSrc->vt); - - hr = propvar_validatetype(pvarSrc->vt); - if (FAILED(hr)) - return DISP_E_BADVARTYPE; - - /* this will deal with most cases */ - *pvarDest = *pvarSrc; - - switch (pvarSrc->vt) - { - case VT_EMPTY: - case VT_NULL: - case VT_I1: - case VT_UI1: - case VT_I2: - case VT_UI2: - case VT_BOOL: - case VT_DECIMAL: - case VT_I4: - case VT_UI4: - case VT_R4: - case VT_ERROR: - case VT_I8: - case VT_UI8: - case VT_INT: - case VT_UINT: - case VT_R8: - case VT_CY: - case VT_DATE: - case VT_FILETIME: +HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, + const PROPVARIANT *pvarSrc) { + ULONG len; + HRESULT hr; + + TRACE("%p, %p vt %04x.\n", pvarDest, pvarSrc, pvarSrc->vt); + + hr = propvar_validatetype(pvarSrc->vt); + if (FAILED(hr)) + return DISP_E_BADVARTYPE; + + /* this will deal with most cases */ + *pvarDest = *pvarSrc; + + switch (pvarSrc->vt) { + case VT_EMPTY: + case VT_NULL: + case VT_I1: + case VT_UI1: + case VT_I2: + case VT_UI2: + case VT_BOOL: + case VT_DECIMAL: + case VT_I4: + case VT_UI4: + case VT_R4: + case VT_ERROR: + case VT_I8: + case VT_UI8: + case VT_INT: + case VT_UINT: + case VT_R8: + case VT_CY: + case VT_DATE: + case VT_FILETIME: + break; + case VT_DISPATCH: + case VT_UNKNOWN: + case VT_STREAM: + case VT_STREAMED_OBJECT: + case VT_STORAGE: + case VT_STORED_OBJECT: + if (pvarDest->pStream) + IStream_AddRef(pvarDest->pStream); + break; + case VT_CLSID: + pvarDest->puuid = CoTaskMemAlloc(sizeof(CLSID)); + *pvarDest->puuid = *pvarSrc->puuid; + break; + case VT_LPSTR: + if (pvarSrc->pszVal) { + len = strlen(pvarSrc->pszVal); + pvarDest->pszVal = CoTaskMemAlloc((len + 1) * sizeof(CHAR)); + CopyMemory(pvarDest->pszVal, pvarSrc->pszVal, (len + 1) * sizeof(CHAR)); + } + break; + case VT_LPWSTR: + if (pvarSrc->pwszVal) { + len = lstrlenW(pvarSrc->pwszVal); + pvarDest->pwszVal = CoTaskMemAlloc((len + 1) * sizeof(WCHAR)); + CopyMemory(pvarDest->pwszVal, pvarSrc->pwszVal, + (len + 1) * sizeof(WCHAR)); + } + break; + case VT_BLOB: + case VT_BLOB_OBJECT: + if (pvarSrc->blob.pBlobData) { + len = pvarSrc->blob.cbSize; + pvarDest->blob.pBlobData = CoTaskMemAlloc(len); + CopyMemory(pvarDest->blob.pBlobData, pvarSrc->blob.pBlobData, len); + } + break; + case VT_BSTR: + pvarDest->bstrVal = SysAllocString(pvarSrc->bstrVal); + break; + case VT_CF: + if (pvarSrc->pclipdata) { + len = pvarSrc->pclipdata->cbSize - sizeof(pvarSrc->pclipdata->ulClipFmt); + pvarDest->pclipdata = CoTaskMemAlloc(sizeof(CLIPDATA)); + pvarDest->pclipdata->cbSize = pvarSrc->pclipdata->cbSize; + pvarDest->pclipdata->ulClipFmt = pvarSrc->pclipdata->ulClipFmt; + pvarDest->pclipdata->pClipData = CoTaskMemAlloc(len); + CopyMemory(pvarDest->pclipdata->pClipData, pvarSrc->pclipdata->pClipData, + len); + } + break; + default: + if (pvarSrc->vt & VT_VECTOR) { + int elemSize; + ULONG i; + + switch (pvarSrc->vt & ~VT_VECTOR) { + case VT_I1: + elemSize = sizeof(pvarSrc->cVal); break; - case VT_DISPATCH: - case VT_UNKNOWN: - case VT_STREAM: - case VT_STREAMED_OBJECT: - case VT_STORAGE: - case VT_STORED_OBJECT: - if (pvarDest->pStream) - IStream_AddRef(pvarDest->pStream); + case VT_UI1: + elemSize = sizeof(pvarSrc->bVal); break; - case VT_CLSID: - pvarDest->puuid = CoTaskMemAlloc(sizeof(CLSID)); - *pvarDest->puuid = *pvarSrc->puuid; + case VT_I2: + elemSize = sizeof(pvarSrc->iVal); break; - case VT_LPSTR: - if (pvarSrc->pszVal) - { - len = strlen(pvarSrc->pszVal); - pvarDest->pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR)); - CopyMemory(pvarDest->pszVal, pvarSrc->pszVal, (len+1)*sizeof(CHAR)); - } + case VT_UI2: + elemSize = sizeof(pvarSrc->uiVal); break; - case VT_LPWSTR: - if (pvarSrc->pwszVal) - { - len = lstrlenW(pvarSrc->pwszVal); - pvarDest->pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR)); - CopyMemory(pvarDest->pwszVal, pvarSrc->pwszVal, (len+1)*sizeof(WCHAR)); - } + case VT_BOOL: + elemSize = sizeof(pvarSrc->boolVal); break; - case VT_BLOB: - case VT_BLOB_OBJECT: - if (pvarSrc->blob.pBlobData) - { - len = pvarSrc->blob.cbSize; - pvarDest->blob.pBlobData = CoTaskMemAlloc(len); - CopyMemory(pvarDest->blob.pBlobData, pvarSrc->blob.pBlobData, len); - } + case VT_I4: + elemSize = sizeof(pvarSrc->lVal); break; - case VT_BSTR: - pvarDest->bstrVal = SysAllocString(pvarSrc->bstrVal); + case VT_UI4: + elemSize = sizeof(pvarSrc->ulVal); break; - case VT_CF: - if (pvarSrc->pclipdata) - { - len = pvarSrc->pclipdata->cbSize - sizeof(pvarSrc->pclipdata->ulClipFmt); - pvarDest->pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA)); - pvarDest->pclipdata->cbSize = pvarSrc->pclipdata->cbSize; - pvarDest->pclipdata->ulClipFmt = pvarSrc->pclipdata->ulClipFmt; - pvarDest->pclipdata->pClipData = CoTaskMemAlloc(len); - CopyMemory(pvarDest->pclipdata->pClipData, pvarSrc->pclipdata->pClipData, len); - } + case VT_R4: + elemSize = sizeof(pvarSrc->fltVal); break; - default: - if (pvarSrc->vt & VT_VECTOR) - { - int elemSize; - ULONG i; - - switch (pvarSrc->vt & ~VT_VECTOR) - { - case VT_I1: elemSize = sizeof(pvarSrc->cVal); break; - case VT_UI1: elemSize = sizeof(pvarSrc->bVal); break; - case VT_I2: elemSize = sizeof(pvarSrc->iVal); break; - case VT_UI2: elemSize = sizeof(pvarSrc->uiVal); break; - case VT_BOOL: elemSize = sizeof(pvarSrc->boolVal); break; - case VT_I4: elemSize = sizeof(pvarSrc->lVal); break; - case VT_UI4: elemSize = sizeof(pvarSrc->ulVal); break; - case VT_R4: elemSize = sizeof(pvarSrc->fltVal); break; - case VT_R8: elemSize = sizeof(pvarSrc->dblVal); break; - case VT_ERROR: elemSize = sizeof(pvarSrc->scode); break; - case VT_I8: elemSize = sizeof(pvarSrc->hVal); break; - case VT_UI8: elemSize = sizeof(pvarSrc->uhVal); break; - case VT_CY: elemSize = sizeof(pvarSrc->cyVal); break; - case VT_DATE: elemSize = sizeof(pvarSrc->date); break; - case VT_FILETIME: elemSize = sizeof(pvarSrc->filetime); break; - case VT_CLSID: elemSize = sizeof(*pvarSrc->puuid); break; - case VT_CF: elemSize = sizeof(*pvarSrc->pclipdata); break; - case VT_BSTR: elemSize = sizeof(pvarSrc->bstrVal); break; - case VT_LPSTR: elemSize = sizeof(pvarSrc->pszVal); break; - case VT_LPWSTR: elemSize = sizeof(pvarSrc->pwszVal); break; - case VT_VARIANT: elemSize = sizeof(*pvarSrc->pvarVal); break; - - default: - FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR); - return E_INVALIDARG; - } - len = pvarSrc->capropvar.cElems; - pvarDest->capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL; - if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT)) - { - for (i = 0; i < len; i++) - PropVariantCopy(&pvarDest->capropvar.pElems[i], &pvarSrc->capropvar.pElems[i]); - } - else if (pvarSrc->vt == (VT_VECTOR | VT_CF)) - { - FIXME("Copy clipformats\n"); - } - else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR)) - { - for (i = 0; i < len; i++) - pvarDest->cabstr.pElems[i] = SysAllocString(pvarSrc->cabstr.pElems[i]); - } - else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR)) - { - size_t strLen; - for (i = 0; i < len; i++) - { - strLen = lstrlenA(pvarSrc->calpstr.pElems[i]) + 1; - pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen); - memcpy(pvarDest->calpstr.pElems[i], - pvarSrc->calpstr.pElems[i], strLen); - } - } - else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR)) - { - size_t strLen; - for (i = 0; i < len; i++) - { - strLen = (lstrlenW(pvarSrc->calpwstr.pElems[i]) + 1) * - sizeof(WCHAR); - pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen); - memcpy(pvarDest->calpstr.pElems[i], - pvarSrc->calpstr.pElems[i], strLen); - } - } - else - CopyMemory(pvarDest->capropvar.pElems, pvarSrc->capropvar.pElems, len * elemSize); + case VT_R8: + elemSize = sizeof(pvarSrc->dblVal); + break; + case VT_ERROR: + elemSize = sizeof(pvarSrc->scode); + break; + case VT_I8: + elemSize = sizeof(pvarSrc->hVal); + break; + case VT_UI8: + elemSize = sizeof(pvarSrc->uhVal); + break; + case VT_CY: + elemSize = sizeof(pvarSrc->cyVal); + break; + case VT_DATE: + elemSize = sizeof(pvarSrc->date); + break; + case VT_FILETIME: + elemSize = sizeof(pvarSrc->filetime); + break; + case VT_CLSID: + elemSize = sizeof(*pvarSrc->puuid); + break; + case VT_CF: + elemSize = sizeof(*pvarSrc->pclipdata); + break; + case VT_BSTR: + elemSize = sizeof(pvarSrc->bstrVal); + break; + case VT_LPSTR: + elemSize = sizeof(pvarSrc->pszVal); + break; + case VT_LPWSTR: + elemSize = sizeof(pvarSrc->pwszVal); + break; + case VT_VARIANT: + elemSize = sizeof(*pvarSrc->pvarVal); + break; + + default: + FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR); + return E_INVALIDARG; + } + len = pvarSrc->capropvar.cElems; + pvarDest->capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL; + if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT)) { + for (i = 0; i < len; i++) + PropVariantCopy(&pvarDest->capropvar.pElems[i], + &pvarSrc->capropvar.pElems[i]); + } else if (pvarSrc->vt == (VT_VECTOR | VT_CF)) { + FIXME("Copy clipformats\n"); + } else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR)) { + for (i = 0; i < len; i++) + pvarDest->cabstr.pElems[i] = + SysAllocString(pvarSrc->cabstr.pElems[i]); + } else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR)) { + size_t strLen; + for (i = 0; i < len; i++) { + strLen = lstrlenA(pvarSrc->calpstr.pElems[i]) + 1; + pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen); + memcpy(pvarDest->calpstr.pElems[i], pvarSrc->calpstr.pElems[i], + strLen); } - else if (pvarSrc->vt & VT_ARRAY) - { - pvarDest->uhVal.QuadPart = 0; - return SafeArrayCopy(pvarSrc->parray, &pvarDest->parray); + } else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR)) { + size_t strLen; + for (i = 0; i < len; i++) { + strLen = (lstrlenW(pvarSrc->calpwstr.pElems[i]) + 1) * sizeof(WCHAR); + pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen); + memcpy(pvarDest->calpstr.pElems[i], pvarSrc->calpstr.pElems[i], + strLen); } - else - WARN("Invalid/unsupported type %d\n", pvarSrc->vt); - } + } else + CopyMemory(pvarDest->capropvar.pElems, pvarSrc->capropvar.pElems, + len * elemSize); + } else if (pvarSrc->vt & VT_ARRAY) { + pvarDest->uhVal.QuadPart = 0; + return SafeArrayCopy(pvarSrc->parray, &pvarDest->parray); + } else + WARN("Invalid/unsupported type %d\n", pvarSrc->vt); + } - return S_OK; + return S_OK; } /*********************************************************************** * CoFileTimeNow (combase.@) */ -HRESULT WINAPI CoFileTimeNow(FILETIME *filetime) -{ - GetSystemTimeAsFileTime(filetime); - return S_OK; +HRESULT WINAPI CoFileTimeNow(FILETIME *filetime) { + GetSystemTimeAsFileTime(filetime); + return S_OK; } /****************************************************************************** * CoCreateGuid (combase.@) */ -HRESULT WINAPI CoCreateGuid(GUID *guid) -{ - RPC_STATUS status; +HRESULT WINAPI CoCreateGuid(GUID *guid) { + RPC_STATUS status; - if (!guid) return E_INVALIDARG; + if (!guid) + return E_INVALIDARG; - status = UuidCreate(guid); - if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK; - return HRESULT_FROM_WIN32(status); + status = UuidCreate(guid); + if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) + return S_OK; + return HRESULT_FROM_WIN32(status); } /****************************************************************************** * CoQueryProxyBlanket (combase.@) */ HRESULT WINAPI CoQueryProxyBlanket(IUnknown *proxy, DWORD *authn_service, - DWORD *authz_service, OLECHAR **servername, DWORD *authn_level, - DWORD *imp_level, void **auth_info, DWORD *capabilities) -{ - IClientSecurity *client_security; - HRESULT hr; - - TRACE("%p, %p, %p, %p, %p, %p, %p, %p.\n", proxy, authn_service, authz_service, servername, authn_level, imp_level, - auth_info, capabilities); - - hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security); - if (SUCCEEDED(hr)) - { - hr = IClientSecurity_QueryBlanket(client_security, proxy, authn_service, authz_service, servername, - authn_level, imp_level, auth_info, capabilities); - IClientSecurity_Release(client_security); - } - - if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr); - return hr; + DWORD *authz_service, OLECHAR **servername, + DWORD *authn_level, DWORD *imp_level, + void **auth_info, DWORD *capabilities) { + IClientSecurity *client_security; + HRESULT hr; + + TRACE("%p, %p, %p, %p, %p, %p, %p, %p.\n", proxy, authn_service, + authz_service, servername, authn_level, imp_level, auth_info, + capabilities); + + hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, + (void **)&client_security); + if (SUCCEEDED(hr)) { + hr = IClientSecurity_QueryBlanket(client_security, proxy, authn_service, + authz_service, servername, authn_level, + imp_level, auth_info, capabilities); + IClientSecurity_Release(client_security); + } + + if (FAILED(hr)) + ERR("-- failed with %#lx.\n", hr); + return hr; } /****************************************************************************** * CoSetProxyBlanket (combase.@) */ -HRESULT WINAPI CoSetProxyBlanket(IUnknown *proxy, DWORD authn_service, DWORD authz_service, - OLECHAR *servername, DWORD authn_level, DWORD imp_level, void *auth_info, DWORD capabilities) -{ - IClientSecurity *client_security; - HRESULT hr; +HRESULT WINAPI CoSetProxyBlanket(IUnknown *proxy, DWORD authn_service, + DWORD authz_service, OLECHAR *servername, + DWORD authn_level, DWORD imp_level, + void *auth_info, DWORD capabilities) { + IClientSecurity *client_security; + HRESULT hr; - TRACE("%p, %lu, %lu, %p, %lu, %lu, %p, %#lx.\n", proxy, authn_service, authz_service, servername, - authn_level, imp_level, auth_info, capabilities); + TRACE("%p, %lu, %lu, %p, %lu, %lu, %p, %#lx.\n", proxy, authn_service, + authz_service, servername, authn_level, imp_level, auth_info, + capabilities); - hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security); - if (SUCCEEDED(hr)) - { - hr = IClientSecurity_SetBlanket(client_security, proxy, authn_service, authz_service, servername, authn_level, - imp_level, auth_info, capabilities); - IClientSecurity_Release(client_security); - } + hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, + (void **)&client_security); + if (SUCCEEDED(hr)) { + hr = IClientSecurity_SetBlanket(client_security, proxy, authn_service, + authz_service, servername, authn_level, + imp_level, auth_info, capabilities); + IClientSecurity_Release(client_security); + } - if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr); - return hr; + if (FAILED(hr)) + ERR("-- failed with %#lx.\n", hr); + return hr; } /*********************************************************************** * CoCopyProxy (combase.@) */ -HRESULT WINAPI CoCopyProxy(IUnknown *proxy, IUnknown **proxy_copy) -{ - IClientSecurity *client_security; - HRESULT hr; +HRESULT WINAPI CoCopyProxy(IUnknown *proxy, IUnknown **proxy_copy) { + IClientSecurity *client_security; + HRESULT hr; - TRACE("%p, %p.\n", proxy, proxy_copy); + TRACE("%p, %p.\n", proxy, proxy_copy); - hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security); - if (SUCCEEDED(hr)) - { - hr = IClientSecurity_CopyProxy(client_security, proxy, proxy_copy); - IClientSecurity_Release(client_security); - } + hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, + (void **)&client_security); + if (SUCCEEDED(hr)) { + hr = IClientSecurity_CopyProxy(client_security, proxy, proxy_copy); + IClientSecurity_Release(client_security); + } - if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr); - return hr; + if (FAILED(hr)) + ERR("-- failed with %#lx.\n", hr); + return hr; } /*********************************************************************** * CoQueryClientBlanket (combase.@) */ -HRESULT WINAPI CoQueryClientBlanket(DWORD *authn_service, DWORD *authz_service, OLECHAR **servername, - DWORD *authn_level, DWORD *imp_level, RPC_AUTHZ_HANDLE *privs, DWORD *capabilities) -{ - IServerSecurity *server_security; - HRESULT hr; +HRESULT WINAPI CoQueryClientBlanket(DWORD *authn_service, DWORD *authz_service, + OLECHAR **servername, DWORD *authn_level, + DWORD *imp_level, RPC_AUTHZ_HANDLE *privs, + DWORD *capabilities) { + IServerSecurity *server_security; + HRESULT hr; - TRACE("%p, %p, %p, %p, %p, %p, %p.\n", authn_service, authz_service, servername, authn_level, imp_level, - privs, capabilities); + TRACE("%p, %p, %p, %p, %p, %p, %p.\n", authn_service, authz_service, + servername, authn_level, imp_level, privs, capabilities); - hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security); - if (SUCCEEDED(hr)) - { - hr = IServerSecurity_QueryBlanket(server_security, authn_service, authz_service, servername, authn_level, - imp_level, privs, capabilities); - IServerSecurity_Release(server_security); - } + hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security); + if (SUCCEEDED(hr)) { + hr = IServerSecurity_QueryBlanket(server_security, authn_service, + authz_service, servername, authn_level, + imp_level, privs, capabilities); + IServerSecurity_Release(server_security); + } - return hr; + return hr; } /*********************************************************************** * CoImpersonateClient (combase.@) */ -HRESULT WINAPI CoImpersonateClient(void) -{ - IServerSecurity *server_security; - HRESULT hr; +HRESULT WINAPI CoImpersonateClient(void) { + IServerSecurity *server_security; + HRESULT hr; - TRACE("\n"); + TRACE("\n"); - hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security); - if (SUCCEEDED(hr)) - { - hr = IServerSecurity_ImpersonateClient(server_security); - IServerSecurity_Release(server_security); - } + hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security); + if (SUCCEEDED(hr)) { + hr = IServerSecurity_ImpersonateClient(server_security); + IServerSecurity_Release(server_security); + } - return hr; + return hr; } /*********************************************************************** * CoRevertToSelf (combase.@) */ -HRESULT WINAPI CoRevertToSelf(void) -{ - IServerSecurity *server_security; - HRESULT hr; +HRESULT WINAPI CoRevertToSelf(void) { + IServerSecurity *server_security; + HRESULT hr; - TRACE("\n"); + TRACE("\n"); - hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security); - if (SUCCEEDED(hr)) - { - hr = IServerSecurity_RevertToSelf(server_security); - IServerSecurity_Release(server_security); - } + hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security); + if (SUCCEEDED(hr)) { + hr = IServerSecurity_RevertToSelf(server_security); + IServerSecurity_Release(server_security); + } - return hr; + return hr; } /*********************************************************************** * CoInitializeSecurity (combase.@) */ HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR sd, LONG cAuthSvc, - SOLE_AUTHENTICATION_SERVICE *asAuthSvc, void *reserved1, DWORD authn_level, - DWORD imp_level, void *reserved2, DWORD capabilities, void *reserved3) -{ - FIXME("%p, %ld, %p, %p, %ld, %ld, %p, %ld, %p stub\n", sd, cAuthSvc, asAuthSvc, reserved1, authn_level, - imp_level, reserved2, capabilities, reserved3); + SOLE_AUTHENTICATION_SERVICE *asAuthSvc, + void *reserved1, DWORD authn_level, + DWORD imp_level, void *reserved2, + DWORD capabilities, void *reserved3) { + FIXME("%p, %ld, %p, %p, %ld, %ld, %p, %ld, %p stub\n", sd, cAuthSvc, + asAuthSvc, reserved1, authn_level, imp_level, reserved2, capabilities, + reserved3); - return S_OK; + return S_OK; } /*********************************************************************** * CoGetObjectContext (combase.@) */ -HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv) -{ - IObjContext *context; - HRESULT hr; +HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv) { + IObjContext *context; + HRESULT hr; - TRACE("%s, %p.\n", debugstr_guid(riid), ppv); + TRACE("%s, %p.\n", debugstr_guid(riid), ppv); - *ppv = NULL; - hr = CoGetContextToken((ULONG_PTR *)&context); - if (FAILED(hr)) - return hr; + *ppv = NULL; + hr = CoGetContextToken((ULONG_PTR *)&context); + if (FAILED(hr)) + return hr; - return IObjContext_QueryInterface(context, riid, ppv); + return IObjContext_QueryInterface(context, riid, ppv); } /*********************************************************************** * CoGetDefaultContext (combase.@) */ -HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, void **obj) -{ - FIXME("%d, %s, %p stub\n", type, debugstr_guid(riid), obj); +HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, void **obj) { + FIXME("%d, %s, %p stub\n", type, debugstr_guid(riid), obj); - return E_NOINTERFACE; + return E_NOINTERFACE; } /*********************************************************************** * CoGetCallState (combase.@) */ -HRESULT WINAPI CoGetCallState(int arg1, ULONG *arg2) -{ - FIXME("%d, %p.\n", arg1, arg2); +HRESULT WINAPI CoGetCallState(int arg1, ULONG *arg2) { + FIXME("%d, %p.\n", arg1, arg2); - return E_NOTIMPL; + return E_NOTIMPL; } /*********************************************************************** * CoGetActivationState (combase.@) */ -HRESULT WINAPI CoGetActivationState(GUID guid, DWORD arg2, DWORD *arg3) -{ - FIXME("%s, %lx, %p.\n", debugstr_guid(&guid), arg2, arg3); +HRESULT WINAPI CoGetActivationState(GUID guid, DWORD arg2, DWORD *arg3) { + FIXME("%s, %lx, %p.\n", debugstr_guid(&guid), arg2, arg3); - return E_NOTIMPL; + return E_NOTIMPL; } /****************************************************************************** * CoGetTreatAsClass (combase.@) */ -HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, CLSID *clsidNew) -{ - WCHAR buffW[CHARS_IN_GUID]; - LONG len = sizeof(buffW); - HRESULT hr = S_OK; - HKEY hkey = NULL; +HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, CLSID *clsidNew) { + WCHAR buffW[CHARS_IN_GUID]; + LONG len = sizeof(buffW); + HRESULT hr = S_OK; + HKEY hkey = NULL; - TRACE("%s, %p.\n", debugstr_guid(clsidOld), clsidNew); + TRACE("%s, %p.\n", debugstr_guid(clsidOld), clsidNew); - if (!clsidOld || !clsidNew) - return E_INVALIDARG; + if (!clsidOld || !clsidNew) + return E_INVALIDARG; - *clsidNew = *clsidOld; + *clsidNew = *clsidOld; - hr = open_key_for_clsid(clsidOld, L"TreatAs", KEY_READ, &hkey); - if (FAILED(hr)) - { - hr = S_FALSE; - goto done; - } + hr = open_key_for_clsid(clsidOld, L"TreatAs", KEY_READ, &hkey); + if (FAILED(hr)) { + hr = S_FALSE; + goto done; + } - if (RegQueryValueW(hkey, NULL, buffW, &len)) - { - hr = S_FALSE; - goto done; - } + if (RegQueryValueW(hkey, NULL, buffW, &len)) { + hr = S_FALSE; + goto done; + } - hr = CLSIDFromString(buffW, clsidNew); - if (FAILED(hr)) - ERR("Failed to get CLSID from string %s, hr %#lx.\n", debugstr_w(buffW), hr); + hr = CLSIDFromString(buffW, clsidNew); + if (FAILED(hr)) + ERR("Failed to get CLSID from string %s, hr %#lx.\n", debugstr_w(buffW), + hr); done: - if (hkey) RegCloseKey(hkey); - return hr; + if (hkey) + RegCloseKey(hkey); + return hr; } /****************************************************************************** * ProgIDFromCLSID (combase.@) */ -HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *progid) -{ - ACTCTX_SECTION_KEYED_DATA data; - LONG progidlen = 0; - HKEY hkey; - REGSAM opposite = (sizeof(void *) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY; - BOOL is_wow64; - HRESULT hr; - - if (!progid) - return E_INVALIDARG; - - *progid = NULL; +HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, + LPOLESTR *progid) { + ACTCTX_SECTION_KEYED_DATA data; + LONG progidlen = 0; + HKEY hkey; + REGSAM opposite = + (sizeof(void *) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY; + BOOL is_wow64; + HRESULT hr; + + if (!progid) + return E_INVALIDARG; + + *progid = NULL; + + data.cbSize = sizeof(data); + if (FindActCtxSectionGuid(0, NULL, + ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, + clsid, &data)) { + struct comclassredirect_data *comclass = + (struct comclassredirect_data *)data.lpData; + if (comclass->progid_len) { + WCHAR *ptrW; + + *progid = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR)); + if (!*progid) + return E_OUTOFMEMORY; - data.cbSize = sizeof(data); - if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, - clsid, &data)) - { - struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData; - if (comclass->progid_len) - { - WCHAR *ptrW; - - *progid = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR)); - if (!*progid) return E_OUTOFMEMORY; - - ptrW = (WCHAR *)((BYTE *)comclass + comclass->progid_offset); - memcpy(*progid, ptrW, comclass->progid_len + sizeof(WCHAR)); - return S_OK; - } - else - return REGDB_E_CLASSNOTREG; - } + ptrW = (WCHAR *)((BYTE *)comclass + comclass->progid_offset); + memcpy(*progid, ptrW, comclass->progid_len + sizeof(WCHAR)); + return S_OK; + } else + return REGDB_E_CLASSNOTREG; + } + + hr = open_key_for_clsid(clsid, L"ProgID", KEY_READ, &hkey); + if (FAILED(hr) && + (opposite == KEY_WOW64_32KEY || + (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64))) { + hr = open_key_for_clsid(clsid, L"ProgID", opposite | KEY_READ, &hkey); + if (FAILED(hr)) + return hr; + } - hr = open_key_for_clsid(clsid, L"ProgID", KEY_READ, &hkey); - if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64))) - { - hr = open_key_for_clsid(clsid, L"ProgID", opposite | KEY_READ, &hkey); - if (FAILED(hr)) - return hr; - } + if (RegQueryValueW(hkey, NULL, NULL, &progidlen)) + hr = REGDB_E_CLASSNOTREG; - if (RegQueryValueW(hkey, NULL, NULL, &progidlen)) + if (hr == S_OK) { + *progid = CoTaskMemAlloc(progidlen * sizeof(WCHAR)); + if (*progid) { + if (RegQueryValueW(hkey, NULL, *progid, &progidlen)) { hr = REGDB_E_CLASSNOTREG; + CoTaskMemFree(*progid); + *progid = NULL; + } + } else + hr = E_OUTOFMEMORY; + } - if (hr == S_OK) - { - *progid = CoTaskMemAlloc(progidlen * sizeof(WCHAR)); - if (*progid) - { - if (RegQueryValueW(hkey, NULL, *progid, &progidlen)) - { - hr = REGDB_E_CLASSNOTREG; - CoTaskMemFree(*progid); - *progid = NULL; - } - } - else - hr = E_OUTOFMEMORY; - } - - RegCloseKey(hkey); - return hr; + RegCloseKey(hkey); + return hr; } -static inline BOOL is_valid_hex(WCHAR c) -{ - if (!(((c >= '0') && (c <= '9')) || - ((c >= 'a') && (c <= 'f')) || - ((c >= 'A') && (c <= 'F')))) - return FALSE; - return TRUE; +static inline BOOL is_valid_hex(WCHAR c) { + if (!(((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || + ((c >= 'A') && (c <= 'F')))) + return FALSE; + return TRUE; } -static const BYTE guid_conv_table[256] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */ +static const BYTE guid_conv_table[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */ 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */ 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */ }; -static BOOL guid_from_string(LPCWSTR s, GUID *id) -{ - int i; +static BOOL guid_from_string(LPCWSTR s, GUID *id) { + int i; - if (!s || s[0] != '{') - { - memset(id, 0, sizeof(*id)); - if (!s) return TRUE; - return FALSE; - } + if (!s || s[0] != '{') { + memset(id, 0, sizeof(*id)); + if (!s) + return TRUE; + return FALSE; + } - TRACE("%s -> %p\n", debugstr_w(s), id); + TRACE("%s -> %p\n", debugstr_w(s), id); - /* In form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ + /* In form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ - id->Data1 = 0; - for (i = 1; i < 9; ++i) - { - if (!is_valid_hex(s[i])) return FALSE; - id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]]; - } - if (s[9] != '-') return FALSE; + id->Data1 = 0; + for (i = 1; i < 9; ++i) { + if (!is_valid_hex(s[i])) + return FALSE; + id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]]; + } + if (s[9] != '-') + return FALSE; - id->Data2 = 0; - for (i = 10; i < 14; ++i) - { - if (!is_valid_hex(s[i])) return FALSE; - id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]]; - } - if (s[14] != '-') return FALSE; + id->Data2 = 0; + for (i = 10; i < 14; ++i) { + if (!is_valid_hex(s[i])) + return FALSE; + id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]]; + } + if (s[14] != '-') + return FALSE; - id->Data3 = 0; - for (i = 15; i < 19; ++i) - { - if (!is_valid_hex(s[i])) return FALSE; - id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]]; - } - if (s[19] != '-') return FALSE; - - for (i = 20; i < 37; i += 2) - { - if (i == 24) - { - if (s[i] != '-') return FALSE; - i++; - } - if (!is_valid_hex(s[i]) || !is_valid_hex(s[i + 1])) return FALSE; - id->Data4[(i - 20) / 2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i + 1]]; + id->Data3 = 0; + for (i = 15; i < 19; ++i) { + if (!is_valid_hex(s[i])) + return FALSE; + id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]]; + } + if (s[19] != '-') + return FALSE; + + for (i = 20; i < 37; i += 2) { + if (i == 24) { + if (s[i] != '-') + return FALSE; + i++; } + if (!is_valid_hex(s[i]) || !is_valid_hex(s[i + 1])) + return FALSE; + id->Data4[(i - 20) / 2] = + guid_conv_table[s[i]] << 4 | guid_conv_table[s[i + 1]]; + } - if (s[37] == '}' && s[38] == '\0') - return TRUE; + if (s[37] == '}' && s[38] == '\0') + return TRUE; - return FALSE; + return FALSE; } -static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) -{ - WCHAR buf2[CHARS_IN_GUID]; - LONG buf2len = sizeof(buf2); - HKEY xhkey; - WCHAR *buf; - - memset(clsid, 0, sizeof(*clsid)); - buf = malloc((lstrlenW(progid) + 8) * sizeof(WCHAR)); - if (!buf) return E_OUTOFMEMORY; - - lstrcpyW(buf, progid); - lstrcatW(buf, L"\\CLSID"); - if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey)) - { - free(buf); - WARN("couldn't open key for ProgID %s\n", debugstr_w(progid)); - return CO_E_CLASSSTRING; - } +static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) { + WCHAR buf2[CHARS_IN_GUID]; + LONG buf2len = sizeof(buf2); + HKEY xhkey; + WCHAR *buf; + + memset(clsid, 0, sizeof(*clsid)); + buf = malloc((lstrlenW(progid) + 8) * sizeof(WCHAR)); + if (!buf) + return E_OUTOFMEMORY; + + lstrcpyW(buf, progid); + lstrcatW(buf, L"\\CLSID"); + if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey)) { free(buf); + WARN("couldn't open key for ProgID %s\n", debugstr_w(progid)); + return CO_E_CLASSSTRING; + } + free(buf); - if (RegQueryValueW(xhkey, NULL, buf2, &buf2len)) - { - RegCloseKey(xhkey); - WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid)); - return CO_E_CLASSSTRING; - } + if (RegQueryValueW(xhkey, NULL, buf2, &buf2len)) { RegCloseKey(xhkey); - return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING; + WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid)); + return CO_E_CLASSSTRING; + } + RegCloseKey(xhkey); + return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING; } /****************************************************************************** * CLSIDFromProgID (combase.@) */ -HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid) -{ - ACTCTX_SECTION_KEYED_DATA data; - - if (!progid || !clsid) - return E_INVALIDARG; - - data.cbSize = sizeof(data); - if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION, - progid, &data)) - { - struct progidredirect_data *progiddata = (struct progidredirect_data *)data.lpData; - CLSID *alias = (CLSID *)((BYTE *)data.lpSectionBase + progiddata->clsid_offset); - *clsid = *alias; - return S_OK; - } +HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, + CLSID *clsid) { + ACTCTX_SECTION_KEYED_DATA data; + + if (!progid || !clsid) + return E_INVALIDARG; + + data.cbSize = sizeof(data); + if (FindActCtxSectionStringW( + 0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION, progid, + &data)) { + struct progidredirect_data *progiddata = + (struct progidredirect_data *)data.lpData; + CLSID *alias = + (CLSID *)((BYTE *)data.lpSectionBase + progiddata->clsid_offset); + *clsid = *alias; + return S_OK; + } - return clsid_from_string_reg(progid, clsid); + return clsid_from_string_reg(progid, clsid); } /****************************************************************************** * CLSIDFromProgIDEx (combase.@) */ -HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, CLSID *clsid) -{ - FIXME("%s, %p: semi-stub\n", debugstr_w(progid), clsid); +HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, CLSID *clsid) { + FIXME("%s, %p: semi-stub\n", debugstr_w(progid), clsid); - return CLSIDFromProgID(progid, clsid); + return CLSIDFromProgID(progid, clsid); } /****************************************************************************** * CLSIDFromString (combase.@) */ -HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid) -{ - CLSID tmp_id; - HRESULT hr; +HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid) { + CLSID tmp_id; + HRESULT hr; - if (!clsid) - return E_INVALIDARG; + if (!clsid) + return E_INVALIDARG; - if (guid_from_string(str, clsid)) - return S_OK; + if (guid_from_string(str, clsid)) + return S_OK; - /* It appears a ProgID is also valid */ - hr = clsid_from_string_reg(str, &tmp_id); - if (SUCCEEDED(hr)) - *clsid = tmp_id; + /* It appears a ProgID is also valid */ + hr = clsid_from_string_reg(str, &tmp_id); + if (SUCCEEDED(hr)) + *clsid = tmp_id; - return hr; + return hr; } /****************************************************************************** * IIDFromString (combase.@) */ -HRESULT WINAPI IIDFromString(LPCOLESTR str, IID *iid) -{ - TRACE("%s, %p\n", debugstr_w(str), iid); +HRESULT WINAPI IIDFromString(LPCOLESTR str, IID *iid) { + TRACE("%s, %p\n", debugstr_w(str), iid); - if (!str) - { - memset(iid, 0, sizeof(*iid)); - return S_OK; - } + if (!str) { + memset(iid, 0, sizeof(*iid)); + return S_OK; + } - /* length mismatch is a special case */ - if (lstrlenW(str) + 1 != CHARS_IN_GUID) - return E_INVALIDARG; + /* length mismatch is a special case */ + if (lstrlenW(str) + 1 != CHARS_IN_GUID) + return E_INVALIDARG; - if (str[0] != '{') - return CO_E_IIDSTRING; + if (str[0] != '{') + return CO_E_IIDSTRING; - return guid_from_string(str, iid) ? S_OK : CO_E_IIDSTRING; + return guid_from_string(str, iid) ? S_OK : CO_E_IIDSTRING; } /****************************************************************************** * StringFromCLSID (combase.@) */ -HRESULT WINAPI StringFromCLSID(REFCLSID clsid, LPOLESTR *str) -{ - if (!(*str = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY; - StringFromGUID2(clsid, *str, CHARS_IN_GUID); - return S_OK; +HRESULT WINAPI StringFromCLSID(REFCLSID clsid, LPOLESTR *str) { + if (!(*str = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) + return E_OUTOFMEMORY; + StringFromGUID2(clsid, *str, CHARS_IN_GUID); + return S_OK; } /****************************************************************************** * StringFromGUID2 (combase.@) */ -INT WINAPI StringFromGUID2(REFGUID guid, LPOLESTR str, INT cmax) -{ - if (!guid || cmax < CHARS_IN_GUID) return 0; - swprintf(str, CHARS_IN_GUID, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1, - guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); - return CHARS_IN_GUID; +INT WINAPI StringFromGUID2(REFGUID guid, LPOLESTR str, INT cmax) { + if (!guid || cmax < CHARS_IN_GUID) + return 0; + swprintf(str, CHARS_IN_GUID, + L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1, + guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], + guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], + guid->Data4[6], guid->Data4[7]); + return CHARS_IN_GUID; } -static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr) -{ - ULONG i; +static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr) { + ULONG i; - for (i = 0; i < count; i++) - { - mqi[i].pItf = NULL; - mqi[i].hr = hr; - } + for (i = 0; i < count; i++) { + mqi[i].pItf = NULL; + mqi[i].hr = hr; + } } -static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk) -{ - ULONG index = 0, fetched = 0; +static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, + BOOL include_unk) { + ULONG index = 0, fetched = 0; - if (include_unk) - { - mqi[0].hr = S_OK; - mqi[0].pItf = unk; - index = fetched = 1; - } + if (include_unk) { + mqi[0].hr = S_OK; + mqi[0].pItf = unk; + index = fetched = 1; + } - for (; index < count; index++) - { - mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void **)&mqi[index].pItf); - if (mqi[index].hr == S_OK) - fetched++; - } + for (; index < count; index++) { + mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, + (void **)&mqi[index].pItf); + if (mqi[index].hr == S_OK) + fetched++; + } - if (!include_unk) - IUnknown_Release(unk); + if (!include_unk) + IUnknown_Release(unk); - if (fetched == 0) - return E_NOINTERFACE; + if (fetched == 0) + return E_NOINTERFACE; - return fetched == count ? S_OK : CO_S_NOTALLINTERFACES; + return fetched == count ? S_OK : CO_S_NOTALLINTERFACES; } /*********************************************************************** * CoGetInstanceFromFile (combase.@) */ -HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(COSERVERINFO *server_info, CLSID *rclsid, - IUnknown *outer, DWORD cls_context, DWORD grfmode, OLECHAR *filename, DWORD count, - MULTI_QI *results) -{ - IPersistFile *pf = NULL; - IUnknown *obj = NULL; - CLSID clsid; - HRESULT hr; - - if (!count || !results) - return E_INVALIDARG; +HRESULT WINAPI DECLSPEC_HOTPATCH +CoGetInstanceFromFile(COSERVERINFO *server_info, CLSID *rclsid, IUnknown *outer, + DWORD cls_context, DWORD grfmode, OLECHAR *filename, + DWORD count, MULTI_QI *results) { + IPersistFile *pf = NULL; + IUnknown *obj = NULL; + CLSID clsid; + HRESULT hr; - if (server_info) - FIXME("() non-NULL server_info not supported\n"); + if (!count || !results) + return E_INVALIDARG; - init_multi_qi(count, results, E_NOINTERFACE); + if (server_info) + FIXME("() non-NULL server_info not supported\n"); - if (!rclsid) - { - hr = GetClassFile(filename, &clsid); - if (FAILED(hr)) - { - ERR("Failed to get CLSID from a file.\n"); - return hr; - } + init_multi_qi(count, results, E_NOINTERFACE); - rclsid = &clsid; + if (!rclsid) { + hr = GetClassFile(filename, &clsid); + if (FAILED(hr)) { + ERR("Failed to get CLSID from a file.\n"); + return hr; } - hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj); - if (hr != S_OK) - { - init_multi_qi(count, results, hr); - return hr; - } + rclsid = &clsid; + } - /* Init from file */ - hr = IUnknown_QueryInterface(obj, &IID_IPersistFile, (void **)&pf); - if (FAILED(hr)) - { - init_multi_qi(count, results, hr); - IUnknown_Release(obj); - return hr; - } + hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, + (void **)&obj); + if (hr != S_OK) { + init_multi_qi(count, results, hr); + return hr; + } - hr = IPersistFile_Load(pf, filename, grfmode); - IPersistFile_Release(pf); - if (SUCCEEDED(hr)) - return return_multi_qi(obj, count, results, FALSE); - else - { - init_multi_qi(count, results, hr); - IUnknown_Release(obj); - return hr; - } + /* Init from file */ + hr = IUnknown_QueryInterface(obj, &IID_IPersistFile, (void **)&pf); + if (FAILED(hr)) { + init_multi_qi(count, results, hr); + IUnknown_Release(obj); + return hr; + } + + hr = IPersistFile_Load(pf, filename, grfmode); + IPersistFile_Release(pf); + if (SUCCEEDED(hr)) + return return_multi_qi(obj, count, results, FALSE); + else { + init_multi_qi(count, results, hr); + IUnknown_Release(obj); + return hr; + } } /*********************************************************************** * CoGetInstanceFromIStorage (combase.@) */ -HRESULT WINAPI CoGetInstanceFromIStorage(COSERVERINFO *server_info, CLSID *rclsid, - IUnknown *outer, DWORD cls_context, IStorage *storage, DWORD count, MULTI_QI *results) -{ - IPersistStorage *ps = NULL; - IUnknown *obj = NULL; - STATSTG stat; - HRESULT hr; - - if (!count || !results || !storage) - return E_INVALIDARG; +HRESULT WINAPI CoGetInstanceFromIStorage(COSERVERINFO *server_info, + CLSID *rclsid, IUnknown *outer, + DWORD cls_context, IStorage *storage, + DWORD count, MULTI_QI *results) { + IPersistStorage *ps = NULL; + IUnknown *obj = NULL; + STATSTG stat; + HRESULT hr; - if (server_info) - FIXME("() non-NULL server_info not supported\n"); + if (!count || !results || !storage) + return E_INVALIDARG; - init_multi_qi(count, results, E_NOINTERFACE); + if (server_info) + FIXME("() non-NULL server_info not supported\n"); - if (!rclsid) - { - memset(&stat.clsid, 0, sizeof(stat.clsid)); - hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME); - if (FAILED(hr)) - { - ERR("Failed to get CLSID from a storage.\n"); - return hr; - } + init_multi_qi(count, results, E_NOINTERFACE); - rclsid = &stat.clsid; + if (!rclsid) { + memset(&stat.clsid, 0, sizeof(stat.clsid)); + hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME); + if (FAILED(hr)) { + ERR("Failed to get CLSID from a storage.\n"); + return hr; } - hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj); - if (hr != S_OK) - return hr; + rclsid = &stat.clsid; + } - /* Init from IStorage */ - hr = IUnknown_QueryInterface(obj, &IID_IPersistStorage, (void **)&ps); - if (FAILED(hr)) - ERR("failed to get IPersistStorage\n"); + hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, + (void **)&obj); + if (hr != S_OK) + return hr; - if (ps) - { - IPersistStorage_Load(ps, storage); - IPersistStorage_Release(ps); - } + /* Init from IStorage */ + hr = IUnknown_QueryInterface(obj, &IID_IPersistStorage, (void **)&ps); + if (FAILED(hr)) + ERR("failed to get IPersistStorage\n"); - return return_multi_qi(obj, count, results, FALSE); + if (ps) { + IPersistStorage_Load(ps, storage); + IPersistStorage_Release(ps); + } + + return return_multi_qi(obj, count, results, FALSE); } /*********************************************************************** * CoCreateInstance (combase.@) */ -HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, IUnknown *outer, DWORD cls_context, - REFIID riid, void **obj) -{ - MULTI_QI multi_qi = { .pIID = riid }; - HRESULT hr; +HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, + IUnknown *outer, + DWORD cls_context, + REFIID riid, void **obj) { + MULTI_QI multi_qi = {.pIID = riid}; + HRESULT hr; - TRACE("%s, %p, %#lx, %s, %p.\n", debugstr_guid(rclsid), outer, cls_context, debugstr_guid(riid), obj); + TRACE("%s, %p, %#lx, %s, %p.\n", debugstr_guid(rclsid), outer, cls_context, + debugstr_guid(riid), obj); - if (!obj) - return E_POINTER; + if (!obj) + return E_POINTER; - hr = CoCreateInstanceEx(rclsid, outer, cls_context, NULL, 1, &multi_qi); - *obj = multi_qi.pItf; - return hr; + hr = CoCreateInstanceEx(rclsid, outer, cls_context, NULL, 1, &multi_qi); + *obj = multi_qi.pItf; + return hr; } /*********************************************************************** * CoCreateInstanceFromApp (combase.@) */ -HRESULT WINAPI CoCreateInstanceFromApp(REFCLSID rclsid, IUnknown *outer, DWORD cls_context, - void *server_info, ULONG count, MULTI_QI *results) -{ - TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info, - count, results); +HRESULT WINAPI CoCreateInstanceFromApp(REFCLSID rclsid, IUnknown *outer, + DWORD cls_context, void *server_info, + ULONG count, MULTI_QI *results) { + TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, + cls_context, server_info, count, results); - return CoCreateInstanceEx(rclsid, outer, cls_context | CLSCTX_APPCONTAINER, server_info, - count, results); + return CoCreateInstanceEx(rclsid, outer, cls_context | CLSCTX_APPCONTAINER, + server_info, count, results); } static HRESULT com_get_class_object(REFCLSID rclsid, DWORD clscontext, - COSERVERINFO *server_info, REFIID riid, void **obj) -{ - struct class_reg_data clsreg = { 0 }; - HRESULT hr = E_UNEXPECTED; - IUnknown *registered_obj; - struct apartment *apt; - - if (!obj) - return E_INVALIDARG; + COSERVERINFO *server_info, REFIID riid, + void **obj) { + struct class_reg_data clsreg = {0}; + HRESULT hr = E_UNEXPECTED; + IUnknown *registered_obj; + struct apartment *apt; + + if (!obj) + return E_INVALIDARG; + + *obj = NULL; + + if (!(apt = apartment_get_current_or_mta())) { + WARN("apartment not initialised, implicitly initializing as STA\n"); + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (!(apt = apartment_get_current_or_mta())) { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } + } + + if (server_info) + FIXME("server_info name %s, authinfo %p\n", + debugstr_w(server_info->pwszName), server_info->pAuthInfo); + + if (clscontext & CLSCTX_INPROC_SERVER) { + if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler) || + IsEqualCLSID(rclsid, &CLSID_GlobalOptions) || + (!(clscontext & CLSCTX_APPCONTAINER) && + IsEqualCLSID(rclsid, &CLSID_ManualResetEvent)) || + IsEqualCLSID(rclsid, &CLSID_StdGlobalInterfaceTable)) { + apartment_release(apt); + + if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions)) + return get_builtin_class_factory(rclsid, riid, obj); + else + return Ole32DllGetClassObject(rclsid, riid, obj); + } + } + + if (clscontext & CLSCTX_INPROC) { + ACTCTX_SECTION_KEYED_DATA data; - *obj = NULL; + data.cbSize = sizeof(data); + /* search activation context first */ + if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, + ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, + rclsid, &data)) { + struct comclassredirect_data *comclass = + (struct comclassredirect_data *)data.lpData; + + clsreg.u.actctx.module_name = + (WCHAR *)((BYTE *)data.lpSectionBase + comclass->name_offset); + clsreg.u.actctx.hactctx = data.hActCtx; + clsreg.u.actctx.threading_model = comclass->model; + clsreg.origin = CLASS_REG_ACTCTX; + + hr = apartment_get_inproc_class_object(apt, &clsreg, &comclass->clsid, + riid, clscontext, obj); + ReleaseActCtx(data.hActCtx); + apartment_release(apt); + return hr; + } + } + + /* + * First, try and see if we can't match the class ID with one of the + * registered classes. + */ + if (!(clscontext & CLSCTX_APPCONTAINER) && + (registered_obj = + com_get_registered_class_object(apt, rclsid, clscontext))) { + hr = IUnknown_QueryInterface(registered_obj, riid, obj); + IUnknown_Release(registered_obj); + apartment_release(apt); + return hr; + } - if (!(apt = apartment_get_current_or_mta())) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } + /* First try in-process server */ + if (clscontext & CLSCTX_INPROC_SERVER) { + HKEY hkey; - if (server_info) - FIXME("server_info name %s, authinfo %p\n", debugstr_w(server_info->pwszName), server_info->pAuthInfo); - - if (clscontext & CLSCTX_INPROC_SERVER) - { - if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler) || - IsEqualCLSID(rclsid, &CLSID_GlobalOptions) || - (!(clscontext & CLSCTX_APPCONTAINER) && IsEqualCLSID(rclsid, &CLSID_ManualResetEvent)) || - IsEqualCLSID(rclsid, &CLSID_StdGlobalInterfaceTable)) - { - apartment_release(apt); - - if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions)) - return get_builtin_class_factory(rclsid, riid, obj); - else - return Ole32DllGetClassObject(rclsid, riid, obj); - } + hr = open_key_for_clsid(rclsid, L"InprocServer32", KEY_READ, &hkey); + if (FAILED(hr)) { + if (hr == REGDB_E_CLASSNOTREG) + ERR("class %s not registered\n", debugstr_guid(rclsid)); + else if (hr == REGDB_E_KEYMISSING) { + WARN("class %s not registered as in-proc server\n", + debugstr_guid(rclsid)); + hr = REGDB_E_CLASSNOTREG; + } } - if (clscontext & CLSCTX_INPROC) - { - ACTCTX_SECTION_KEYED_DATA data; - - data.cbSize = sizeof(data); - /* search activation context first */ - if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, - ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, rclsid, &data)) - { - struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData; - - clsreg.u.actctx.module_name = (WCHAR *)((BYTE *)data.lpSectionBase + comclass->name_offset); - clsreg.u.actctx.hactctx = data.hActCtx; - clsreg.u.actctx.threading_model = comclass->model; - clsreg.origin = CLASS_REG_ACTCTX; - - hr = apartment_get_inproc_class_object(apt, &clsreg, &comclass->clsid, riid, clscontext, obj); - ReleaseActCtx(data.hActCtx); - apartment_release(apt); - return hr; - } - } + if (SUCCEEDED(hr)) { + clsreg.u.hkey = hkey; + clsreg.origin = CLASS_REG_REGISTRY; - /* - * First, try and see if we can't match the class ID with one of the - * registered classes. - */ - if (!(clscontext & CLSCTX_APPCONTAINER) && (registered_obj = com_get_registered_class_object(apt, rclsid, clscontext))) - { - hr = IUnknown_QueryInterface(registered_obj, riid, obj); - IUnknown_Release(registered_obj); - apartment_release(apt); - return hr; + hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, + clscontext, obj); + RegCloseKey(hkey); } - /* First try in-process server */ - if (clscontext & CLSCTX_INPROC_SERVER) - { - HKEY hkey; - - hr = open_key_for_clsid(rclsid, L"InprocServer32", KEY_READ, &hkey); - if (FAILED(hr)) - { - if (hr == REGDB_E_CLASSNOTREG) - ERR("class %s not registered\n", debugstr_guid(rclsid)); - else if (hr == REGDB_E_KEYMISSING) - { - WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid)); - hr = REGDB_E_CLASSNOTREG; - } - } - - if (SUCCEEDED(hr)) - { - clsreg.u.hkey = hkey; - clsreg.origin = CLASS_REG_REGISTRY; - - hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj); - RegCloseKey(hkey); - } - - /* return if we got a class, otherwise fall through to one of the - * other types */ - if (SUCCEEDED(hr)) - { - apartment_release(apt); - return hr; - } + /* return if we got a class, otherwise fall through to one of the + * other types */ + if (SUCCEEDED(hr)) { + apartment_release(apt); + return hr; } + } - /* Next try in-process handler */ - if (clscontext & CLSCTX_INPROC_HANDLER) - { - HKEY hkey; - - hr = open_key_for_clsid(rclsid, L"InprocHandler32", KEY_READ, &hkey); - if (FAILED(hr)) - { - if (hr == REGDB_E_CLASSNOTREG) - ERR("class %s not registered\n", debugstr_guid(rclsid)); - else if (hr == REGDB_E_KEYMISSING) - { - WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid)); - hr = REGDB_E_CLASSNOTREG; - } - } + /* Next try in-process handler */ + if (clscontext & CLSCTX_INPROC_HANDLER) { + HKEY hkey; - if (SUCCEEDED(hr)) - { - clsreg.u.hkey = hkey; - clsreg.origin = CLASS_REG_REGISTRY; + hr = open_key_for_clsid(rclsid, L"InprocHandler32", KEY_READ, &hkey); + if (FAILED(hr)) { + if (hr == REGDB_E_CLASSNOTREG) + ERR("class %s not registered\n", debugstr_guid(rclsid)); + else if (hr == REGDB_E_KEYMISSING) { + WARN("class %s not registered in-proc handler\n", + debugstr_guid(rclsid)); + hr = REGDB_E_CLASSNOTREG; + } + } - hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj); - RegCloseKey(hkey); - } + if (SUCCEEDED(hr)) { + clsreg.u.hkey = hkey; + clsreg.origin = CLASS_REG_REGISTRY; - /* return if we got a class, otherwise fall through to one of the - * other types */ - if (SUCCEEDED(hr)) - { - apartment_release(apt); - return hr; - } + hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, + clscontext, obj); + RegCloseKey(hkey); } - apartment_release(apt); - /* Next try out of process */ - if (clscontext & CLSCTX_LOCAL_SERVER) - { - hr = rpc_get_local_class_object(rclsid, riid, obj); - if (SUCCEEDED(hr)) - return hr; + /* return if we got a class, otherwise fall through to one of the + * other types */ + if (SUCCEEDED(hr)) { + apartment_release(apt); + return hr; } + } + apartment_release(apt); - /* Finally try remote: this requires networked DCOM (a lot of work) */ - if (clscontext & CLSCTX_REMOTE_SERVER) - { - FIXME ("CLSCTX_REMOTE_SERVER not supported\n"); - hr = REGDB_E_CLASSNOTREG; - } + /* Next try out of process */ + if (clscontext & CLSCTX_LOCAL_SERVER) { + hr = rpc_get_local_class_object(rclsid, riid, obj); + if (SUCCEEDED(hr)) + return hr; + } - if (FAILED(hr)) - ERR("no class object %s could be created for context %#lx\n", debugstr_guid(rclsid), clscontext); + /* Finally try remote: this requires networked DCOM (a lot of work) */ + if (clscontext & CLSCTX_REMOTE_SERVER) { + FIXME("CLSCTX_REMOTE_SERVER not supported\n"); + hr = REGDB_E_CLASSNOTREG; + } - return hr; + if (FAILED(hr)) + ERR("no class object %s could be created for context %#lx\n", + debugstr_guid(rclsid), clscontext); + + return hr; } /*********************************************************************** * CoCreateInstanceEx (combase.@) */ -HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(REFCLSID rclsid, IUnknown *outer, DWORD cls_context, - COSERVERINFO *server_info, ULONG count, MULTI_QI *results) -{ - IClassFactory *factory; - IUnknown *unk = NULL; - CLSID clsid; - HRESULT hr; +HRESULT WINAPI DECLSPEC_HOTPATCH +CoCreateInstanceEx(REFCLSID rclsid, IUnknown *outer, DWORD cls_context, + COSERVERINFO *server_info, ULONG count, MULTI_QI *results) { + IClassFactory *factory; + IUnknown *unk = NULL; + CLSID clsid; + HRESULT hr; - TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info, count, results); + TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, + cls_context, server_info, count, results); - if (!count || !results) - return E_INVALIDARG; + if (!count || !results) + return E_INVALIDARG; - if (server_info) - FIXME("Server info is not supported.\n"); + if (server_info) + FIXME("Server info is not supported.\n"); - init_multi_qi(count, results, E_NOINTERFACE); + init_multi_qi(count, results, E_NOINTERFACE); - clsid = *rclsid; - if (!(cls_context & CLSCTX_APPCONTAINER)) - CoGetTreatAsClass(rclsid, &clsid); + clsid = *rclsid; + if (!(cls_context & CLSCTX_APPCONTAINER)) + CoGetTreatAsClass(rclsid, &clsid); - if (FAILED(hr = com_get_class_object(&clsid, cls_context, NULL, &IID_IClassFactory, (void **)&factory))) - return hr; + if (FAILED(hr = com_get_class_object(&clsid, cls_context, NULL, + &IID_IClassFactory, (void **)&factory))) + return hr; - hr = IClassFactory_CreateInstance(factory, outer, results[0].pIID, (void **)&unk); - IClassFactory_Release(factory); - if (FAILED(hr)) - { - if (hr == CLASS_E_NOAGGREGATION && outer) - FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid)); - else - FIXME("no instance created for interface %s of class %s, hr %#lx.\n", - debugstr_guid(results[0].pIID), debugstr_guid(&clsid), hr); - return hr; - } + hr = IClassFactory_CreateInstance(factory, outer, results[0].pIID, + (void **)&unk); + IClassFactory_Release(factory); + if (FAILED(hr)) { + if (hr == CLASS_E_NOAGGREGATION && outer) + FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid)); + else + FIXME("no instance created for interface %s of class %s, hr %#lx.\n", + debugstr_guid(results[0].pIID), debugstr_guid(&clsid), hr); + return hr; + } - return return_multi_qi(unk, count, results, TRUE); + return return_multi_qi(unk, count, results, TRUE); } /*********************************************************************** * CoGetClassObject (combase.@) */ -HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscontext, - COSERVERINFO *server_info, REFIID riid, void **obj) -{ - TRACE("%s, %#lx, %s\n", debugstr_guid(rclsid), clscontext, debugstr_guid(riid)); +HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, + DWORD clscontext, + COSERVERINFO *server_info, + REFIID riid, void **obj) { + TRACE("%s, %#lx, %s\n", debugstr_guid(rclsid), clscontext, + debugstr_guid(riid)); - return com_get_class_object(rclsid, clscontext, server_info, riid, obj); + return com_get_class_object(rclsid, clscontext, server_info, riid, obj); } /*********************************************************************** * CoFreeUnusedLibraries (combase.@) */ -void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void) -{ - CoFreeUnusedLibrariesEx(INFINITE, 0); +void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void) { + CoFreeUnusedLibrariesEx(INFINITE, 0); } /*********************************************************************** * CoGetCallContext (combase.@) */ -HRESULT WINAPI CoGetCallContext(REFIID riid, void **obj) -{ - struct tlsdata *tlsdata; - HRESULT hr; +HRESULT WINAPI CoGetCallContext(REFIID riid, void **obj) { + struct tlsdata *tlsdata; + HRESULT hr; - TRACE("%s, %p\n", debugstr_guid(riid), obj); + TRACE("%s, %p\n", debugstr_guid(riid), obj); - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; - if (!tlsdata->call_state) - return RPC_E_CALL_COMPLETE; + if (!tlsdata->call_state) + return RPC_E_CALL_COMPLETE; - return IUnknown_QueryInterface(tlsdata->call_state, riid, obj); + return IUnknown_QueryInterface(tlsdata->call_state, riid, obj); } /*********************************************************************** * CoSwitchCallContext (combase.@) */ -HRESULT WINAPI CoSwitchCallContext(IUnknown *context, IUnknown **old_context) -{ - struct tlsdata *tlsdata; - HRESULT hr; +HRESULT WINAPI CoSwitchCallContext(IUnknown *context, IUnknown **old_context) { + struct tlsdata *tlsdata; + HRESULT hr; - TRACE("%p, %p\n", context, old_context); + TRACE("%p, %p\n", context, old_context); - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; - /* Reference counts are not touched. */ - *old_context = tlsdata->call_state; - tlsdata->call_state = context; + /* Reference counts are not touched. */ + *old_context = tlsdata->call_state; + tlsdata->call_state = context; - return S_OK; + return S_OK; } /****************************************************************************** * CoRegisterInitializeSpy (combase.@) */ -HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie) -{ - struct tlsdata *tlsdata; - struct init_spy *entry; - unsigned int id; - HRESULT hr; +HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, + ULARGE_INTEGER *cookie) { + struct tlsdata *tlsdata; + struct init_spy *entry; + unsigned int id; + HRESULT hr; - TRACE("%p, %p\n", spy, cookie); + TRACE("%p, %p\n", spy, cookie); - if (!spy || !cookie) - return E_INVALIDARG; + if (!spy || !cookie) + return E_INVALIDARG; - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; - hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy); - if (FAILED(hr)) - return hr; + hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy); + if (FAILED(hr)) + return hr; - entry = malloc(sizeof(*entry)); - if (!entry) - { - IInitializeSpy_Release(spy); - return E_OUTOFMEMORY; - } + entry = malloc(sizeof(*entry)); + if (!entry) { + IInitializeSpy_Release(spy); + return E_OUTOFMEMORY; + } - entry->spy = spy; + entry->spy = spy; - id = 0; - while (get_spy_entry(tlsdata, id) != NULL) - { - id++; - } + id = 0; + while (get_spy_entry(tlsdata, id) != NULL) { + id++; + } - entry->id = id; - list_add_head(&tlsdata->spies, &entry->entry); + entry->id = id; + list_add_head(&tlsdata->spies, &entry->entry); - cookie->u.HighPart = GetCurrentThreadId(); - cookie->u.LowPart = entry->id; + cookie->u.HighPart = GetCurrentThreadId(); + cookie->u.LowPart = entry->id; - return S_OK; + return S_OK; } /****************************************************************************** * CoRevokeInitializeSpy (combase.@) */ -HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie) -{ - struct tlsdata *tlsdata; - struct init_spy *spy; - HRESULT hr; +HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie) { + struct tlsdata *tlsdata; + struct init_spy *spy; + HRESULT hr; - TRACE("%s\n", wine_dbgstr_longlong(cookie.QuadPart)); + TRACE("%s\n", wine_dbgstr_longlong(cookie.QuadPart)); - if (cookie.u.HighPart != GetCurrentThreadId()) - return E_INVALIDARG; + if (cookie.u.HighPart != GetCurrentThreadId()) + return E_INVALIDARG; - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; - if (!(spy = get_spy_entry(tlsdata, cookie.u.LowPart))) return E_INVALIDARG; + if (!(spy = get_spy_entry(tlsdata, cookie.u.LowPart))) + return E_INVALIDARG; - IInitializeSpy_Release(spy->spy); - spy->spy = NULL; - if (!tlsdata->spies_lock) - { - list_remove(&spy->entry); - free(spy); - } - return S_OK; + IInitializeSpy_Release(spy->spy); + spy->spy = NULL; + if (!tlsdata->spies_lock) { + list_remove(&spy->entry); + free(spy); + } + return S_OK; } -static BOOL com_peek_message(struct apartment *apt, MSG *msg) -{ - /* First try to retrieve messages for incoming COM calls to the apartment window */ - return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE | PM_NOYIELD)) || - /* Next retrieve other messages necessary for the app to remain responsive */ - PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE | PM_NOYIELD) || - PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT | PM_QS_SENDMESSAGE | PM_REMOVE | PM_NOYIELD); +static BOOL com_peek_message(struct apartment *apt, MSG *msg) { + /* First try to retrieve messages for incoming COM calls to the apartment + * window */ + return (apt->win && + PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE | PM_NOYIELD)) || + /* Next retrieve other messages necessary for the app to remain + responsive */ + PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, + PM_REMOVE | PM_NOYIELD) || + PeekMessageW(msg, NULL, 0, 0, + PM_QS_PAINT | PM_QS_SENDMESSAGE | PM_REMOVE | PM_NOYIELD); } /*********************************************************************** * CoWaitForMultipleHandles (combase.@) */ -HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle_count, HANDLE *handles, - DWORD *index) -{ - BOOL check_apc = !!(flags & COWAIT_ALERTABLE), message_loop; - struct { BOOL post; UINT code; } quit = { .post = FALSE }; - DWORD start_time, wait_flags = 0; - struct tlsdata *tlsdata; - struct apartment *apt; - HRESULT hr; +HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, + ULONG handle_count, HANDLE *handles, + DWORD *index) { + BOOL check_apc = !!(flags & COWAIT_ALERTABLE), message_loop; + struct { + BOOL post; + UINT code; + } quit = {.post = FALSE}; + DWORD start_time, wait_flags = 0; + struct tlsdata *tlsdata; + struct apartment *apt; + HRESULT hr; - TRACE("%#lx, %#lx, %lu, %p, %p\n", flags, timeout, handle_count, handles, index); + TRACE("%#lx, %#lx, %lu, %p, %p\n", flags, timeout, handle_count, handles, + index); - if (!index) - return E_INVALIDARG; + if (!index) + return E_INVALIDARG; - *index = 0; + *index = 0; - if (!handles) - return E_INVALIDARG; + if (!handles) + return E_INVALIDARG; - if (!handle_count) - return RPC_E_NO_SYNC; + if (!handle_count) + return RPC_E_NO_SYNC; - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; - apt = com_get_current_apt(); - message_loop = apt && !apt->multi_threaded; + apt = com_get_current_apt(); + message_loop = apt && !apt->multi_threaded; - if (flags & COWAIT_WAITALL) - wait_flags |= MWMO_WAITALL; - if (flags & COWAIT_ALERTABLE) - wait_flags |= MWMO_ALERTABLE; + if (flags & COWAIT_WAITALL) + wait_flags |= MWMO_WAITALL; + if (flags & COWAIT_ALERTABLE) + wait_flags |= MWMO_ALERTABLE; - start_time = GetTickCount(); + start_time = GetTickCount(); - while (TRUE) - { - DWORD now = GetTickCount(), res; + while (TRUE) { + DWORD now = GetTickCount(), res; - if (now - start_time > timeout) - { - hr = RPC_S_CALLPENDING; - break; - } + if (now - start_time > timeout) { + hr = RPC_S_CALLPENDING; + break; + } - if (message_loop) - { - TRACE("waiting for rpc completion or window message\n"); - - res = WAIT_TIMEOUT; - - if (check_apc) - { - res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), 0, TRUE); - check_apc = FALSE; - } - - if (res == WAIT_TIMEOUT) - res = MsgWaitForMultipleObjectsEx(handle_count, handles, - timeout == INFINITE ? INFINITE : start_time + timeout - now, - QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags); - - if (res == WAIT_OBJECT_0 + handle_count) /* messages available */ - { - int msg_count = 0; - MSG msg; - - /* call message filter */ - - if (apt->filter) - { - PENDINGTYPE pendingtype = tlsdata->pending_call_count_server ? PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL; - DWORD be_handled = IMessageFilter_MessagePending(apt->filter, 0 /* FIXME */, now - start_time, pendingtype); - - TRACE("IMessageFilter_MessagePending returned %ld\n", be_handled); - - switch (be_handled) - { - case PENDINGMSG_CANCELCALL: - WARN("call canceled\n"); - hr = RPC_E_CALL_CANCELED; - break; - case PENDINGMSG_WAITNOPROCESS: - case PENDINGMSG_WAITDEFPROCESS: - default: - /* FIXME: MSDN is very vague about the difference - * between WAITNOPROCESS and WAITDEFPROCESS - there - * appears to be none, so it is possibly a left-over - * from the 16-bit world. */ - break; - } - } - - if (!apt->win) - { - /* If window is NULL on apartment, peek at messages so that it will not trigger - * MsgWaitForMultipleObjects next time. */ - PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD); - } - - /* Some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever, - * so after processing 100 messages we go back to checking the wait handles */ - while (msg_count++ < 100 && com_peek_message(apt, &msg)) - { - if (msg.message == WM_QUIT) - { - TRACE("Received WM_QUIT message\n"); - quit.post = TRUE; - quit.code = msg.wParam; - } - else - { - TRACE("Received message whilst waiting for RPC: 0x%04x\n", msg.message); - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - } - continue; - } - } - else - { - TRACE("Waiting for rpc completion\n"); + if (message_loop) { + TRACE("waiting for rpc completion or window message\n"); - res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), - (timeout == INFINITE) ? INFINITE : start_time + timeout - now, !!(flags & COWAIT_ALERTABLE)); - } + res = WAIT_TIMEOUT; - switch (res) - { - case WAIT_TIMEOUT: - hr = RPC_S_CALLPENDING; - break; - case WAIT_FAILED: - hr = HRESULT_FROM_WIN32(GetLastError()); + if (check_apc) { + res = WaitForMultipleObjectsEx(handle_count, handles, + !!(flags & COWAIT_WAITALL), 0, TRUE); + check_apc = FALSE; + } + + if (res == WAIT_TIMEOUT) + res = MsgWaitForMultipleObjectsEx( + handle_count, handles, + timeout == INFINITE ? INFINITE : start_time + timeout - now, + QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags); + + if (res == WAIT_OBJECT_0 + handle_count) /* messages available */ + { + int msg_count = 0; + MSG msg; + + /* call message filter */ + + if (apt->filter) { + PENDINGTYPE pendingtype = tlsdata->pending_call_count_server + ? PENDINGTYPE_NESTED + : PENDINGTYPE_TOPLEVEL; + DWORD be_handled = IMessageFilter_MessagePending( + apt->filter, 0 /* FIXME */, now - start_time, pendingtype); + + TRACE("IMessageFilter_MessagePending returned %ld\n", be_handled); + + switch (be_handled) { + case PENDINGMSG_CANCELCALL: + WARN("call canceled\n"); + hr = RPC_E_CALL_CANCELED; break; - default: - *index = res; + case PENDINGMSG_WAITNOPROCESS: + case PENDINGMSG_WAITDEFPROCESS: + default: + /* FIXME: MSDN is very vague about the difference + * between WAITNOPROCESS and WAITDEFPROCESS - there + * appears to be none, so it is possibly a left-over + * from the 16-bit world. */ break; + } } - break; + + if (!apt->win) { + /* If window is NULL on apartment, peek at messages so that it will + * not trigger MsgWaitForMultipleObjects next time. */ + PeekMessageW(NULL, NULL, 0, 0, + PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD); + } + + /* Some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop + * forever, so after processing 100 messages we go back to checking the + * wait handles */ + while (msg_count++ < 100 && com_peek_message(apt, &msg)) { + if (msg.message == WM_QUIT) { + TRACE("Received WM_QUIT message\n"); + quit.post = TRUE; + quit.code = msg.wParam; + } else { + TRACE("Received message whilst waiting for RPC: 0x%04x\n", + msg.message); + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + continue; + } + } else { + TRACE("Waiting for rpc completion\n"); + + res = WaitForMultipleObjectsEx( + handle_count, handles, !!(flags & COWAIT_WAITALL), + (timeout == INFINITE) ? INFINITE : start_time + timeout - now, + !!(flags & COWAIT_ALERTABLE)); + } + + switch (res) { + case WAIT_TIMEOUT: + hr = RPC_S_CALLPENDING; + break; + case WAIT_FAILED: + hr = HRESULT_FROM_WIN32(GetLastError()); + break; + default: + *index = res; + break; } - if (quit.post) PostQuitMessage(quit.code); + break; + } + if (quit.post) + PostQuitMessage(quit.code); - TRACE("-- %#lx\n", hr); + TRACE("-- %#lx\n", hr); - return hr; + return hr; } /****************************************************************************** * CoRegisterMessageFilter (combase.@) */ -HRESULT WINAPI CoRegisterMessageFilter(IMessageFilter *filter, IMessageFilter **ret_filter) -{ - IMessageFilter *old_filter; - struct apartment *apt; +HRESULT WINAPI CoRegisterMessageFilter(IMessageFilter *filter, + IMessageFilter **ret_filter) { + IMessageFilter *old_filter; + struct apartment *apt; - TRACE("%p, %p\n", filter, ret_filter); + TRACE("%p, %p\n", filter, ret_filter); - apt = com_get_current_apt(); + apt = com_get_current_apt(); - /* Can't set a message filter in a multi-threaded apartment */ - if (!apt || apt->multi_threaded) - { - WARN("Can't set message filter in MTA or uninitialized apt\n"); - return CO_E_NOT_SUPPORTED; - } + /* Can't set a message filter in a multi-threaded apartment */ + if (!apt || apt->multi_threaded) { + WARN("Can't set message filter in MTA or uninitialized apt\n"); + return CO_E_NOT_SUPPORTED; + } - if (filter) - IMessageFilter_AddRef(filter); + if (filter) + IMessageFilter_AddRef(filter); - EnterCriticalSection(&apt->cs); + EnterCriticalSection(&apt->cs); - old_filter = apt->filter; - apt->filter = filter; + old_filter = apt->filter; + apt->filter = filter; - LeaveCriticalSection(&apt->cs); + LeaveCriticalSection(&apt->cs); - if (ret_filter) - *ret_filter = old_filter; - else if (old_filter) - IMessageFilter_Release(old_filter); + if (ret_filter) + *ret_filter = old_filter; + else if (old_filter) + IMessageFilter_Release(old_filter); - return S_OK; + return S_OK; } -static void com_revoke_all_ps_clsids(void) -{ - struct registered_ps *cur, *cur2; +static void com_revoke_all_ps_clsids(void) { + struct registered_ps *cur, *cur2; - EnterCriticalSection(&cs_registered_ps); + EnterCriticalSection(&cs_registered_ps); - LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, ®istered_proxystubs, struct registered_ps, entry) - { - list_remove(&cur->entry); - free(cur); - } + LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, ®istered_proxystubs, + struct registered_ps, entry) { + list_remove(&cur->entry); + free(cur); + } - LeaveCriticalSection(&cs_registered_ps); + LeaveCriticalSection(&cs_registered_ps); } -static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid) -{ - WCHAR value[CHARS_IN_GUID]; - HKEY hkey; - DWORD len; +static HRESULT get_ps_clsid_from_registry(const WCHAR *path, REGSAM access, + CLSID *pclsid) { + WCHAR value[CHARS_IN_GUID]; + HKEY hkey; + DWORD len; - access |= KEY_READ; + access |= KEY_READ; - if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey)) - return REGDB_E_IIDNOTREG; + if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey)) + return REGDB_E_IIDNOTREG; - len = sizeof(value); - if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len)) - return REGDB_E_IIDNOTREG; - RegCloseKey(hkey); + len = sizeof(value); + if (ERROR_SUCCESS != + RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len)) + return REGDB_E_IIDNOTREG; + RegCloseKey(hkey); - if (CLSIDFromString(value, pclsid) != NOERROR) - return REGDB_E_IIDNOTREG; + if (CLSIDFromString(value, pclsid) != NOERROR) + return REGDB_E_IIDNOTREG; - return S_OK; + return S_OK; } /***************************************************************************** * CoGetPSClsid (combase.@) */ -HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) -{ - static const WCHAR interfaceW[] = L"Interface\\"; - static const WCHAR psW[] = L"\\ProxyStubClsid32"; - WCHAR path[ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(psW)]; - ACTCTX_SECTION_KEYED_DATA data; - struct registered_ps *cur; - REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY; - BOOL is_wow64; - HRESULT hr; - - TRACE("%s, %p\n", debugstr_guid(riid), pclsid); - - if (!InternalIsProcessInitialized()) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } - - if (!pclsid) - return E_INVALIDARG; - - EnterCriticalSection(&cs_registered_ps); - - LIST_FOR_EACH_ENTRY(cur, ®istered_proxystubs, struct registered_ps, entry) - { - if (IsEqualIID(&cur->iid, riid)) - { - *pclsid = cur->clsid; - LeaveCriticalSection(&cs_registered_ps); - return S_OK; - } - } - - LeaveCriticalSection(&cs_registered_ps); - - data.cbSize = sizeof(data); - if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION, - riid, &data)) - { - struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data *)data.lpData; - *pclsid = ifaceps->iid; - return S_OK; - } +HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) { + static const WCHAR interfaceW[] = L"Interface\\"; + static const WCHAR psW[] = L"\\ProxyStubClsid32"; + WCHAR path[ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(psW)]; + ACTCTX_SECTION_KEYED_DATA data; + struct registered_ps *cur; + REGSAM opposite = + (sizeof(void *) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY; + BOOL is_wow64; + HRESULT hr; + + TRACE("%s, %p\n", debugstr_guid(riid), pclsid); + + if (!InternalIsProcessInitialized()) { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } + + if (!pclsid) + return E_INVALIDARG; + + EnterCriticalSection(&cs_registered_ps); + + LIST_FOR_EACH_ENTRY(cur, ®istered_proxystubs, struct registered_ps, + entry) { + if (IsEqualIID(&cur->iid, riid)) { + *pclsid = cur->clsid; + LeaveCriticalSection(&cs_registered_ps); + return S_OK; + } + } + + LeaveCriticalSection(&cs_registered_ps); + + data.cbSize = sizeof(data); + if (FindActCtxSectionGuid( + 0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION, riid, + &data)) { + struct ifacepsredirect_data *ifaceps = + (struct ifacepsredirect_data *)data.lpData; + *pclsid = ifaceps->iid; + return S_OK; + } - /* Interface\\{string form of riid}\\ProxyStubClsid32 */ - lstrcpyW(path, interfaceW); - StringFromGUID2(riid, path + ARRAY_SIZE(interfaceW) - 1, CHARS_IN_GUID); - lstrcpyW(path + ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1, psW); + /* Interface\\{string form of riid}\\ProxyStubClsid32 */ + lstrcpyW(path, interfaceW); + StringFromGUID2(riid, path + ARRAY_SIZE(interfaceW) - 1, CHARS_IN_GUID); + lstrcpyW(path + ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1, psW); - hr = get_ps_clsid_from_registry(path, KEY_READ, pclsid); - if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64))) - hr = get_ps_clsid_from_registry(path, opposite | KEY_READ, pclsid); + hr = get_ps_clsid_from_registry(path, KEY_READ, pclsid); + if (FAILED(hr) && + (opposite == KEY_WOW64_32KEY || + (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64))) + hr = get_ps_clsid_from_registry(path, opposite | KEY_READ, pclsid); - if (hr == S_OK) - TRACE("() Returning CLSID %s\n", debugstr_guid(pclsid)); - else - WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid)); + if (hr == S_OK) + TRACE("() Returning CLSID %s\n", debugstr_guid(pclsid)); + else + WARN("No PSFactoryBuffer object is registered for IID %s\n", + debugstr_guid(riid)); - return hr; + return hr; } /***************************************************************************** * CoRegisterPSClsid (combase.@) */ -HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid) -{ - struct registered_ps *cur; +HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid) { + struct registered_ps *cur; - TRACE("%s, %s\n", debugstr_guid(riid), debugstr_guid(rclsid)); + TRACE("%s, %s\n", debugstr_guid(riid), debugstr_guid(rclsid)); - if (!InternalIsProcessInitialized()) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } + if (!InternalIsProcessInitialized()) { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } - EnterCriticalSection(&cs_registered_ps); + EnterCriticalSection(&cs_registered_ps); - LIST_FOR_EACH_ENTRY(cur, ®istered_proxystubs, struct registered_ps, entry) - { - if (IsEqualIID(&cur->iid, riid)) - { - cur->clsid = *rclsid; - LeaveCriticalSection(&cs_registered_ps); - return S_OK; - } + LIST_FOR_EACH_ENTRY(cur, ®istered_proxystubs, struct registered_ps, + entry) { + if (IsEqualIID(&cur->iid, riid)) { + cur->clsid = *rclsid; + LeaveCriticalSection(&cs_registered_ps); + return S_OK; } + } - cur = malloc(sizeof(*cur)); - if (!cur) - { - LeaveCriticalSection(&cs_registered_ps); - return E_OUTOFMEMORY; - } + cur = malloc(sizeof(*cur)); + if (!cur) { + LeaveCriticalSection(&cs_registered_ps); + return E_OUTOFMEMORY; + } - cur->iid = *riid; - cur->clsid = *rclsid; - list_add_head(®istered_proxystubs, &cur->entry); + cur->iid = *riid; + cur->clsid = *rclsid; + list_add_head(®istered_proxystubs, &cur->entry); - LeaveCriticalSection(&cs_registered_ps); + LeaveCriticalSection(&cs_registered_ps); - return S_OK; + return S_OK; } -struct thread_context -{ - IComThreadingInfo IComThreadingInfo_iface; - IContextCallback IContextCallback_iface; - IObjContext IObjContext_iface; - LONG refcount; +struct thread_context { + IComThreadingInfo IComThreadingInfo_iface; + IContextCallback IContextCallback_iface; + IObjContext IObjContext_iface; + LONG refcount; }; -static inline struct thread_context *impl_from_IComThreadingInfo(IComThreadingInfo *iface) -{ - return CONTAINING_RECORD(iface, struct thread_context, IComThreadingInfo_iface); +static inline struct thread_context * +impl_from_IComThreadingInfo(IComThreadingInfo *iface) { + return CONTAINING_RECORD(iface, struct thread_context, + IComThreadingInfo_iface); } -static inline struct thread_context *impl_from_IContextCallback(IContextCallback *iface) -{ - return CONTAINING_RECORD(iface, struct thread_context, IContextCallback_iface); +static inline struct thread_context * +impl_from_IContextCallback(IContextCallback *iface) { + return CONTAINING_RECORD(iface, struct thread_context, + IContextCallback_iface); } -static inline struct thread_context *impl_from_IObjContext(IObjContext *iface) -{ - return CONTAINING_RECORD(iface, struct thread_context, IObjContext_iface); +static inline struct thread_context *impl_from_IObjContext(IObjContext *iface) { + return CONTAINING_RECORD(iface, struct thread_context, IObjContext_iface); } -static HRESULT WINAPI thread_context_info_QueryInterface(IComThreadingInfo *iface, REFIID riid, void **obj) -{ - struct thread_context *context = impl_from_IComThreadingInfo(iface); +static HRESULT WINAPI thread_context_info_QueryInterface( + IComThreadingInfo *iface, REFIID riid, void **obj) { + struct thread_context *context = impl_from_IComThreadingInfo(iface); - *obj = NULL; + *obj = NULL; - if (IsEqualIID(riid, &IID_IComThreadingInfo) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = &context->IComThreadingInfo_iface; - } - else if (IsEqualIID(riid, &IID_IContextCallback)) - { - *obj = &context->IContextCallback_iface; - } - else if (IsEqualIID(riid, &IID_IObjContext)) - { - *obj = &context->IObjContext_iface; - } + if (IsEqualIID(riid, &IID_IComThreadingInfo) || + IsEqualIID(riid, &IID_IUnknown)) { + *obj = &context->IComThreadingInfo_iface; + } else if (IsEqualIID(riid, &IID_IContextCallback)) { + *obj = &context->IContextCallback_iface; + } else if (IsEqualIID(riid, &IID_IObjContext)) { + *obj = &context->IObjContext_iface; + } - if (*obj) - { - IUnknown_AddRef((IUnknown *)*obj); - return S_OK; - } + if (*obj) { + IUnknown_AddRef((IUnknown *)*obj); + return S_OK; + } - FIXME("interface not implemented %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; + FIXME("interface not implemented %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; } -static ULONG WINAPI thread_context_info_AddRef(IComThreadingInfo *iface) -{ - struct thread_context *context = impl_from_IComThreadingInfo(iface); - return InterlockedIncrement(&context->refcount); +static ULONG WINAPI thread_context_info_AddRef(IComThreadingInfo *iface) { + struct thread_context *context = impl_from_IComThreadingInfo(iface); + return InterlockedIncrement(&context->refcount); } -static ULONG WINAPI thread_context_info_Release(IComThreadingInfo *iface) -{ - struct thread_context *context = impl_from_IComThreadingInfo(iface); +static ULONG WINAPI thread_context_info_Release(IComThreadingInfo *iface) { + struct thread_context *context = impl_from_IComThreadingInfo(iface); - /* Context instance is initially created with CoGetContextToken() with refcount set to 0, - releasing context while refcount is at 0 destroys it. */ - if (!context->refcount) - { - free(context); - return 0; - } + /* Context instance is initially created with CoGetContextToken() with + refcount set to 0, releasing context while refcount is at 0 destroys it. */ + if (!context->refcount) { + free(context); + return 0; + } - return InterlockedDecrement(&context->refcount); + return InterlockedDecrement(&context->refcount); } -static HRESULT WINAPI thread_context_info_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype) -{ - APTTYPEQUALIFIER qualifier; +static HRESULT WINAPI thread_context_info_GetCurrentApartmentType( + IComThreadingInfo *iface, APTTYPE *apttype) { + APTTYPEQUALIFIER qualifier; - TRACE("%p\n", apttype); + TRACE("%p\n", apttype); - return CoGetApartmentType(apttype, &qualifier); + return CoGetApartmentType(apttype, &qualifier); } -static HRESULT WINAPI thread_context_info_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype) -{ - APTTYPEQUALIFIER qualifier; - APTTYPE apttype; - HRESULT hr; +static HRESULT WINAPI thread_context_info_GetCurrentThreadType( + IComThreadingInfo *iface, THDTYPE *thdtype) { + APTTYPEQUALIFIER qualifier; + APTTYPE apttype; + HRESULT hr; - hr = CoGetApartmentType(&apttype, &qualifier); - if (FAILED(hr)) - return hr; + hr = CoGetApartmentType(&apttype, &qualifier); + if (FAILED(hr)) + return hr; - TRACE("%p\n", thdtype); + TRACE("%p\n", thdtype); - switch (apttype) - { - case APTTYPE_STA: - case APTTYPE_MAINSTA: - *thdtype = THDTYPE_PROCESSMESSAGES; - break; - default: - *thdtype = THDTYPE_BLOCKMESSAGES; - break; - } - return S_OK; + switch (apttype) { + case APTTYPE_STA: + case APTTYPE_MAINSTA: + *thdtype = THDTYPE_PROCESSMESSAGES; + break; + default: + *thdtype = THDTYPE_BLOCKMESSAGES; + break; + } + return S_OK; } -static HRESULT WINAPI thread_context_info_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id) -{ - TRACE("%p\n", logical_thread_id); +static HRESULT WINAPI thread_context_info_GetCurrentLogicalThreadId( + IComThreadingInfo *iface, GUID *logical_thread_id) { + TRACE("%p\n", logical_thread_id); - return CoGetCurrentLogicalThreadId(logical_thread_id); + return CoGetCurrentLogicalThreadId(logical_thread_id); } -static HRESULT WINAPI thread_context_info_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id) -{ - FIXME("%s stub\n", debugstr_guid(logical_thread_id)); +static HRESULT WINAPI thread_context_info_SetCurrentLogicalThreadId( + IComThreadingInfo *iface, REFGUID logical_thread_id) { + FIXME("%s stub\n", debugstr_guid(logical_thread_id)); - return E_NOTIMPL; + return E_NOTIMPL; } -static const IComThreadingInfoVtbl thread_context_info_vtbl = -{ +static const IComThreadingInfoVtbl thread_context_info_vtbl = { thread_context_info_QueryInterface, thread_context_info_AddRef, thread_context_info_Release, thread_context_info_GetCurrentApartmentType, thread_context_info_GetCurrentThreadType, thread_context_info_GetCurrentLogicalThreadId, - thread_context_info_SetCurrentLogicalThreadId -}; + thread_context_info_SetCurrentLogicalThreadId}; -static HRESULT WINAPI thread_context_callback_QueryInterface(IContextCallback *iface, REFIID riid, void **obj) -{ - struct thread_context *context = impl_from_IContextCallback(iface); - return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj); +static HRESULT WINAPI thread_context_callback_QueryInterface( + IContextCallback *iface, REFIID riid, void **obj) { + struct thread_context *context = impl_from_IContextCallback(iface); + return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, + riid, obj); } -static ULONG WINAPI thread_context_callback_AddRef(IContextCallback *iface) -{ - struct thread_context *context = impl_from_IContextCallback(iface); - return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface); +static ULONG WINAPI thread_context_callback_AddRef(IContextCallback *iface) { + struct thread_context *context = impl_from_IContextCallback(iface); + return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface); } -static ULONG WINAPI thread_context_callback_Release(IContextCallback *iface) -{ - struct thread_context *context = impl_from_IContextCallback(iface); - return IComThreadingInfo_Release(&context->IComThreadingInfo_iface); +static ULONG WINAPI thread_context_callback_Release(IContextCallback *iface) { + struct thread_context *context = impl_from_IContextCallback(iface); + return IComThreadingInfo_Release(&context->IComThreadingInfo_iface); } -static HRESULT WINAPI thread_context_callback_ContextCallback(IContextCallback *iface, - PFNCONTEXTCALL callback, ComCallData *param, REFIID riid, int method, IUnknown *punk) -{ - FIXME("%p, %p, %p, %s, %d, %p\n", iface, callback, param, debugstr_guid(riid), method, punk); +static HRESULT WINAPI thread_context_callback_ContextCallback( + IContextCallback *iface, PFNCONTEXTCALL callback, ComCallData *param, + REFIID riid, int method, IUnknown *punk) { + FIXME("%p, %p, %p, %s, %d, %p\n", iface, callback, param, debugstr_guid(riid), + method, punk); - return E_NOTIMPL; + return E_NOTIMPL; } -static const IContextCallbackVtbl thread_context_callback_vtbl = -{ - thread_context_callback_QueryInterface, - thread_context_callback_AddRef, - thread_context_callback_Release, - thread_context_callback_ContextCallback -}; +static const IContextCallbackVtbl thread_context_callback_vtbl = { + thread_context_callback_QueryInterface, thread_context_callback_AddRef, + thread_context_callback_Release, thread_context_callback_ContextCallback}; -static HRESULT WINAPI thread_object_context_QueryInterface(IObjContext *iface, REFIID riid, void **obj) -{ - struct thread_context *context = impl_from_IObjContext(iface); - return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj); +static HRESULT WINAPI thread_object_context_QueryInterface(IObjContext *iface, + REFIID riid, + void **obj) { + struct thread_context *context = impl_from_IObjContext(iface); + return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, + riid, obj); } -static ULONG WINAPI thread_object_context_AddRef(IObjContext *iface) -{ - struct thread_context *context = impl_from_IObjContext(iface); - return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface); +static ULONG WINAPI thread_object_context_AddRef(IObjContext *iface) { + struct thread_context *context = impl_from_IObjContext(iface); + return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface); } -static ULONG WINAPI thread_object_context_Release(IObjContext *iface) -{ - struct thread_context *context = impl_from_IObjContext(iface); - return IComThreadingInfo_Release(&context->IComThreadingInfo_iface); +static ULONG WINAPI thread_object_context_Release(IObjContext *iface) { + struct thread_context *context = impl_from_IObjContext(iface); + return IComThreadingInfo_Release(&context->IComThreadingInfo_iface); } -static HRESULT WINAPI thread_object_context_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk) -{ - FIXME("%p, %s, %lx, %p\n", iface, debugstr_guid(propid), flags, punk); +static HRESULT WINAPI thread_object_context_SetProperty(IObjContext *iface, + REFGUID propid, + CPFLAGS flags, + IUnknown *punk) { + FIXME("%p, %s, %lx, %p\n", iface, debugstr_guid(propid), flags, punk); - return E_NOTIMPL; + return E_NOTIMPL; } -static HRESULT WINAPI thread_object_context_RemoveProperty(IObjContext *iface, REFGUID propid) -{ - FIXME("%p, %s\n", iface, debugstr_guid(propid)); +static HRESULT WINAPI thread_object_context_RemoveProperty(IObjContext *iface, + REFGUID propid) { + FIXME("%p, %s\n", iface, debugstr_guid(propid)); - return E_NOTIMPL; + return E_NOTIMPL; } -static HRESULT WINAPI thread_object_context_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk) -{ - FIXME("%p, %s, %p, %p\n", iface, debugstr_guid(propid), flags, punk); +static HRESULT WINAPI thread_object_context_GetProperty(IObjContext *iface, + REFGUID propid, + CPFLAGS *flags, + IUnknown **punk) { + FIXME("%p, %s, %p, %p\n", iface, debugstr_guid(propid), flags, punk); - return E_NOTIMPL; + return E_NOTIMPL; } -static HRESULT WINAPI thread_object_context_EnumContextProps(IObjContext *iface, IEnumContextProps **props) -{ - FIXME("%p, %p\n", iface, props); +static HRESULT WINAPI thread_object_context_EnumContextProps( + IObjContext *iface, IEnumContextProps **props) { + FIXME("%p, %p\n", iface, props); - return E_NOTIMPL; + return E_NOTIMPL; } -static void WINAPI thread_object_context_Reserved1(IObjContext *iface) -{ - FIXME("%p\n", iface); +static void WINAPI thread_object_context_Reserved1(IObjContext *iface) { + FIXME("%p\n", iface); } -static void WINAPI thread_object_context_Reserved2(IObjContext *iface) -{ - FIXME("%p\n", iface); +static void WINAPI thread_object_context_Reserved2(IObjContext *iface) { + FIXME("%p\n", iface); } -static void WINAPI thread_object_context_Reserved3(IObjContext *iface) -{ - FIXME("%p\n", iface); +static void WINAPI thread_object_context_Reserved3(IObjContext *iface) { + FIXME("%p\n", iface); } -static void WINAPI thread_object_context_Reserved4(IObjContext *iface) -{ - FIXME("%p\n", iface); +static void WINAPI thread_object_context_Reserved4(IObjContext *iface) { + FIXME("%p\n", iface); } -static void WINAPI thread_object_context_Reserved5(IObjContext *iface) -{ - FIXME("%p\n", iface); +static void WINAPI thread_object_context_Reserved5(IObjContext *iface) { + FIXME("%p\n", iface); } -static void WINAPI thread_object_context_Reserved6(IObjContext *iface) -{ - FIXME("%p\n", iface); +static void WINAPI thread_object_context_Reserved6(IObjContext *iface) { + FIXME("%p\n", iface); } -static void WINAPI thread_object_context_Reserved7(IObjContext *iface) -{ - FIXME("%p\n", iface); +static void WINAPI thread_object_context_Reserved7(IObjContext *iface) { + FIXME("%p\n", iface); } -static const IObjContextVtbl thread_object_context_vtbl = -{ - thread_object_context_QueryInterface, - thread_object_context_AddRef, - thread_object_context_Release, - thread_object_context_SetProperty, - thread_object_context_RemoveProperty, - thread_object_context_GetProperty, - thread_object_context_EnumContextProps, - thread_object_context_Reserved1, - thread_object_context_Reserved2, - thread_object_context_Reserved3, - thread_object_context_Reserved4, - thread_object_context_Reserved5, - thread_object_context_Reserved6, - thread_object_context_Reserved7 -}; +static const IObjContextVtbl thread_object_context_vtbl = { + thread_object_context_QueryInterface, thread_object_context_AddRef, + thread_object_context_Release, thread_object_context_SetProperty, + thread_object_context_RemoveProperty, thread_object_context_GetProperty, + thread_object_context_EnumContextProps, thread_object_context_Reserved1, + thread_object_context_Reserved2, thread_object_context_Reserved3, + thread_object_context_Reserved4, thread_object_context_Reserved5, + thread_object_context_Reserved6, thread_object_context_Reserved7}; /*********************************************************************** * CoGetContextToken (combase.@) */ -HRESULT WINAPI CoGetContextToken(ULONG_PTR *token) -{ - struct tlsdata *tlsdata; - HRESULT hr; +HRESULT WINAPI CoGetContextToken(ULONG_PTR *token) { + struct tlsdata *tlsdata; + HRESULT hr; - TRACE("%p\n", token); + TRACE("%p\n", token); - if (!InternalIsProcessInitialized()) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } + if (!InternalIsProcessInitialized()) { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; - if (!token) - return E_POINTER; + if (!token) + return E_POINTER; - if (!tlsdata->context_token) - { - struct thread_context *context; + if (!tlsdata->context_token) { + struct thread_context *context; - context = calloc(1, sizeof(*context)); - if (!context) - return E_OUTOFMEMORY; + context = calloc(1, sizeof(*context)); + if (!context) + return E_OUTOFMEMORY; - context->IComThreadingInfo_iface.lpVtbl = &thread_context_info_vtbl; - context->IContextCallback_iface.lpVtbl = &thread_context_callback_vtbl; - context->IObjContext_iface.lpVtbl = &thread_object_context_vtbl; - /* Context token does not take a reference, it's always zero until the - interface is explicitly requested with CoGetObjectContext(). */ - context->refcount = 0; + context->IComThreadingInfo_iface.lpVtbl = &thread_context_info_vtbl; + context->IContextCallback_iface.lpVtbl = &thread_context_callback_vtbl; + context->IObjContext_iface.lpVtbl = &thread_object_context_vtbl; + /* Context token does not take a reference, it's always zero until the + interface is explicitly requested with CoGetObjectContext(). */ + context->refcount = 0; - tlsdata->context_token = &context->IObjContext_iface; - } + tlsdata->context_token = &context->IObjContext_iface; + } - *token = (ULONG_PTR)tlsdata->context_token; - TRACE("context_token %p\n", tlsdata->context_token); + *token = (ULONG_PTR)tlsdata->context_token; + TRACE("context_token %p\n", tlsdata->context_token); - return S_OK; + return S_OK; } /*********************************************************************** * CoGetCurrentLogicalThreadId (combase.@) */ -HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id) -{ - struct tlsdata *tlsdata; - HRESULT hr; +HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id) { + struct tlsdata *tlsdata; + HRESULT hr; - if (!id) - return E_INVALIDARG; + if (!id) + return E_INVALIDARG; - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; - if (IsEqualGUID(&tlsdata->causality_id, &GUID_NULL)) - { - CoCreateGuid(&tlsdata->causality_id); - tlsdata->flags |= OLETLS_UUIDINITIALIZED; - } + if (IsEqualGUID(&tlsdata->causality_id, &GUID_NULL)) { + CoCreateGuid(&tlsdata->causality_id); + tlsdata->flags |= OLETLS_UUIDINITIALIZED; + } - *id = tlsdata->causality_id; + *id = tlsdata->causality_id; - return S_OK; + return S_OK; } /****************************************************************************** * CoGetCurrentProcess (combase.@) */ -DWORD WINAPI CoGetCurrentProcess(void) -{ - struct tlsdata *tlsdata; +DWORD WINAPI CoGetCurrentProcess(void) { + struct tlsdata *tlsdata; - if (FAILED(com_get_tlsdata(&tlsdata))) - return 0; + if (FAILED(com_get_tlsdata(&tlsdata))) + return 0; - if (!tlsdata->thread_seqid) - rpcss_get_next_seqid(&tlsdata->thread_seqid); + if (!tlsdata->thread_seqid) + rpcss_get_next_seqid(&tlsdata->thread_seqid); - return tlsdata->thread_seqid; + return tlsdata->thread_seqid; } /*********************************************************************** * CoFreeUnusedLibrariesEx (combase.@) */ -void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD unload_delay, DWORD reserved) -{ - struct apartment *apt = com_get_current_apt(); - if (!apt) - { - ERR("apartment not initialised\n"); - return; - } +void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD unload_delay, + DWORD reserved) { + struct apartment *apt = com_get_current_apt(); + if (!apt) { + ERR("apartment not initialised\n"); + return; + } - apartment_freeunusedlibraries(apt, unload_delay); + apartment_freeunusedlibraries(apt, unload_delay); } /* * When locked, don't modify list (unless we add a new head), so that it's * safe to iterate it. Freeing of list entries is delayed and done on unlock. */ -static inline void lock_init_spies(struct tlsdata *tlsdata) -{ - tlsdata->spies_lock++; +static inline void lock_init_spies(struct tlsdata *tlsdata) { + tlsdata->spies_lock++; } -static void unlock_init_spies(struct tlsdata *tlsdata) -{ - struct init_spy *spy, *next; +static void unlock_init_spies(struct tlsdata *tlsdata) { + struct init_spy *spy, *next; - if (--tlsdata->spies_lock) return; + if (--tlsdata->spies_lock) + return; - LIST_FOR_EACH_ENTRY_SAFE(spy, next, &tlsdata->spies, struct init_spy, entry) - { - if (spy->spy) continue; - list_remove(&spy->entry); - free(spy); - } + LIST_FOR_EACH_ENTRY_SAFE(spy, next, &tlsdata->spies, struct init_spy, entry) { + if (spy->spy) + continue; + list_remove(&spy->entry); + free(spy); + } } /****************************************************************************** * CoInitializeWOW (combase.@) */ -HRESULT WINAPI CoInitializeWOW(DWORD arg1, DWORD arg2) -{ - FIXME("%#lx, %#lx\n", arg1, arg2); +HRESULT WINAPI CoInitializeWOW(DWORD arg1, DWORD arg2) { + FIXME("%#lx, %#lx\n", arg1, arg2); - return S_OK; + return S_OK; } /****************************************************************************** * CoInitializeEx (combase.@) */ -HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(void *reserved, DWORD model) -{ - struct tlsdata *tlsdata; - struct init_spy *cursor; - HRESULT hr; +HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(void *reserved, DWORD model) { + struct tlsdata *tlsdata; + struct init_spy *cursor; + HRESULT hr; - TRACE("%p, %#lx\n", reserved, model); + TRACE("%p, %#lx\n", reserved, model); - if (reserved) - WARN("Unexpected reserved argument %p\n", reserved); + if (reserved) + WARN("Unexpected reserved argument %p\n", reserved); - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; - if (InterlockedExchangeAdd(&com_lockcount, 1) == 0) - TRACE("Initializing the COM libraries\n"); + if (InterlockedExchangeAdd(&com_lockcount, 1) == 0) + TRACE("Initializing the COM libraries\n"); - lock_init_spies(tlsdata); - LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry) - { - if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, model, tlsdata->inits); - } - unlock_init_spies(tlsdata); + lock_init_spies(tlsdata); + LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry) { + if (cursor->spy) + IInitializeSpy_PreInitialize(cursor->spy, model, tlsdata->inits); + } + unlock_init_spies(tlsdata); - hr = enter_apartment(tlsdata, model); + hr = enter_apartment(tlsdata, model); - lock_init_spies(tlsdata); - LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry) - { - if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, model, tlsdata->inits); - } - unlock_init_spies(tlsdata); + lock_init_spies(tlsdata); + LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry) { + if (cursor->spy) + hr = + IInitializeSpy_PostInitialize(cursor->spy, hr, model, tlsdata->inits); + } + unlock_init_spies(tlsdata); - return hr; + return hr; } /*********************************************************************** * CoUninitialize (combase.@) */ -void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void) -{ - struct tlsdata *tlsdata; - struct init_spy *cursor, *next; - LONG lockcount; +void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void) { + struct tlsdata *tlsdata; + struct init_spy *cursor, *next; + LONG lockcount; - TRACE("\n"); + TRACE("\n"); - if (FAILED(com_get_tlsdata(&tlsdata))) - return; + if (FAILED(com_get_tlsdata(&tlsdata))) + return; + + lock_init_spies(tlsdata); + LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, + entry) { + if (cursor->spy) + IInitializeSpy_PreUninitialize(cursor->spy, tlsdata->inits); + } + unlock_init_spies(tlsdata); + + /* sanity check */ + if (!tlsdata->inits) { + ERR("Mismatched CoUninitialize\n"); lock_init_spies(tlsdata); - LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry) - { - if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, tlsdata->inits); + LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, + entry) { + if (cursor->spy) + IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits); } unlock_init_spies(tlsdata); - /* sanity check */ - if (!tlsdata->inits) - { - ERR("Mismatched CoUninitialize\n"); + return; + } - lock_init_spies(tlsdata); - LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry) - { - if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits); - } - unlock_init_spies(tlsdata); + leave_apartment(tlsdata); - return; - } + /* + * Decrease the reference count. + * If we are back to 0 locks on the COM library, make sure we free + * all the associated data structures. + */ + lockcount = InterlockedExchangeAdd(&com_lockcount, -1); + if (lockcount == 1) { + TRACE("Releasing the COM libraries\n"); - leave_apartment(tlsdata); - - /* - * Decrease the reference count. - * If we are back to 0 locks on the COM library, make sure we free - * all the associated data structures. - */ - lockcount = InterlockedExchangeAdd(&com_lockcount, -1); - if (lockcount == 1) - { - TRACE("Releasing the COM libraries\n"); - - com_revoke_all_ps_clsids(); - DestroyRunningObjectTable(); - } - else if (lockcount < 1) - { - ERR("Unbalanced lock count %ld\n", lockcount); - InterlockedExchangeAdd(&com_lockcount, 1); - } + com_revoke_all_ps_clsids(); + DestroyRunningObjectTable(); + } else if (lockcount < 1) { + ERR("Unbalanced lock count %ld\n", lockcount); + InterlockedExchangeAdd(&com_lockcount, 1); + } - lock_init_spies(tlsdata); - LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry) - { - if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits); - } - unlock_init_spies(tlsdata); + lock_init_spies(tlsdata); + LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry) { + if (cursor->spy) + IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits); + } + unlock_init_spies(tlsdata); } /*********************************************************************** * CoIncrementMTAUsage (combase.@) */ -HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie) -{ - TRACE("%p\n", cookie); +HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie) { + TRACE("%p\n", cookie); - return apartment_increment_mta_usage(cookie); + return apartment_increment_mta_usage(cookie); } /*********************************************************************** * CoDecrementMTAUsage (combase.@) */ -HRESULT WINAPI CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie) -{ - TRACE("%p\n", cookie); +HRESULT WINAPI CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie) { + TRACE("%p\n", cookie); - apartment_decrement_mta_usage(cookie); - return S_OK; + apartment_decrement_mta_usage(cookie); + return S_OK; } /*********************************************************************** * CoGetApartmentType (combase.@) */ -HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) -{ - struct tlsdata *tlsdata; - struct apartment *apt; - HRESULT hr; +HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) { + struct tlsdata *tlsdata; + struct apartment *apt; + HRESULT hr; - TRACE("%p, %p\n", type, qualifier); + TRACE("%p, %p\n", type, qualifier); - if (!type || !qualifier) - return E_INVALIDARG; + if (!type || !qualifier) + return E_INVALIDARG; - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; - if (!tlsdata->apt) - *type = APTTYPE_CURRENT; - else if (tlsdata->apt->multi_threaded) - *type = APTTYPE_MTA; - else if (tlsdata->apt->main) - *type = APTTYPE_MAINSTA; - else - *type = APTTYPE_STA; + if (!tlsdata->apt) + *type = APTTYPE_CURRENT; + else if (tlsdata->apt->multi_threaded) + *type = APTTYPE_MTA; + else if (tlsdata->apt->main) + *type = APTTYPE_MAINSTA; + else + *type = APTTYPE_STA; - *qualifier = APTTYPEQUALIFIER_NONE; + *qualifier = APTTYPEQUALIFIER_NONE; - if (!tlsdata->apt && (apt = apartment_get_mta())) - { - apartment_release(apt); - *type = APTTYPE_MTA; - *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA; - return S_OK; - } + if (!tlsdata->apt && (apt = apartment_get_mta())) { + apartment_release(apt); + *type = APTTYPE_MTA; + *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA; + return S_OK; + } - return tlsdata->apt ? S_OK : CO_E_NOTINITIALIZED; + return tlsdata->apt ? S_OK : CO_E_NOTINITIALIZED; } /****************************************************************************** @@ -2950,450 +2888,422 @@ HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) * MSDN claims that multiple interface registrations are legal, but we * can't do that with our current implementation. */ -HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD clscontext, - DWORD flags, DWORD *cookie) -{ - static LONG next_cookie; - - struct registered_class *newclass; - IUnknown *found_object; - struct apartment *apt; - HRESULT hr = S_OK; - - TRACE("%s, %p, %#lx, %#lx, %p\n", debugstr_guid(rclsid), object, clscontext, flags, cookie); - - if (!cookie || !object) - return E_INVALIDARG; - - if (!(apt = apartment_get_current_or_mta())) - { - ERR("COM was not initialized\n"); - return CO_E_NOTINITIALIZED; - } - - *cookie = 0; - - /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what - * differentiates the flag from REGCLS_MULTI_SEPARATE. */ - if (flags & REGCLS_MULTIPLEUSE) - clscontext |= CLSCTX_INPROC_SERVER; - - /* - * First, check if the class is already registered. - * If it is, this should cause an error. - */ - if ((found_object = com_get_registered_class_object(apt, rclsid, clscontext))) - { - if (flags & REGCLS_MULTIPLEUSE) - { - if (clscontext & CLSCTX_LOCAL_SERVER) - hr = CoLockObjectExternal(found_object, TRUE, FALSE); - IUnknown_Release(found_object); - apartment_release(apt); - return hr; - } - - IUnknown_Release(found_object); - ERR("object already registered for class %s\n", debugstr_guid(rclsid)); - apartment_release(apt); - return CO_E_OBJISREG; - } - - newclass = calloc(1, sizeof(*newclass)); - if (!newclass) - { - apartment_release(apt); - return E_OUTOFMEMORY; - } +HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, + DWORD clscontext, DWORD flags, + DWORD *cookie) { + static LONG next_cookie; + + struct registered_class *newclass; + IUnknown *found_object; + struct apartment *apt; + HRESULT hr = S_OK; + + TRACE("%s, %p, %#lx, %#lx, %p\n", debugstr_guid(rclsid), object, clscontext, + flags, cookie); + + if (!cookie || !object) + return E_INVALIDARG; + + if (!(apt = apartment_get_current_or_mta())) { + ERR("COM was not initialized\n"); + return CO_E_NOTINITIALIZED; + } + + *cookie = 0; + + /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what + * differentiates the flag from REGCLS_MULTI_SEPARATE. */ + if (flags & REGCLS_MULTIPLEUSE) + clscontext |= CLSCTX_INPROC_SERVER; + + /* + * First, check if the class is already registered. + * If it is, this should cause an error. + */ + if ((found_object = + com_get_registered_class_object(apt, rclsid, clscontext))) { + if (flags & REGCLS_MULTIPLEUSE) { + if (clscontext & CLSCTX_LOCAL_SERVER) + hr = CoLockObjectExternal(found_object, TRUE, FALSE); + IUnknown_Release(found_object); + apartment_release(apt); + return hr; + } + + IUnknown_Release(found_object); + ERR("object already registered for class %s\n", debugstr_guid(rclsid)); + apartment_release(apt); + return CO_E_OBJISREG; + } - newclass->clsid = *rclsid; - newclass->apartment_id = apt->oxid; - newclass->clscontext = clscontext; - newclass->flags = flags; + newclass = calloc(1, sizeof(*newclass)); + if (!newclass) { + apartment_release(apt); + return E_OUTOFMEMORY; + } - if (!(newclass->cookie = InterlockedIncrement(&next_cookie))) - newclass->cookie = InterlockedIncrement(&next_cookie); + newclass->clsid = *rclsid; + newclass->apartment_id = apt->oxid; + newclass->clscontext = clscontext; + newclass->flags = flags; - newclass->object = object; - IUnknown_AddRef(newclass->object); + if (!(newclass->cookie = InterlockedIncrement(&next_cookie))) + newclass->cookie = InterlockedIncrement(&next_cookie); - EnterCriticalSection(®istered_classes_cs); - list_add_tail(®istered_classes, &newclass->entry); - LeaveCriticalSection(®istered_classes_cs); + newclass->object = object; + IUnknown_AddRef(newclass->object); - *cookie = newclass->cookie; + EnterCriticalSection(®istered_classes_cs); + list_add_tail(®istered_classes, &newclass->entry); + LeaveCriticalSection(®istered_classes_cs); - if (clscontext & CLSCTX_LOCAL_SERVER) - { - IStream *marshal_stream; + *cookie = newclass->cookie; - hr = apartment_get_local_server_stream(apt, &marshal_stream); - if(FAILED(hr)) - { - apartment_release(apt); - return hr; - } + if (clscontext & CLSCTX_LOCAL_SERVER) { + IStream *marshal_stream; - hr = rpc_register_local_server(&newclass->clsid, marshal_stream, flags, &newclass->rpcss_cookie); - IStream_Release(marshal_stream); + hr = apartment_get_local_server_stream(apt, &marshal_stream); + if (FAILED(hr)) { + apartment_release(apt); + return hr; } - apartment_release(apt); - return S_OK; + hr = rpc_register_local_server(&newclass->clsid, marshal_stream, flags, + &newclass->rpcss_cookie); + IStream_Release(marshal_stream); + } + + apartment_release(apt); + return S_OK; } -static void com_revoke_class_object(struct registered_class *entry) -{ - list_remove(&entry->entry); +static void com_revoke_class_object(struct registered_class *entry) { + list_remove(&entry->entry); - if (entry->clscontext & CLSCTX_LOCAL_SERVER) - rpc_revoke_local_server(entry->rpcss_cookie); + if (entry->clscontext & CLSCTX_LOCAL_SERVER) + rpc_revoke_local_server(entry->rpcss_cookie); - IUnknown_Release(entry->object); - free(entry); + IUnknown_Release(entry->object); + free(entry); } /* Cleans up rpcss registry */ -static void com_revoke_local_servers(void) -{ - struct registered_class *cur, *cur2; +static void com_revoke_local_servers(void) { + struct registered_class *cur, *cur2; - EnterCriticalSection(®istered_classes_cs); + EnterCriticalSection(®istered_classes_cs); - LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, ®istered_classes, struct registered_class, entry) - { - if (cur->clscontext & CLSCTX_LOCAL_SERVER) - com_revoke_class_object(cur); - } + LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, ®istered_classes, + struct registered_class, entry) { + if (cur->clscontext & CLSCTX_LOCAL_SERVER) + com_revoke_class_object(cur); + } - LeaveCriticalSection(®istered_classes_cs); + LeaveCriticalSection(®istered_classes_cs); } -void apartment_revoke_all_classes(const struct apartment *apt) -{ - struct registered_class *cur, *cur2; +void apartment_revoke_all_classes(const struct apartment *apt) { + struct registered_class *cur, *cur2; - EnterCriticalSection(®istered_classes_cs); + EnterCriticalSection(®istered_classes_cs); - LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, ®istered_classes, struct registered_class, entry) - { - if (cur->apartment_id == apt->oxid) - com_revoke_class_object(cur); - } + LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, ®istered_classes, + struct registered_class, entry) { + if (cur->apartment_id == apt->oxid) + com_revoke_class_object(cur); + } - LeaveCriticalSection(®istered_classes_cs); + LeaveCriticalSection(®istered_classes_cs); } /*********************************************************************** * CoRevokeClassObject (combase.@) */ -HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(DWORD cookie) -{ - HRESULT hr = E_INVALIDARG; - struct registered_class *cur; - struct apartment *apt; +HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(DWORD cookie) { + HRESULT hr = E_INVALIDARG; + struct registered_class *cur; + struct apartment *apt; - TRACE("%#lx\n", cookie); + TRACE("%#lx\n", cookie); - if (!(apt = apartment_get_current_or_mta())) - { - ERR("COM was not initialized\n"); - return CO_E_NOTINITIALIZED; - } - - EnterCriticalSection(®istered_classes_cs); + if (!(apt = apartment_get_current_or_mta())) { + ERR("COM was not initialized\n"); + return CO_E_NOTINITIALIZED; + } - LIST_FOR_EACH_ENTRY(cur, ®istered_classes, struct registered_class, entry) - { - if (cur->cookie != cookie) - continue; + EnterCriticalSection(®istered_classes_cs); - if (cur->apartment_id == apt->oxid) - { - com_revoke_class_object(cur); - hr = S_OK; - } - else - { - ERR("called from wrong apartment, should be called from %s\n", wine_dbgstr_longlong(cur->apartment_id)); - hr = RPC_E_WRONG_THREAD; - } + LIST_FOR_EACH_ENTRY(cur, ®istered_classes, struct registered_class, + entry) { + if (cur->cookie != cookie) + continue; - break; + if (cur->apartment_id == apt->oxid) { + com_revoke_class_object(cur); + hr = S_OK; + } else { + ERR("called from wrong apartment, should be called from %s\n", + wine_dbgstr_longlong(cur->apartment_id)); + hr = RPC_E_WRONG_THREAD; } - LeaveCriticalSection(®istered_classes_cs); - apartment_release(apt); + break; + } - return hr; + LeaveCriticalSection(®istered_classes_cs); + apartment_release(apt); + + return hr; } /*********************************************************************** * CoAddRefServerProcess (combase.@) */ -ULONG WINAPI CoAddRefServerProcess(void) -{ - ULONG refs; +ULONG WINAPI CoAddRefServerProcess(void) { + ULONG refs; - TRACE("\n"); + TRACE("\n"); - EnterCriticalSection(®istered_classes_cs); - refs = ++com_server_process_refcount; - LeaveCriticalSection(®istered_classes_cs); + EnterCriticalSection(®istered_classes_cs); + refs = ++com_server_process_refcount; + LeaveCriticalSection(®istered_classes_cs); - TRACE("refs before: %ld\n", refs - 1); + TRACE("refs before: %ld\n", refs - 1); - return refs; + return refs; } /*********************************************************************** * CoReleaseServerProcess [OLE32.@] */ -ULONG WINAPI CoReleaseServerProcess(void) -{ - ULONG refs; +ULONG WINAPI CoReleaseServerProcess(void) { + ULONG refs; - TRACE("\n"); + TRACE("\n"); - EnterCriticalSection(®istered_classes_cs); + EnterCriticalSection(®istered_classes_cs); - refs = --com_server_process_refcount; - /* FIXME: suspend objects */ + refs = --com_server_process_refcount; + /* FIXME: suspend objects */ - LeaveCriticalSection(®istered_classes_cs); + LeaveCriticalSection(®istered_classes_cs); - TRACE("refs after: %ld\n", refs); + TRACE("refs after: %ld\n", refs); - return refs; + return refs; } /****************************************************************************** * CoDisconnectObject (combase.@) */ -HRESULT WINAPI CoDisconnectObject(IUnknown *object, DWORD reserved) -{ - struct stub_manager *manager; - struct apartment *apt; - IMarshal *marshal; - HRESULT hr; +HRESULT WINAPI CoDisconnectObject(IUnknown *object, DWORD reserved) { + struct stub_manager *manager; + struct apartment *apt; + IMarshal *marshal; + HRESULT hr; - TRACE("%p, %#lx\n", object, reserved); + TRACE("%p, %#lx\n", object, reserved); - if (!object) - return E_INVALIDARG; + if (!object) + return E_INVALIDARG; - hr = IUnknown_QueryInterface(object, &IID_IMarshal, (void **)&marshal); - if (hr == S_OK) - { - hr = IMarshal_DisconnectObject(marshal, reserved); - IMarshal_Release(marshal); - return hr; - } + hr = IUnknown_QueryInterface(object, &IID_IMarshal, (void **)&marshal); + if (hr == S_OK) { + hr = IMarshal_DisconnectObject(marshal, reserved); + IMarshal_Release(marshal); + return hr; + } - if (!(apt = apartment_get_current_or_mta())) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } + if (!(apt = apartment_get_current_or_mta())) { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } - manager = get_stub_manager_from_object(apt, object, FALSE); - if (manager) - { - stub_manager_disconnect(manager); - /* Release stub manager twice, to remove the apartment reference. */ - stub_manager_int_release(manager); - stub_manager_int_release(manager); - } + manager = get_stub_manager_from_object(apt, object, FALSE); + if (manager) { + stub_manager_disconnect(manager); + /* Release stub manager twice, to remove the apartment reference. */ + stub_manager_int_release(manager); + stub_manager_int_release(manager); + } - /* Note: native is pretty broken here because it just silently - * fails, without returning an appropriate error code if the object was - * not found, making apps think that the object was disconnected, when - * it actually wasn't */ + /* Note: native is pretty broken here because it just silently + * fails, without returning an appropriate error code if the object was + * not found, making apps think that the object was disconnected, when + * it actually wasn't */ - apartment_release(apt); - return S_OK; + apartment_release(apt); + return S_OK; } /****************************************************************************** * CoLockObjectExternal (combase.@) */ -HRESULT WINAPI CoLockObjectExternal(IUnknown *object, BOOL lock, BOOL last_unlock_releases) -{ - struct stub_manager *stubmgr; - struct apartment *apt; - - TRACE("%p, %d, %d\n", object, lock, last_unlock_releases); +HRESULT WINAPI CoLockObjectExternal(IUnknown *object, BOOL lock, + BOOL last_unlock_releases) { + struct stub_manager *stubmgr; + struct apartment *apt; - if (!(apt = apartment_get_current_or_mta())) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } - - stubmgr = get_stub_manager_from_object(apt, object, lock); - if (!stubmgr) - { - WARN("stub object not found %p\n", object); - /* Note: native is pretty broken here because it just silently - * fails, without returning an appropriate error code, making apps - * think that the object was disconnected, when it actually wasn't */ - apartment_release(apt); - return S_OK; - } + TRACE("%p, %d, %d\n", object, lock, last_unlock_releases); - if (lock) - stub_manager_ext_addref(stubmgr, 1, FALSE); - else - stub_manager_ext_release(stubmgr, 1, FALSE, last_unlock_releases); + if (!(apt = apartment_get_current_or_mta())) { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } - stub_manager_int_release(stubmgr); + stubmgr = get_stub_manager_from_object(apt, object, lock); + if (!stubmgr) { + WARN("stub object not found %p\n", object); + /* Note: native is pretty broken here because it just silently + * fails, without returning an appropriate error code, making apps + * think that the object was disconnected, when it actually wasn't */ apartment_release(apt); return S_OK; + } + + if (lock) + stub_manager_ext_addref(stubmgr, 1, FALSE); + else + stub_manager_ext_release(stubmgr, 1, FALSE, last_unlock_releases); + + stub_manager_int_release(stubmgr); + apartment_release(apt); + return S_OK; } /*********************************************************************** * CoRegisterChannelHook (combase.@) */ -HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *channel_hook) -{ - TRACE("%s, %p\n", debugstr_guid(guidExtension), channel_hook); +HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, + IChannelHook *channel_hook) { + TRACE("%s, %p\n", debugstr_guid(guidExtension), channel_hook); - return rpc_register_channel_hook(guidExtension, channel_hook); + return rpc_register_channel_hook(guidExtension, channel_hook); } /*********************************************************************** * CoDisableCallCancellation (combase.@) */ -HRESULT WINAPI CoDisableCallCancellation(void *reserved) -{ - struct tlsdata *tlsdata; - HRESULT hr; +HRESULT WINAPI CoDisableCallCancellation(void *reserved) { + struct tlsdata *tlsdata; + HRESULT hr; - TRACE("%p\n", reserved); + TRACE("%p\n", reserved); - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; - if (!tlsdata->cancelcount) - return CO_E_CANCEL_DISABLED; + if (!tlsdata->cancelcount) + return CO_E_CANCEL_DISABLED; - tlsdata->cancelcount--; + tlsdata->cancelcount--; - return S_OK; + return S_OK; } /*********************************************************************** * CoEnableCallCancellation (combase.@) */ -HRESULT WINAPI CoEnableCallCancellation(void *reserved) -{ - struct tlsdata *tlsdata; - HRESULT hr; +HRESULT WINAPI CoEnableCallCancellation(void *reserved) { + struct tlsdata *tlsdata; + HRESULT hr; - TRACE("%p\n", reserved); + TRACE("%p\n", reserved); - if (FAILED(hr = com_get_tlsdata(&tlsdata))) - return hr; + if (FAILED(hr = com_get_tlsdata(&tlsdata))) + return hr; - tlsdata->cancelcount++; + tlsdata->cancelcount++; - return S_OK; + return S_OK; } /*********************************************************************** * CoGetCallerTID (combase.@) */ -HRESULT WINAPI CoGetCallerTID(DWORD *tid) -{ - FIXME("stub!\n"); - return E_NOTIMPL; +HRESULT WINAPI CoGetCallerTID(DWORD *tid) { + FIXME("stub!\n"); + return E_NOTIMPL; } /*********************************************************************** * CoIsHandlerConnected (combase.@) */ -BOOL WINAPI CoIsHandlerConnected(IUnknown *object) -{ - FIXME("%p\n", object); +BOOL WINAPI CoIsHandlerConnected(IUnknown *object) { + FIXME("%p\n", object); - return TRUE; + return TRUE; } /*********************************************************************** * CoSuspendClassObjects (combase.@) */ -HRESULT WINAPI CoSuspendClassObjects(void) -{ - FIXME("\n"); +HRESULT WINAPI CoSuspendClassObjects(void) { + FIXME("\n"); - return S_OK; + return S_OK; } /*********************************************************************** * CoResumeClassObjects (combase.@) */ -HRESULT WINAPI CoResumeClassObjects(void) -{ - FIXME("stub\n"); +HRESULT WINAPI CoResumeClassObjects(void) { + FIXME("stub\n"); - return S_OK; + return S_OK; } /*********************************************************************** * CoRegisterSurrogate (combase.@) */ -HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate) -{ - FIXME("%p stub\n", surrogate); +HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate) { + FIXME("%p stub\n", surrogate); - return E_NOTIMPL; + return E_NOTIMPL; } /*********************************************************************** * CoRegisterSurrogateEx (combase.@) */ -HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved) -{ - FIXME("%s, %p stub\n", debugstr_guid(guid), reserved); +HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved) { + FIXME("%s, %p stub\n", debugstr_guid(guid), reserved); - return E_NOTIMPL; + return E_NOTIMPL; } /*********************************************************************** * DllMain (combase.@) */ -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved) -{ - TRACE("%p, %#lx, %p\n", hinstDLL, reason, reserved); +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved) { + TRACE("%p, %#lx, %p\n", hinstDLL, reason, reserved); - switch (reason) - { - case DLL_PROCESS_ATTACH: - hProxyDll = hinstDLL; - break; - case DLL_PROCESS_DETACH: - com_revoke_local_servers(); - if (reserved) break; - apartment_global_cleanup(); - DeleteCriticalSection(®istered_classes_cs); - rpc_unregister_channel_hooks(); - break; - case DLL_THREAD_DETACH: - com_cleanup_tlsdata(); - break; - } + switch (reason) { + case DLL_PROCESS_ATTACH: + hProxyDll = hinstDLL; + break; + case DLL_PROCESS_DETACH: + com_revoke_local_servers(); + if (reserved) + break; + apartment_global_cleanup(); + DeleteCriticalSection(®istered_classes_cs); + rpc_unregister_channel_hooks(); + break; + case DLL_THREAD_DETACH: + com_cleanup_tlsdata(); + break; + } - return TRUE; + return TRUE; } -HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj) -{ - TRACE("%s, %s, %p.\n", debugstr_guid(rclsid), debugstr_guid(riid), obj); +HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj) { + TRACE("%s, %s, %p.\n", debugstr_guid(rclsid), debugstr_guid(riid), obj); - *obj = NULL; + *obj = NULL; - if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions)) - return IClassFactory_QueryInterface(&global_options_factory, riid, obj); + if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions)) + return IClassFactory_QueryInterface(&global_options_factory, riid, obj); - return CLASS_E_CLASSNOTAVAILABLE; + return CLASS_E_CLASSNOTAVAILABLE; } From 064383a758ad4412d354a067126305930fa183aa Mon Sep 17 00:00:00 2001 From: WINDROID-EMU <45230455+WINDROID-EMU@users.noreply.github.com> Date: Wed, 18 Feb 2026 22:38:56 -0300 Subject: [PATCH 2/5] Wine Update error handling for PROT_EXEC in virtual.c --- dlls/ntdll/unix/virtual.c | 9999 +++++++++++++++++++------------------ 1 file changed, 5013 insertions(+), 4986 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index ab90c0f1000a..2a0bd62aa17c 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -27,126 +27,126 @@ #include #include #include +#include #include #include -#include #include -#include -#include +#include +#include #include #include -#include +#include #ifdef HAVE_SYS_SYSINFO_H -# include +#include #endif #ifdef HAVE_SYS_SYSCTL_H -# include +#include #endif #ifdef HAVE_SYS_PARAM_H -# include +#include #endif #ifdef HAVE_SYS_QUEUE_H -# include +#include #endif #ifdef HAVE_SYS_USER_H -# include +#include #endif #ifdef HAVE_LIBPROCSTAT_H -# include +#include #endif -#include #include +#include #ifdef HAVE_VALGRIND_VALGRIND_H -# include +#include #endif #if defined(__APPLE__) -# include -# include +#include +#include #endif #include "ntstatus.h" +#include #define WIN32_NO_STATUS #include "windef.h" #include "winnt.h" #include "winternl.h" +#define FIELD_OFFSET(type, field) ((LONG)offsetof(type, field)) +#define WINAPI #include "ddk/wdm.h" -#include "wine/list.h" -#include "wine/rbtree.h" #include "unix_private.h" #include "wine/debug.h" +#include "wine/list.h" +#include "wine/rbtree.h" WINE_DEFAULT_DEBUG_CHANNEL(virtual); WINE_DECLARE_DEBUG_CHANNEL(module); WINE_DECLARE_DEBUG_CHANNEL(virtual_ranges); -struct preload_info -{ - void *addr; - size_t size; +struct preload_info { + void *addr; + size_t size; }; -struct reserved_area -{ - struct list entry; - void *base; - size_t size; +struct reserved_area { + struct list entry; + void *base; + size_t size; }; static struct list reserved_areas = LIST_INIT(reserved_areas); -struct builtin_module -{ - struct list entry; - unsigned int refcount; - void *handle; - void *module; - char *unix_path; - void *unix_handle; +struct builtin_module { + struct list entry; + unsigned int refcount; + void *handle; + void *module; + char *unix_path; + void *unix_handle; }; -static struct list builtin_modules = LIST_INIT( builtin_modules ); +static struct list builtin_modules = LIST_INIT(builtin_modules); -struct file_view -{ - struct wine_rb_entry entry; /* entry in global view tree */ - void *base; /* base address */ - size_t size; /* size in bytes */ - unsigned int protect; /* protection for all pages at allocation time and SEC_* flags */ +struct file_view { + struct wine_rb_entry entry; /* entry in global view tree */ + void *base; /* base address */ + size_t size; /* size in bytes */ + unsigned int + protect; /* protection for all pages at allocation time and SEC_* flags */ }; /* per-page protection flags */ -#define VPROT_READ 0x01 -#define VPROT_WRITE 0x02 -#define VPROT_EXEC 0x04 -#define VPROT_WRITECOPY 0x08 -#define VPROT_GUARD 0x10 -#define VPROT_COMMITTED 0x20 +#define VPROT_READ 0x01 +#define VPROT_WRITE 0x02 +#define VPROT_EXEC 0x04 +#define VPROT_WRITECOPY 0x08 +#define VPROT_GUARD 0x10 +#define VPROT_COMMITTED 0x20 #define VPROT_WRITEWATCH 0x40 /* per-mapping protection flags */ -#define VPROT_ARM64EC 0x0100 /* view may contain ARM64EC code */ -#define VPROT_SYSTEM 0x0200 /* system view (underlying mmap not under our control) */ -#define VPROT_PLACEHOLDER 0x0400 +#define VPROT_ARM64EC 0x0100 /* view may contain ARM64EC code */ +#define VPROT_SYSTEM \ + 0x0200 /* system view (underlying mmap not under our control) */ +#define VPROT_PLACEHOLDER 0x0400 #define VPROT_FREE_PLACEHOLDER 0x0800 /* Conversion from VPROT_* to Win32 flags */ -static const BYTE VIRTUAL_Win32Flags[16] = -{ - PAGE_NOACCESS, /* 0 */ - PAGE_READONLY, /* READ */ - PAGE_READWRITE, /* WRITE */ - PAGE_READWRITE, /* READ | WRITE */ - PAGE_EXECUTE, /* EXEC */ - PAGE_EXECUTE_READ, /* READ | EXEC */ - PAGE_EXECUTE_READWRITE, /* WRITE | EXEC */ - PAGE_EXECUTE_READWRITE, /* READ | WRITE | EXEC */ - PAGE_WRITECOPY, /* WRITECOPY */ - PAGE_WRITECOPY, /* READ | WRITECOPY */ - PAGE_WRITECOPY, /* WRITE | WRITECOPY */ - PAGE_WRITECOPY, /* READ | WRITE | WRITECOPY */ - PAGE_EXECUTE_WRITECOPY, /* EXEC | WRITECOPY */ - PAGE_EXECUTE_WRITECOPY, /* READ | EXEC | WRITECOPY */ - PAGE_EXECUTE_WRITECOPY, /* WRITE | EXEC | WRITECOPY */ - PAGE_EXECUTE_WRITECOPY /* READ | WRITE | EXEC | WRITECOPY */ +static const BYTE VIRTUAL_Win32Flags[16] = { + PAGE_NOACCESS, /* 0 */ + PAGE_READONLY, /* READ */ + PAGE_READWRITE, /* WRITE */ + PAGE_READWRITE, /* READ | WRITE */ + PAGE_EXECUTE, /* EXEC */ + PAGE_EXECUTE_READ, /* READ | EXEC */ + PAGE_EXECUTE_READWRITE, /* WRITE | EXEC */ + PAGE_EXECUTE_READWRITE, /* READ | WRITE | EXEC */ + PAGE_WRITECOPY, /* WRITECOPY */ + PAGE_WRITECOPY, /* READ | WRITECOPY */ + PAGE_WRITECOPY, /* WRITE | WRITECOPY */ + PAGE_WRITECOPY, /* READ | WRITE | WRITECOPY */ + PAGE_EXECUTE_WRITECOPY, /* EXEC | WRITECOPY */ + PAGE_EXECUTE_WRITECOPY, /* READ | EXEC | WRITECOPY */ + PAGE_EXECUTE_WRITECOPY, /* WRITE | EXEC | WRITECOPY */ + PAGE_EXECUTE_WRITECOPY /* READ | WRITE | EXEC | WRITECOPY */ }; static struct wine_rb_tree views_tree; @@ -163,16 +163,19 @@ static void *address_space_start = (void *)0x110000; /* keep DOS area clear */ static void *address_space_start = (void *)0x10000; #endif #ifdef _WIN64 -static void *address_space_limit = (void *)0x7fffffff0000; /* top of the total available address space */ -static void *user_space_limit = (void *)0x7fffffff0000; /* top of the user address space */ -static void *working_set_limit = (void *)0x7fffffff0000; /* top of the current working set */ +static void *address_space_limit = + (void *)0x7fffffff0000; /* top of the total available address space */ +static void *user_space_limit = + (void *)0x7fffffff0000; /* top of the user address space */ +static void *working_set_limit = + (void *)0x7fffffff0000; /* top of the current working set */ #else static void *address_space_limit = (void *)0xc0000000; -static void *user_space_limit = (void *)0x7fff0000; -static void *working_set_limit = (void *)0x7fff0000; +static void *user_space_limit = (void *)0x7fff0000; +static void *working_set_limit = (void *)0x7fff0000; #endif -static void *host_addr_space_limit; /* top of the host virtual address space */ +static void *host_addr_space_limit; /* top of the host virtual address space */ static struct file_view *arm64ec_view; @@ -183,24 +186,33 @@ struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000; static void *teb_block; static void **next_free_teb; static int teb_block_pos; -static struct list teb_list = LIST_INIT( teb_list ); - -#define ROUND_ADDR(addr,mask) ((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask))) -#define ROUND_SIZE(addr,size) (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask) - -#define VIRTUAL_DEBUG_DUMP_VIEW(view) do { if (TRACE_ON(virtual)) dump_view(view); } while (0) -#define VIRTUAL_DEBUG_DUMP_RANGES() do { if (TRACE_ON(virtual_ranges)) dump_free_ranges(); } while (0) +static struct list teb_list = LIST_INIT(teb_list); + +#define ROUND_ADDR(addr, mask) ((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask))) +#define ROUND_SIZE(addr, size) \ + (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask) + +#define VIRTUAL_DEBUG_DUMP_VIEW(view) \ + do { \ + if (TRACE_ON(virtual)) \ + dump_view(view); \ + } while (0) +#define VIRTUAL_DEBUG_DUMP_RANGES() \ + do { \ + if (TRACE_ON(virtual_ranges)) \ + dump_free_ranges(); \ + } while (0) #ifndef MAP_NORESERVE #define MAP_NORESERVE 0 #endif -#ifdef _WIN64 /* on 64-bit the page protection bytes use a 2-level table */ +#ifdef _WIN64 /* on 64-bit the page protection bytes use a 2-level table */ static const size_t pages_vprot_shift = 20; static const size_t pages_vprot_mask = (1 << 20) - 1; static size_t pages_vprot_size; static BYTE **pages_vprot; -#else /* on 32-bit we use a simple array with one byte per page */ +#else /* on 32-bit we use a simple array with one byte per page */ static BYTE *pages_vprot; #endif @@ -208,516 +220,491 @@ static struct file_view *view_block_start, *view_block_end, *next_free_view; static const size_t view_block_size = 0x100000; static void *preload_reserve_start; static void *preload_reserve_end; -static BOOL force_exec_prot; /* whether to force PROT_EXEC on all PROT_READ mmaps */ -static BOOL enable_write_exceptions; /* raise exception on writes to executable memory */ - -struct range_entry -{ - void *base; - void *end; +static BOOL + force_exec_prot; /* whether to force PROT_EXEC on all PROT_READ mmaps */ +static BOOL enable_write_exceptions; /* raise exception on writes to executable + memory */ + +struct range_entry { + void *base; + void *end; }; static struct range_entry *free_ranges; static struct range_entry *free_ranges_end; - -static inline BOOL is_beyond_limit( const void *addr, size_t size, const void *limit ) -{ - return (addr >= limit || (const char *)addr + size > (const char *)limit); +static inline BOOL is_beyond_limit(const void *addr, size_t size, + const void *limit) { + return (addr >= limit || (const char *)addr + size > (const char *)limit); } -static inline BOOL is_vprot_exec_write( BYTE vprot ) -{ - return (vprot & VPROT_EXEC) && (vprot & (VPROT_WRITE | VPROT_WRITECOPY)); +static inline BOOL is_vprot_exec_write(BYTE vprot) { + return (vprot & VPROT_EXEC) && (vprot & (VPROT_WRITE | VPROT_WRITECOPY)); } /* mmap() anonymous memory at a fixed address */ -void *anon_mmap_fixed( void *start, size_t size, int prot, int flags ) -{ - return mmap( start, size, prot, MAP_PRIVATE | MAP_ANON | MAP_FIXED | flags, -1, 0 ); +void *anon_mmap_fixed(void *start, size_t size, int prot, int flags) { + return mmap(start, size, prot, MAP_PRIVATE | MAP_ANON | MAP_FIXED | flags, -1, + 0); } /* allocate anonymous mmap() memory at any address */ -void *anon_mmap_alloc( size_t size, int prot ) -{ - return mmap( NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0 ); +void *anon_mmap_alloc(size_t size, int prot) { + return mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0); } +static void mmap_add_reserved_area(void *addr, SIZE_T size) { + struct reserved_area *area; + struct list *ptr, *next; + void *end, *area_end; -static void mmap_add_reserved_area( void *addr, SIZE_T size ) -{ - struct reserved_area *area; - struct list *ptr, *next; - void *end, *area_end; - - if (!((intptr_t)addr + size)) size--; /* avoid wrap-around */ - end = (char *)addr + size; + if (!((intptr_t)addr + size)) + size--; /* avoid wrap-around */ + end = (char *)addr + size; - LIST_FOR_EACH( ptr, &reserved_areas ) - { - area = LIST_ENTRY( ptr, struct reserved_area, entry ); - area_end = (char *)area->base + area->size; - - if (area->base > end) break; - if (area_end < addr) continue; - if (area->base > addr) - { - area->size += (char *)area->base - (char *)addr; - area->base = addr; - } - if (area_end >= end) return; - - /* try to merge with the following ones */ - while ((next = list_next( &reserved_areas, ptr ))) - { - struct reserved_area *area_next = LIST_ENTRY( next, struct reserved_area, entry ); - void *next_end = (char *)area_next->base + area_next->size; - - if (area_next->base > end) break; - list_remove( next ); - free( area_next ); - if (next_end >= end) - { - end = next_end; - break; - } - } - area->size = (char *)end - (char *)area->base; - return; - } + LIST_FOR_EACH(ptr, &reserved_areas) { + area = LIST_ENTRY(ptr, struct reserved_area, entry); + area_end = (char *)area->base + area->size; - if ((area = malloc( sizeof(*area) ))) - { - area->base = addr; - area->size = size; - list_add_before( ptr, &area->entry ); + if (area->base > end) + break; + if (area_end < addr) + continue; + if (area->base > addr) { + area->size += (char *)area->base - (char *)addr; + area->base = addr; } -} - -static void mmap_remove_reserved_area( void *addr, SIZE_T size ) -{ - struct reserved_area *area; - struct list *ptr; + if (area_end >= end) + return; - if (!((intptr_t)addr + size)) size--; /* avoid wrap-around */ + /* try to merge with the following ones */ + while ((next = list_next(&reserved_areas, ptr))) { + struct reserved_area *area_next = + LIST_ENTRY(next, struct reserved_area, entry); + void *next_end = (char *)area_next->base + area_next->size; - ptr = list_head( &reserved_areas ); - /* find the first area covering address */ - while (ptr) - { - area = LIST_ENTRY( ptr, struct reserved_area, entry ); - if ((char *)area->base >= (char *)addr + size) break; /* outside the range */ - if ((char *)area->base + area->size > (char *)addr) /* overlaps range */ - { - if (area->base >= addr) - { - if ((char *)area->base + area->size > (char *)addr + size) - { - /* range overlaps beginning of area only -> shrink area */ - area->size -= (char *)addr + size - (char *)area->base; - area->base = (char *)addr + size; - break; - } - else - { - /* range contains the whole area -> remove area completely */ - ptr = list_next( &reserved_areas, ptr ); - list_remove( &area->entry ); - free( area ); - continue; - } - } - else - { - if ((char *)area->base + area->size > (char *)addr + size) - { - /* range is in the middle of area -> split area in two */ - struct reserved_area *new_area = malloc( sizeof(*new_area) ); - if (new_area) - { - new_area->base = (char *)addr + size; - new_area->size = (char *)area->base + area->size - (char *)new_area->base; - list_add_after( ptr, &new_area->entry ); - } - area->size = (char *)addr - (char *)area->base; - break; - } - else - { - /* range overlaps end of area only -> shrink area */ - area->size = (char *)addr - (char *)area->base; - } - } + if (area_next->base > end) + break; + list_remove(next); + free(area_next); + if (next_end >= end) { + end = next_end; + break; + } + } + area->size = (char *)end - (char *)area->base; + return; + } + + if ((area = malloc(sizeof(*area)))) { + area->base = addr; + area->size = size; + list_add_before(ptr, &area->entry); + } +} + +static void mmap_remove_reserved_area(void *addr, SIZE_T size) { + struct reserved_area *area; + struct list *ptr; + + if (!((intptr_t)addr + size)) + size--; /* avoid wrap-around */ + + ptr = list_head(&reserved_areas); + /* find the first area covering address */ + while (ptr) { + area = LIST_ENTRY(ptr, struct reserved_area, entry); + if ((char *)area->base >= (char *)addr + size) + break; /* outside the range */ + if ((char *)area->base + area->size > (char *)addr) /* overlaps range */ + { + if (area->base >= addr) { + if ((char *)area->base + area->size > (char *)addr + size) { + /* range overlaps beginning of area only -> shrink area */ + area->size -= (char *)addr + size - (char *)area->base; + area->base = (char *)addr + size; + break; + } else { + /* range contains the whole area -> remove area completely */ + ptr = list_next(&reserved_areas, ptr); + list_remove(&area->entry); + free(area); + continue; } - ptr = list_next( &reserved_areas, ptr ); + } else { + if ((char *)area->base + area->size > (char *)addr + size) { + /* range is in the middle of area -> split area in two */ + struct reserved_area *new_area = malloc(sizeof(*new_area)); + if (new_area) { + new_area->base = (char *)addr + size; + new_area->size = + (char *)area->base + area->size - (char *)new_area->base; + list_add_after(ptr, &new_area->entry); + } + area->size = (char *)addr - (char *)area->base; + break; + } else { + /* range overlaps end of area only -> shrink area */ + area->size = (char *)addr - (char *)area->base; + } + } } + ptr = list_next(&reserved_areas, ptr); + } } -static int mmap_is_in_reserved_area( void *addr, SIZE_T size ) -{ - struct reserved_area *area; +static int mmap_is_in_reserved_area(void *addr, SIZE_T size) { + struct reserved_area *area; - LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) - { - if (area->base > addr) break; - if ((char *)area->base + area->size <= (char *)addr) continue; - /* area must contain block completely */ - if ((char *)area->base + area->size < (char *)addr + size) return -1; - return 1; - } - return 0; + LIST_FOR_EACH_ENTRY(area, &reserved_areas, struct reserved_area, entry) { + if (area->base > addr) + break; + if ((char *)area->base + area->size <= (char *)addr) + continue; + /* area must contain block completely */ + if ((char *)area->base + area->size < (char *)addr + size) + return -1; + return 1; + } + return 0; } - /*********************************************************************** * unmap_area_above_user_limit * - * Unmap memory that's above the user space limit, by replacing it with an empty mapping, - * and return the remaining size below the limit. virtual_mutex must be held by caller. + * Unmap memory that's above the user space limit, by replacing it with an empty + * mapping, and return the remaining size below the limit. virtual_mutex must be + * held by caller. */ -static size_t unmap_area_above_user_limit( void *addr, size_t size ) -{ - size_t ret = 0; +static size_t unmap_area_above_user_limit(void *addr, size_t size) { + size_t ret = 0; - if (addr < user_space_limit) - { - ret = (char *)user_space_limit - (char *)addr; - if (ret >= size) return size; /* nothing is above limit */ - size -= ret; - addr = user_space_limit; - } - anon_mmap_fixed( addr, size, PROT_NONE, MAP_NORESERVE ); - mmap_add_reserved_area( addr, size ); - return ret; + if (addr < user_space_limit) { + ret = (char *)user_space_limit - (char *)addr; + if (ret >= size) + return size; /* nothing is above limit */ + size -= ret; + addr = user_space_limit; + } + anon_mmap_fixed(addr, size, PROT_NONE, MAP_NORESERVE); + mmap_add_reserved_area(addr, size); + return ret; } - -static void *anon_mmap_tryfixed( void *start, size_t size, int prot, int flags ) -{ - void *ptr; +static void *anon_mmap_tryfixed(void *start, size_t size, int prot, int flags) { + void *ptr; #ifdef MAP_FIXED_NOREPLACE - ptr = mmap( start, size, prot, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANON | flags, -1, 0 ); + ptr = mmap(start, size, prot, + MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANON | flags, -1, 0); #elif defined(MAP_TRYFIXED) - ptr = mmap( start, size, prot, MAP_TRYFIXED | MAP_PRIVATE | MAP_ANON | flags, -1, 0 ); + ptr = mmap(start, size, prot, MAP_TRYFIXED | MAP_PRIVATE | MAP_ANON | flags, + -1, 0); #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - ptr = mmap( start, size, prot, MAP_FIXED | MAP_EXCL | MAP_PRIVATE | MAP_ANON | flags, -1, 0 ); - if (ptr == MAP_FAILED && errno == EINVAL) errno = EEXIST; + ptr = mmap(start, size, prot, + MAP_FIXED | MAP_EXCL | MAP_PRIVATE | MAP_ANON | flags, -1, 0); + if (ptr == MAP_FAILED && errno == EINVAL) + errno = EEXIST; #elif defined(__APPLE__) - mach_vm_address_t result = (mach_vm_address_t)start; - kern_return_t ret = mach_vm_map( mach_task_self(), &result, size, 0, VM_FLAGS_FIXED, - MEMORY_OBJECT_NULL, 0, 0, prot, VM_PROT_ALL, VM_INHERIT_COPY ); - - if (!ret) - { - if ((ptr = anon_mmap_fixed( start, size, prot, flags )) == MAP_FAILED) - mach_vm_deallocate( mach_task_self(), result, size ); - } - else - { - errno = (ret == KERN_NO_SPACE ? EEXIST : ENOMEM); - ptr = MAP_FAILED; - } + mach_vm_address_t result = (mach_vm_address_t)start; + kern_return_t ret = + mach_vm_map(mach_task_self(), &result, size, 0, VM_FLAGS_FIXED, + MEMORY_OBJECT_NULL, 0, 0, prot, VM_PROT_ALL, VM_INHERIT_COPY); + + if (!ret) { + if ((ptr = anon_mmap_fixed(start, size, prot, flags)) == MAP_FAILED) + mach_vm_deallocate(mach_task_self(), result, size); + } else { + errno = (ret == KERN_NO_SPACE ? EEXIST : ENOMEM); + ptr = MAP_FAILED; + } #else - ptr = mmap( start, size, prot, MAP_PRIVATE | MAP_ANON | flags, -1, 0 ); + ptr = mmap(start, size, prot, MAP_PRIVATE | MAP_ANON | flags, -1, 0); #endif - if (ptr != MAP_FAILED && ptr != start) - { - size = unmap_area_above_user_limit( ptr, size ); - if (size) munmap( ptr, size ); - ptr = MAP_FAILED; - errno = EEXIST; - } - return ptr; + if (ptr != MAP_FAILED && ptr != start) { + size = unmap_area_above_user_limit(ptr, size); + if (size) + munmap(ptr, size); + ptr = MAP_FAILED; + errno = EEXIST; + } + return ptr; } -static void reserve_area( void *addr, void *end ) -{ +static void reserve_area(void *addr, void *end) { #ifdef __APPLE__ #ifdef __i386__ - static const mach_vm_address_t max_address = VM_MAX_ADDRESS; + static const mach_vm_address_t max_address = VM_MAX_ADDRESS; #else - static const mach_vm_address_t max_address = MACH_VM_MAX_ADDRESS; + static const mach_vm_address_t max_address = MACH_VM_MAX_ADDRESS; #endif - mach_vm_address_t address = (mach_vm_address_t)addr; - mach_vm_address_t end_address = (mach_vm_address_t)end; - - if (!end_address || max_address < end_address) - end_address = max_address; - - while (address < end_address) - { - mach_vm_address_t hole_address = address; - kern_return_t ret; - mach_vm_size_t size; - vm_region_basic_info_data_64_t info; - mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; - mach_port_t dummy_object_name = MACH_PORT_NULL; - - /* find the mapped region at or above the current address. */ - ret = mach_vm_region(mach_task_self(), &address, &size, VM_REGION_BASIC_INFO_64, - (vm_region_info_t)&info, &count, &dummy_object_name); - if (ret != KERN_SUCCESS) - { - address = max_address; - size = 0; - } - - if (end_address < address) - address = end_address; - if (hole_address < address) - { - /* found a hole, attempt to reserve it. */ - size_t hole_size = address - hole_address; - mach_vm_address_t alloc_address = hole_address; - - ret = mach_vm_map( mach_task_self(), &alloc_address, hole_size, 0, VM_FLAGS_FIXED, - MEMORY_OBJECT_NULL, 0, 0, PROT_NONE, VM_PROT_ALL, VM_INHERIT_COPY ); - if (!ret) mmap_add_reserved_area( (void*)hole_address, hole_size ); - else if (ret == KERN_NO_SPACE) - { - /* something filled (part of) the hole before we could. - go back and look again. */ - address = hole_address; - continue; - } - } - address += size; - } + mach_vm_address_t address = (mach_vm_address_t)addr; + mach_vm_address_t end_address = (mach_vm_address_t)end; + + if (!end_address || max_address < end_address) + end_address = max_address; + + while (address < end_address) { + mach_vm_address_t hole_address = address; + kern_return_t ret; + mach_vm_size_t size; + vm_region_basic_info_data_64_t info; + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; + mach_port_t dummy_object_name = MACH_PORT_NULL; + + /* find the mapped region at or above the current address. */ + ret = mach_vm_region(mach_task_self(), &address, &size, + VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, + &count, &dummy_object_name); + if (ret != KERN_SUCCESS) { + address = max_address; + size = 0; + } + + if (end_address < address) + address = end_address; + if (hole_address < address) { + /* found a hole, attempt to reserve it. */ + size_t hole_size = address - hole_address; + mach_vm_address_t alloc_address = hole_address; + + ret = mach_vm_map(mach_task_self(), &alloc_address, hole_size, 0, + VM_FLAGS_FIXED, MEMORY_OBJECT_NULL, 0, 0, PROT_NONE, + VM_PROT_ALL, VM_INHERIT_COPY); + if (!ret) + mmap_add_reserved_area((void *)hole_address, hole_size); + else if (ret == KERN_NO_SPACE) { + /* something filled (part of) the hole before we could. + go back and look again. */ + address = hole_address; + continue; + } + } + address += size; + } #else - size_t size = (char *)end - (char *)addr; - - if (!size) return; - - if (anon_mmap_tryfixed( addr, size, PROT_NONE, MAP_NORESERVE ) != MAP_FAILED) - { - mmap_add_reserved_area( addr, size ); - return; - } - size = (size / 2) & ~granularity_mask; - if (size) - { - reserve_area( addr, (char *)addr + size ); - reserve_area( (char *)addr + size, end ); - } + size_t size = (char *)end - (char *)addr; + + if (!size) + return; + + if (anon_mmap_tryfixed(addr, size, PROT_NONE, MAP_NORESERVE) != MAP_FAILED) { + mmap_add_reserved_area(addr, size); + return; + } + size = (size / 2) & ~granularity_mask; + if (size) { + reserve_area(addr, (char *)addr + size); + reserve_area((char *)addr + size, end); + } #endif /* __APPLE__ */ } - -static void mmap_init( const struct preload_info *preload_info ) -{ +static void mmap_init(const struct preload_info *preload_info) { #ifndef _WIN64 #ifndef __APPLE__ - char stack; - char * const stack_ptr = &stack; + char stack; + char *const stack_ptr = &stack; #endif - char *user_space_limit = (char *)0x7ffe0000; - int i; - - if (preload_info) - { - /* check for a reserved area starting at the user space limit */ - /* to avoid wasting time trying to allocate it again */ - for (i = 0; preload_info[i].size; i++) - { - if ((char *)preload_info[i].addr > user_space_limit) break; - if ((char *)preload_info[i].addr + preload_info[i].size > user_space_limit) - { - user_space_limit = (char *)preload_info[i].addr + preload_info[i].size; - break; - } - } + char *user_space_limit = (char *)0x7ffe0000; + int i; + + if (preload_info) { + /* check for a reserved area starting at the user space limit */ + /* to avoid wasting time trying to allocate it again */ + for (i = 0; preload_info[i].size; i++) { + if ((char *)preload_info[i].addr > user_space_limit) + break; + if ((char *)preload_info[i].addr + preload_info[i].size > + user_space_limit) { + user_space_limit = (char *)preload_info[i].addr + preload_info[i].size; + break; + } } - else reserve_area( (void *)0x00010000, (void *)0x40000000 ); - + } else + reserve_area((void *)0x00010000, (void *)0x40000000); #ifndef __APPLE__ - if (stack_ptr >= user_space_limit) - { - char *end = 0; - char *base = stack_ptr - ((unsigned int)stack_ptr & granularity_mask) - (granularity_mask + 1); - if (base > user_space_limit) reserve_area( user_space_limit, base ); - base = stack_ptr - ((unsigned int)stack_ptr & granularity_mask) + (granularity_mask + 1); -#if defined(linux) || defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__) - /* Heuristic: assume the stack is near the end of the address */ - /* space, this avoids a lot of futile allocation attempts */ - end = (char *)(((unsigned long)base + 0x0fffffff) & 0xf0000000); + if (stack_ptr >= user_space_limit) { + char *end = 0; + char *base = stack_ptr - ((unsigned int)stack_ptr & granularity_mask) - + (granularity_mask + 1); + if (base > user_space_limit) + reserve_area(user_space_limit, base); + base = stack_ptr - ((unsigned int)stack_ptr & granularity_mask) + + (granularity_mask + 1); +#if defined(linux) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ + defined(__DragonFly__) + /* Heuristic: assume the stack is near the end of the address */ + /* space, this avoids a lot of futile allocation attempts */ + end = (char *)(((unsigned long)base + 0x0fffffff) & 0xf0000000); #endif - reserve_area( base, end ); - } - else + reserve_area(base, end); + } else #endif - reserve_area( user_space_limit, 0 ); + reserve_area(user_space_limit, 0); #else - if (preload_info) return; - /* if we don't have a preloader, try to reserve the space now */ - reserve_area( (void *)0x000000010000, (void *)0x000068000000 ); - reserve_area( (void *)0x00007f000000, (void *)0x00007fff0000 ); - reserve_area( (void *)0x7ffffe000000, (void *)0x7fffffff0000 ); + if (preload_info) + return; + /* if we don't have a preloader, try to reserve the space now */ + reserve_area((void *)0x000000010000, (void *)0x000068000000); + reserve_area((void *)0x00007f000000, (void *)0x00007fff0000); + reserve_area((void *)0x7ffffe000000, (void *)0x7fffffff0000); #endif } - /*********************************************************************** * get_wow_user_space_limit */ -static ULONG_PTR get_wow_user_space_limit(void) -{ +static ULONG_PTR get_wow_user_space_limit(void) { #ifdef _WIN64 - return user_space_wow_limit & ~granularity_mask; + return user_space_wow_limit & ~granularity_mask; #endif - return (ULONG_PTR)user_space_limit; + return (ULONG_PTR)user_space_limit; } - /*********************************************************************** * add_builtin_module */ -static void add_builtin_module( void *module, void *handle ) -{ - struct builtin_module *builtin; +static void add_builtin_module(void *module, void *handle) { + struct builtin_module *builtin; - if (!(builtin = malloc( sizeof(*builtin) ))) return; - builtin->handle = handle; - builtin->module = module; - builtin->refcount = 1; - builtin->unix_path = NULL; - builtin->unix_handle = NULL; - list_add_tail( &builtin_modules, &builtin->entry ); + if (!(builtin = malloc(sizeof(*builtin)))) + return; + builtin->handle = handle; + builtin->module = module; + builtin->refcount = 1; + builtin->unix_path = NULL; + builtin->unix_handle = NULL; + list_add_tail(&builtin_modules, &builtin->entry); } - /*********************************************************************** * release_builtin_module */ -static void release_builtin_module( void *module ) -{ - struct builtin_module *builtin; +static void release_builtin_module(void *module) { + struct builtin_module *builtin; - LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry ) - { - if (builtin->module != module) continue; - if (!--builtin->refcount) - { - list_remove( &builtin->entry ); - if (builtin->handle) dlclose( builtin->handle ); - if (builtin->unix_handle) dlclose( builtin->unix_handle ); - free( builtin->unix_path ); - free( builtin ); - } - break; + LIST_FOR_EACH_ENTRY(builtin, &builtin_modules, struct builtin_module, entry) { + if (builtin->module != module) + continue; + if (!--builtin->refcount) { + list_remove(&builtin->entry); + if (builtin->handle) + dlclose(builtin->handle); + if (builtin->unix_handle) + dlclose(builtin->unix_handle); + free(builtin->unix_path); + free(builtin); } + break; + } } - /*********************************************************************** * get_builtin_so_handle */ -void *get_builtin_so_handle( void *module ) -{ - sigset_t sigset; - void *ret = NULL; - struct builtin_module *builtin; +void *get_builtin_so_handle(void *module) { + sigset_t sigset; + void *ret = NULL; + struct builtin_module *builtin; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry ) - { - if (builtin->module != module) continue; - ret = builtin->handle; - if (ret) builtin->refcount++; - break; - } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return ret; + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + LIST_FOR_EACH_ENTRY(builtin, &builtin_modules, struct builtin_module, entry) { + if (builtin->module != module) + continue; + ret = builtin->handle; + if (ret) + builtin->refcount++; + break; + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return ret; } - /*********************************************************************** * get_builtin_unix_funcs */ -static NTSTATUS get_builtin_unix_funcs( void *module, BOOL wow, const void **funcs ) -{ - const char *ptr_name = wow ? "__wine_unix_call_wow64_funcs" : "__wine_unix_call_funcs"; - sigset_t sigset; - NTSTATUS status = STATUS_DLL_NOT_FOUND; - struct builtin_module *builtin; +static NTSTATUS get_builtin_unix_funcs(void *module, BOOL wow, + const void **funcs) { + const char *ptr_name = + wow ? "__wine_unix_call_wow64_funcs" : "__wine_unix_call_funcs"; + sigset_t sigset; + NTSTATUS status = STATUS_DLL_NOT_FOUND; + struct builtin_module *builtin; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry ) - { - if (builtin->module != module) continue; - if (builtin->unix_path && !builtin->unix_handle) - { - builtin->unix_handle = dlopen( builtin->unix_path, RTLD_NOW ); - if (!builtin->unix_handle) - WARN_(module)( "failed to load %s: %s\n", debugstr_a(builtin->unix_path), dlerror() ); - } - if (builtin->unix_handle) - { - *funcs = dlsym( builtin->unix_handle, ptr_name ); - status = *funcs ? STATUS_SUCCESS : STATUS_ENTRYPOINT_NOT_FOUND; - } - break; + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + LIST_FOR_EACH_ENTRY(builtin, &builtin_modules, struct builtin_module, entry) { + if (builtin->module != module) + continue; + if (builtin->unix_path && !builtin->unix_handle) { + builtin->unix_handle = dlopen(builtin->unix_path, RTLD_NOW); + if (!builtin->unix_handle) + WARN_(module)("failed to load %s: %s\n", debugstr_a(builtin->unix_path), + dlerror()); } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return status; + if (builtin->unix_handle) { + *funcs = dlsym(builtin->unix_handle, ptr_name); + status = *funcs ? STATUS_SUCCESS : STATUS_ENTRYPOINT_NOT_FOUND; + } + break; + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return status; } - /*********************************************************************** * load_builtin_unixlib */ -NTSTATUS load_builtin_unixlib( void *module, const char *name ) -{ - sigset_t sigset; - NTSTATUS status = STATUS_SUCCESS; - struct builtin_module *builtin; - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry ) - { - if (builtin->module != module) continue; - if (!builtin->unix_path) builtin->unix_path = strdup( name ); - else status = STATUS_IMAGE_ALREADY_LOADED; - break; - } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return status; +NTSTATUS load_builtin_unixlib(void *module, const char *name) { + sigset_t sigset; + NTSTATUS status = STATUS_SUCCESS; + struct builtin_module *builtin; + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + LIST_FOR_EACH_ENTRY(builtin, &builtin_modules, struct builtin_module, entry) { + if (builtin->module != module) + continue; + if (!builtin->unix_path) + builtin->unix_path = strdup(name); + else + status = STATUS_IMAGE_ALREADY_LOADED; + break; + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return status; } - /*********************************************************************** * free_ranges_lower_bound * - * Returns the first range whose end is not less than addr, or end if there's none. - */ -static struct range_entry *free_ranges_lower_bound( void *addr ) -{ - struct range_entry *begin = free_ranges; - struct range_entry *end = free_ranges_end; - struct range_entry *mid; - - while (begin < end) - { - mid = begin + (end - begin) / 2; - if (mid->end < addr) - begin = mid + 1; - else - end = mid; - } + * Returns the first range whose end is not less than addr, or end if there's + * none. + */ +static struct range_entry *free_ranges_lower_bound(void *addr) { + struct range_entry *begin = free_ranges; + struct range_entry *end = free_ranges_end; + struct range_entry *mid; + + while (begin < end) { + mid = begin + (end - begin) / 2; + if (mid->end < addr) + begin = mid + 1; + else + end = mid; + } - return begin; + return begin; } -static void dump_free_ranges(void) -{ - struct range_entry *r; - for (r = free_ranges; r != free_ranges_end; ++r) - TRACE_(virtual_ranges)("%p - %p.\n", r->base, r->end); +static void dump_free_ranges(void) { + struct range_entry *r; + for (r = free_ranges; r != free_ranges_end; ++r) + TRACE_(virtual_ranges)("%p - %p.\n", r->base, r->end); } /*********************************************************************** @@ -725,72 +712,70 @@ static void dump_free_ranges(void) * * Updates the free_ranges after a new view has been created. */ -static void free_ranges_insert_view( struct file_view *view ) -{ - void *view_base = ROUND_ADDR( view->base, granularity_mask ); - void *view_end = ROUND_ADDR( (char *)view->base + view->size + granularity_mask, granularity_mask ); - struct range_entry *range = free_ranges_lower_bound( view_base ); - struct range_entry *next = range + 1; +static void free_ranges_insert_view(struct file_view *view) { + void *view_base = ROUND_ADDR(view->base, granularity_mask); + void *view_end = ROUND_ADDR( + (char *)view->base + view->size + granularity_mask, granularity_mask); + struct range_entry *range = free_ranges_lower_bound(view_base); + struct range_entry *next = range + 1; - /* free_ranges initial value is such that the view is either inside range or before another one. */ - assert( range != free_ranges_end ); - assert( range->end > view_base || next != free_ranges_end ); + /* free_ranges initial value is such that the view is either inside range or + * before another one. */ + assert(range != free_ranges_end); + assert(range->end > view_base || next != free_ranges_end); - /* Free ranges addresses are aligned at granularity_mask while the views may be not. */ + /* Free ranges addresses are aligned at granularity_mask while the views may + * be not. */ - if (range->base > view_base) - view_base = range->base; - if (range->end < view_end) - view_end = range->end; - if (range->end == view_base && next->base >= view_end) - view_end = view_base; + if (range->base > view_base) + view_base = range->base; + if (range->end < view_end) + view_end = range->end; + if (range->end == view_base && next->base >= view_end) + view_end = view_base; - TRACE_(virtual_ranges)( "%p - %p, aligned %p - %p.\n", - view->base, (char *)view->base + view->size, view_base, view_end ); + TRACE_(virtual_ranges)("%p - %p, aligned %p - %p.\n", view->base, + (char *)view->base + view->size, view_base, view_end); - if (view_end <= view_base) - { - VIRTUAL_DEBUG_DUMP_RANGES(); - return; - } - - /* this should never happen */ - if (range->base > view_base || range->end < view_end) - ERR( "range %p - %p is already partially mapped\n", view_base, view_end ); - assert( range->base <= view_base && range->end >= view_end ); - - /* need to split the range in two */ - if (range->base < view_base && range->end > view_end) - { - memmove( next + 1, next, (free_ranges_end - next) * sizeof(struct range_entry) ); - free_ranges_end += 1; - if ((char *)free_ranges_end - (char *)free_ranges > view_block_size) - ERR( "Free range sequence is full, trouble ahead!\n" ); - assert( (char *)free_ranges_end - (char *)free_ranges <= view_block_size ); - - next->base = view_end; - next->end = range->end; - range->end = view_base; - } + if (view_end <= view_base) { + VIRTUAL_DEBUG_DUMP_RANGES(); + return; + } + + /* this should never happen */ + if (range->base > view_base || range->end < view_end) + ERR("range %p - %p is already partially mapped\n", view_base, view_end); + assert(range->base <= view_base && range->end >= view_end); + + /* need to split the range in two */ + if (range->base < view_base && range->end > view_end) { + memmove(next + 1, next, + (free_ranges_end - next) * sizeof(struct range_entry)); + free_ranges_end += 1; + if ((char *)free_ranges_end - (char *)free_ranges > view_block_size) + ERR("Free range sequence is full, trouble ahead!\n"); + assert((char *)free_ranges_end - (char *)free_ranges <= view_block_size); + + next->base = view_end; + next->end = range->end; + range->end = view_base; + } else { + /* otherwise we just have to shrink it */ + if (range->base < view_base) + range->end = view_base; else - { - /* otherwise we just have to shrink it */ - if (range->base < view_base) - range->end = view_base; - else - range->base = view_end; + range->base = view_end; - if (range->base < range->end) - { - VIRTUAL_DEBUG_DUMP_RANGES(); - return; - } - /* and possibly remove it if it's now empty */ - memmove( range, next, (free_ranges_end - next) * sizeof(struct range_entry) ); - free_ranges_end -= 1; - assert( free_ranges_end - free_ranges > 0 ); + if (range->base < range->end) { + VIRTUAL_DEBUG_DUMP_RANGES(); + return; } - VIRTUAL_DEBUG_DUMP_RANGES(); + /* and possibly remove it if it's now empty */ + memmove(range, next, (free_ranges_end - next) * sizeof(struct range_entry)); + free_ranges_end -= 1; + assert(free_ranges_end - free_ranges > 0); + } + VIRTUAL_DEBUG_DUMP_RANGES(); } /*********************************************************************** @@ -798,82 +783,92 @@ static void free_ranges_insert_view( struct file_view *view ) * * Updates the free_ranges after a view has been destroyed. */ -static void free_ranges_remove_view( struct file_view *view ) -{ - void *view_base = ROUND_ADDR( view->base, granularity_mask ); - void *view_end = ROUND_ADDR( (char *)view->base + view->size + granularity_mask, granularity_mask ); - struct range_entry *range = free_ranges_lower_bound( view_base ); - struct range_entry *next = range + 1; - - /* Free ranges addresses are aligned at granularity_mask while the views may be not. */ - struct file_view *prev_view = RB_ENTRY_VALUE( rb_prev( &view->entry ), struct file_view, entry ); - struct file_view *next_view = RB_ENTRY_VALUE( rb_next( &view->entry ), struct file_view, entry ); - void *prev_view_base = prev_view ? ROUND_ADDR( prev_view->base, granularity_mask ) : NULL; - void *prev_view_end = prev_view ? ROUND_ADDR( (char *)prev_view->base + prev_view->size + granularity_mask, granularity_mask ) : NULL; - void *next_view_base = next_view ? ROUND_ADDR( next_view->base, granularity_mask ) : NULL; - void *next_view_end = next_view ? ROUND_ADDR( (char *)next_view->base + next_view->size + granularity_mask, granularity_mask ) : NULL; - - if (prev_view_end && prev_view_end > view_base && prev_view_base < view_end) - view_base = prev_view_end; - if (next_view_base && next_view_base < view_end && next_view_end > view_base) - view_end = next_view_base; - - TRACE_(virtual_ranges)( "%p - %p, aligned %p - %p.\n", - view->base, (char *)view->base + view->size, view_base, view_end ); - - if (view_end <= view_base) - { - VIRTUAL_DEBUG_DUMP_RANGES(); - return; - } - /* free_ranges initial value is such that the view is either inside range or before another one. */ - assert( range != free_ranges_end ); - assert( range->end > view_base || next != free_ranges_end ); - - /* this should never happen, but we can safely ignore it */ - if (range->base <= view_base && range->end >= view_end) - { - WARN( "range %p - %p is already unmapped\n", view_base, view_end ); - return; - } - - /* this should never happen */ - if (range->base < view_end && range->end > view_base) - ERR( "range %p - %p is already partially unmapped\n", view_base, view_end ); - assert( range->end <= view_base || range->base >= view_end ); - - /* merge with next if possible */ - if (range->end == view_base && next->base == view_end) - { - range->end = next->end; - memmove( next, next + 1, (free_ranges_end - next - 1) * sizeof(struct range_entry) ); - free_ranges_end -= 1; - assert( free_ranges_end - free_ranges > 0 ); - } - /* or try growing the range */ - else if (range->end == view_base) - range->end = view_end; - else if (range->base == view_end) - range->base = view_base; - /* otherwise create a new one */ - else - { - memmove( range + 1, range, (free_ranges_end - range) * sizeof(struct range_entry) ); - free_ranges_end += 1; - if ((char *)free_ranges_end - (char *)free_ranges > view_block_size) - ERR( "Free range sequence is full, trouble ahead!\n" ); - assert( (char *)free_ranges_end - (char *)free_ranges <= view_block_size ); - - range->base = view_base; - range->end = view_end; - } +static void free_ranges_remove_view(struct file_view *view) { + void *view_base = ROUND_ADDR(view->base, granularity_mask); + void *view_end = ROUND_ADDR( + (char *)view->base + view->size + granularity_mask, granularity_mask); + struct range_entry *range = free_ranges_lower_bound(view_base); + struct range_entry *next = range + 1; + + /* Free ranges addresses are aligned at granularity_mask while the views may + * be not. */ + struct file_view *prev_view = + RB_ENTRY_VALUE(rb_prev(&view->entry), struct file_view, entry); + struct file_view *next_view = + RB_ENTRY_VALUE(rb_next(&view->entry), struct file_view, entry); + void *prev_view_base = + prev_view ? ROUND_ADDR(prev_view->base, granularity_mask) : NULL; + void *prev_view_end = prev_view + ? ROUND_ADDR((char *)prev_view->base + + prev_view->size + granularity_mask, + granularity_mask) + : NULL; + void *next_view_base = + next_view ? ROUND_ADDR(next_view->base, granularity_mask) : NULL; + void *next_view_end = next_view + ? ROUND_ADDR((char *)next_view->base + + next_view->size + granularity_mask, + granularity_mask) + : NULL; + + if (prev_view_end && prev_view_end > view_base && prev_view_base < view_end) + view_base = prev_view_end; + if (next_view_base && next_view_base < view_end && next_view_end > view_base) + view_end = next_view_base; + + TRACE_(virtual_ranges)("%p - %p, aligned %p - %p.\n", view->base, + (char *)view->base + view->size, view_base, view_end); + + if (view_end <= view_base) { VIRTUAL_DEBUG_DUMP_RANGES(); -} - - -static inline int is_view_valloc( const struct file_view *view ) -{ - return !(view->protect & (SEC_FILE | SEC_RESERVE | SEC_COMMIT)); + return; + } + /* free_ranges initial value is such that the view is either inside range or + * before another one. */ + assert(range != free_ranges_end); + assert(range->end > view_base || next != free_ranges_end); + + /* this should never happen, but we can safely ignore it */ + if (range->base <= view_base && range->end >= view_end) { + WARN("range %p - %p is already unmapped\n", view_base, view_end); + return; + } + + /* this should never happen */ + if (range->base < view_end && range->end > view_base) + ERR("range %p - %p is already partially unmapped\n", view_base, view_end); + assert(range->end <= view_base || range->base >= view_end); + + /* merge with next if possible */ + if (range->end == view_base && next->base == view_end) { + range->end = next->end; + memmove(next, next + 1, + (free_ranges_end - next - 1) * sizeof(struct range_entry)); + free_ranges_end -= 1; + assert(free_ranges_end - free_ranges > 0); + } + /* or try growing the range */ + else if (range->end == view_base) + range->end = view_end; + else if (range->base == view_end) + range->base = view_base; + /* otherwise create a new one */ + else { + memmove(range + 1, range, + (free_ranges_end - range) * sizeof(struct range_entry)); + free_ranges_end += 1; + if ((char *)free_ranges_end - (char *)free_ranges > view_block_size) + ERR("Free range sequence is full, trouble ahead!\n"); + assert((char *)free_ranges_end - (char *)free_ranges <= view_block_size); + + range->base = view_base; + range->end = view_end; + } + VIRTUAL_DEBUG_DUMP_RANGES(); +} + +static inline int is_view_valloc(const struct file_view *view) { + return !(view->protect & (SEC_FILE | SEC_RESERVE | SEC_COMMIT)); } /*********************************************************************** @@ -881,20 +876,20 @@ static inline int is_view_valloc( const struct file_view *view ) * * Return the page protection byte. */ -static BYTE get_page_vprot( const void *addr ) -{ - size_t idx = (size_t)addr >> page_shift; +static BYTE get_page_vprot(const void *addr) { + size_t idx = (size_t)addr >> page_shift; #ifdef _WIN64 - if ((idx >> pages_vprot_shift) >= pages_vprot_size) return 0; - if (!pages_vprot[idx >> pages_vprot_shift]) return 0; - return pages_vprot[idx >> pages_vprot_shift][idx & pages_vprot_mask]; + if ((idx >> pages_vprot_shift) >= pages_vprot_size) + return 0; + if (!pages_vprot[idx >> pages_vprot_shift]) + return 0; + return pages_vprot[idx >> pages_vprot_shift][idx & pages_vprot_mask]; #else - return pages_vprot[idx]; + return pages_vprot[idx]; #endif } - /*********************************************************************** * get_vprot_range_size * @@ -903,50 +898,55 @@ static BYTE get_page_vprot( const void *addr ) * The function assumes that base and size are page aligned, * base + size does not wrap around and the range is within view so * vprot bytes are allocated for the range. */ -static SIZE_T get_vprot_range_size( char *base, SIZE_T size, BYTE mask, BYTE *vprot ) -{ - static const UINT_PTR word_from_byte = (UINT_PTR)0x101010101010101; - static const UINT_PTR index_align_mask = sizeof(UINT_PTR) - 1; - SIZE_T curr_idx, start_idx, end_idx, aligned_start_idx; - UINT_PTR vprot_word, mask_word; - const BYTE *vprot_ptr; +static SIZE_T get_vprot_range_size(char *base, SIZE_T size, BYTE mask, + BYTE *vprot) { + static const UINT_PTR word_from_byte = (UINT_PTR)0x101010101010101; + static const UINT_PTR index_align_mask = sizeof(UINT_PTR) - 1; + SIZE_T curr_idx, start_idx, end_idx, aligned_start_idx; + UINT_PTR vprot_word, mask_word; + const BYTE *vprot_ptr; - TRACE("base %p, size %p, mask %#x.\n", base, (void *)size, mask); + TRACE("base %p, size %p, mask %#x.\n", base, (void *)size, mask); - curr_idx = start_idx = (size_t)base >> page_shift; - end_idx = start_idx + (size >> page_shift); + curr_idx = start_idx = (size_t)base >> page_shift; + end_idx = start_idx + (size >> page_shift); - aligned_start_idx = (start_idx + index_align_mask) & ~index_align_mask; - if (aligned_start_idx > end_idx) aligned_start_idx = end_idx; + aligned_start_idx = (start_idx + index_align_mask) & ~index_align_mask; + if (aligned_start_idx > end_idx) + aligned_start_idx = end_idx; #ifdef _WIN64 - vprot_ptr = pages_vprot[curr_idx >> pages_vprot_shift] + (curr_idx & pages_vprot_mask); + vprot_ptr = pages_vprot[curr_idx >> pages_vprot_shift] + + (curr_idx & pages_vprot_mask); #else - vprot_ptr = pages_vprot + curr_idx; + vprot_ptr = pages_vprot + curr_idx; #endif - *vprot = *vprot_ptr; + *vprot = *vprot_ptr; - /* Page count page table is at least the multiples of sizeof(UINT_PTR) - * so we don't have to worry about crossing the boundary on unaligned idx values. */ + /* Page count page table is at least the multiples of sizeof(UINT_PTR) + * so we don't have to worry about crossing the boundary on unaligned idx + * values. */ - for (; curr_idx < aligned_start_idx; ++curr_idx, ++vprot_ptr) - if ((*vprot ^ *vprot_ptr) & mask) return (curr_idx - start_idx) << page_shift; + for (; curr_idx < aligned_start_idx; ++curr_idx, ++vprot_ptr) + if ((*vprot ^ *vprot_ptr) & mask) + return (curr_idx - start_idx) << page_shift; - vprot_word = word_from_byte * *vprot; - mask_word = word_from_byte * mask; - for (; curr_idx < end_idx; curr_idx += sizeof(UINT_PTR), vprot_ptr += sizeof(UINT_PTR)) - { + vprot_word = word_from_byte * *vprot; + mask_word = word_from_byte * mask; + for (; curr_idx < end_idx; + curr_idx += sizeof(UINT_PTR), vprot_ptr += sizeof(UINT_PTR)) { #ifdef _WIN64 - if (!(curr_idx & pages_vprot_mask)) vprot_ptr = pages_vprot[curr_idx >> pages_vprot_shift]; + if (!(curr_idx & pages_vprot_mask)) + vprot_ptr = pages_vprot[curr_idx >> pages_vprot_shift]; #endif - if ((vprot_word ^ *(UINT_PTR *)vprot_ptr) & mask_word) - { - for (; curr_idx < end_idx; ++curr_idx, ++vprot_ptr) - if ((*vprot ^ *vprot_ptr) & mask) break; - return (curr_idx - start_idx) << page_shift; - } + if ((vprot_word ^ *(UINT_PTR *)vprot_ptr) & mask_word) { + for (; curr_idx < end_idx; ++curr_idx, ++vprot_ptr) + if ((*vprot ^ *vprot_ptr) & mask) + break; + return (curr_idx - start_idx) << page_shift; } - return size; + } + return size; } /*********************************************************************** @@ -954,262 +954,254 @@ static SIZE_T get_vprot_range_size( char *base, SIZE_T size, BYTE mask, BYTE *vp * * Set a range of page protection bytes. */ -static void set_page_vprot( const void *addr, size_t size, BYTE vprot ) -{ - size_t idx = (size_t)addr >> page_shift; - size_t end = ((size_t)addr + size + page_mask) >> page_shift; +static void set_page_vprot(const void *addr, size_t size, BYTE vprot) { + size_t idx = (size_t)addr >> page_shift; + size_t end = ((size_t)addr + size + page_mask) >> page_shift; #ifdef _WIN64 - while (idx >> pages_vprot_shift != end >> pages_vprot_shift) - { - size_t dir_size = pages_vprot_mask + 1 - (idx & pages_vprot_mask); - memset( pages_vprot[idx >> pages_vprot_shift] + (idx & pages_vprot_mask), vprot, dir_size ); - idx += dir_size; - } - memset( pages_vprot[idx >> pages_vprot_shift] + (idx & pages_vprot_mask), vprot, end - idx ); + while (idx >> pages_vprot_shift != end >> pages_vprot_shift) { + size_t dir_size = pages_vprot_mask + 1 - (idx & pages_vprot_mask); + memset(pages_vprot[idx >> pages_vprot_shift] + (idx & pages_vprot_mask), + vprot, dir_size); + idx += dir_size; + } + memset(pages_vprot[idx >> pages_vprot_shift] + (idx & pages_vprot_mask), + vprot, end - idx); #else - memset( pages_vprot + idx, vprot, end - idx ); + memset(pages_vprot + idx, vprot, end - idx); #endif } - /*********************************************************************** * set_page_vprot_bits * * Set or clear bits in a range of page protection bytes. */ -static void set_page_vprot_bits( const void *addr, size_t size, BYTE set, BYTE clear ) -{ - size_t idx = (size_t)addr >> page_shift; - size_t end = ((size_t)addr + size + page_mask) >> page_shift; +static void set_page_vprot_bits(const void *addr, size_t size, BYTE set, + BYTE clear) { + size_t idx = (size_t)addr >> page_shift; + size_t end = ((size_t)addr + size + page_mask) >> page_shift; #ifdef _WIN64 - for ( ; idx < end; idx++) - { - BYTE *ptr = pages_vprot[idx >> pages_vprot_shift] + (idx & pages_vprot_mask); - *ptr = (*ptr & ~clear) | set; - } + for (; idx < end; idx++) { + BYTE *ptr = + pages_vprot[idx >> pages_vprot_shift] + (idx & pages_vprot_mask); + *ptr = (*ptr & ~clear) | set; + } #else - for ( ; idx < end; idx++) pages_vprot[idx] = (pages_vprot[idx] & ~clear) | set; + for (; idx < end; idx++) + pages_vprot[idx] = (pages_vprot[idx] & ~clear) | set; #endif } - /*********************************************************************** * set_page_vprot_exec_write_protect * * Write protect pages that are executable. */ -static BOOL set_page_vprot_exec_write_protect( const void *addr, size_t size ) -{ - BOOL ret = FALSE; +static BOOL set_page_vprot_exec_write_protect(const void *addr, size_t size) { + BOOL ret = FALSE; #ifdef _WIN64 /* only supported on 64-bit so assume 2-level table */ - size_t idx = (size_t)addr >> page_shift; - size_t end = ((size_t)addr + size + page_mask) >> page_shift; - - for ( ; idx < end; idx++) - { - BYTE *ptr = pages_vprot[idx >> pages_vprot_shift] + (idx & pages_vprot_mask); - if (!is_vprot_exec_write( *ptr )) continue; - *ptr |= VPROT_WRITEWATCH; - ret = TRUE; - } + size_t idx = (size_t)addr >> page_shift; + size_t end = ((size_t)addr + size + page_mask) >> page_shift; + + for (; idx < end; idx++) { + BYTE *ptr = + pages_vprot[idx >> pages_vprot_shift] + (idx & pages_vprot_mask); + if (!is_vprot_exec_write(*ptr)) + continue; + *ptr |= VPROT_WRITEWATCH; + ret = TRUE; + } #endif - return ret; + return ret; } - /*********************************************************************** * alloc_pages_vprot * * Allocate the page protection bytes for a given range. */ -static BOOL alloc_pages_vprot( const void *addr, size_t size ) -{ +static BOOL alloc_pages_vprot(const void *addr, size_t size) { #ifdef _WIN64 - size_t idx = (size_t)addr >> page_shift; - size_t end = ((size_t)addr + size + page_mask) >> page_shift; - size_t i; - void *ptr; - - assert( end <= pages_vprot_size << pages_vprot_shift ); - for (i = idx >> pages_vprot_shift; i < (end + pages_vprot_mask) >> pages_vprot_shift; i++) - { - if (pages_vprot[i]) continue; - if ((ptr = anon_mmap_alloc( pages_vprot_mask + 1, PROT_READ | PROT_WRITE )) == MAP_FAILED) - { - ERR( "anon mmap error %s for vprot table, size %08lx\n", strerror(errno), pages_vprot_mask + 1 ); - return FALSE; - } - pages_vprot[i] = ptr; - } + size_t idx = (size_t)addr >> page_shift; + size_t end = ((size_t)addr + size + page_mask) >> page_shift; + size_t i; + void *ptr; + + assert(end <= pages_vprot_size << pages_vprot_shift); + for (i = idx >> pages_vprot_shift; + i < (end + pages_vprot_mask) >> pages_vprot_shift; i++) { + if (pages_vprot[i]) + continue; + if ((ptr = anon_mmap_alloc(pages_vprot_mask + 1, PROT_READ | PROT_WRITE)) == + MAP_FAILED) { + ERR("anon mmap error %s for vprot table, size %08lx\n", strerror(errno), + pages_vprot_mask + 1); + return FALSE; + } + pages_vprot[i] = ptr; + } #endif - return TRUE; + return TRUE; } - -static inline UINT64 maskbits( size_t idx ) -{ - return ~(UINT64)0 << (idx & 63); -} +static inline UINT64 maskbits(size_t idx) { return ~(UINT64)0 << (idx & 63); } /*********************************************************************** * set_arm64ec_range */ -static void set_arm64ec_range( const void *addr, size_t size ) -{ - UINT64 *map = arm64ec_view->base; - size_t idx = (size_t)addr >> page_shift; - size_t end = ((size_t)addr + size + page_mask) >> page_shift; - size_t pos = idx / 64; - size_t end_pos = end / 64; +static void set_arm64ec_range(const void *addr, size_t size) { + UINT64 *map = arm64ec_view->base; + size_t idx = (size_t)addr >> page_shift; + size_t end = ((size_t)addr + size + page_mask) >> page_shift; + size_t pos = idx / 64; + size_t end_pos = end / 64; - if (end_pos > pos) - { - map[pos++] |= maskbits( idx ); - while (pos < end_pos) map[pos++] = ~(UINT64)0; - if (end & 63) map[pos] |= ~maskbits( end ); - } - else map[pos] |= maskbits( idx ) & ~maskbits( end ); + if (end_pos > pos) { + map[pos++] |= maskbits(idx); + while (pos < end_pos) + map[pos++] = ~(UINT64)0; + if (end & 63) + map[pos] |= ~maskbits(end); + } else + map[pos] |= maskbits(idx) & ~maskbits(end); } - /*********************************************************************** * clear_arm64ec_range */ -static void clear_arm64ec_range( const void *addr, size_t size ) -{ - UINT64 *map = arm64ec_view->base; - size_t idx = (size_t)addr >> page_shift; - size_t end = ((size_t)addr + size + page_mask) >> page_shift; - size_t pos = idx / 64; - size_t end_pos = end / 64; +static void clear_arm64ec_range(const void *addr, size_t size) { + UINT64 *map = arm64ec_view->base; + size_t idx = (size_t)addr >> page_shift; + size_t end = ((size_t)addr + size + page_mask) >> page_shift; + size_t pos = idx / 64; + size_t end_pos = end / 64; - if (end_pos > pos) - { - map[pos++] &= ~maskbits( idx ); - while (pos < end_pos) map[pos++] = 0; - if (end & 63) map[pos] &= maskbits( end ); - } - else map[pos] &= ~maskbits( idx ) | maskbits( end ); + if (end_pos > pos) { + map[pos++] &= ~maskbits(idx); + while (pos < end_pos) + map[pos++] = 0; + if (end & 63) + map[pos] &= maskbits(end); + } else + map[pos] &= ~maskbits(idx) | maskbits(end); } - /*********************************************************************** * compare_view * * View comparison function used for the rb tree. */ -static int compare_view( const void *addr, const struct wine_rb_entry *entry ) -{ - struct file_view *view = WINE_RB_ENTRY_VALUE( entry, struct file_view, entry ); +static int compare_view(const void *addr, const struct wine_rb_entry *entry) { + struct file_view *view = WINE_RB_ENTRY_VALUE(entry, struct file_view, entry); - if (addr < view->base) return -1; - if (addr > view->base) return 1; - return 0; + if (addr < view->base) + return -1; + if (addr > view->base) + return 1; + return 0; } - /*********************************************************************** * get_prot_str */ -static const char *get_prot_str( BYTE prot ) -{ - static char buffer[6]; - buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-'; - buffer[1] = (prot & VPROT_GUARD) ? 'g' : ((prot & VPROT_WRITEWATCH) ? 'H' : '-'); - buffer[2] = (prot & VPROT_READ) ? 'r' : '-'; - buffer[3] = (prot & VPROT_WRITECOPY) ? 'W' : ((prot & VPROT_WRITE) ? 'w' : '-'); - buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-'; - buffer[5] = 0; - return buffer; +static const char *get_prot_str(BYTE prot) { + static char buffer[6]; + buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-'; + buffer[1] = + (prot & VPROT_GUARD) ? 'g' : ((prot & VPROT_WRITEWATCH) ? 'H' : '-'); + buffer[2] = (prot & VPROT_READ) ? 'r' : '-'; + buffer[3] = + (prot & VPROT_WRITECOPY) ? 'W' : ((prot & VPROT_WRITE) ? 'w' : '-'); + buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-'; + buffer[5] = 0; + return buffer; } - /*********************************************************************** * get_unix_prot * * Convert page protections to protection for mmap/mprotect. */ -static int get_unix_prot( BYTE vprot ) -{ - int prot = 0; - if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD)) - { - if (vprot & VPROT_READ) prot |= PROT_READ; - if (vprot & VPROT_WRITE) prot |= PROT_WRITE | PROT_READ; - if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE | PROT_READ; - if (vprot & VPROT_EXEC) prot |= PROT_EXEC | PROT_READ; - if (vprot & VPROT_WRITEWATCH) prot &= ~PROT_WRITE; - } - if (!prot) prot = PROT_NONE; - return prot; +static int get_unix_prot(BYTE vprot) { + int prot = 0; + if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD)) { + if (vprot & VPROT_READ) + prot |= PROT_READ; + if (vprot & VPROT_WRITE) + prot |= PROT_WRITE | PROT_READ; + if (vprot & VPROT_WRITECOPY) + prot |= PROT_WRITE | PROT_READ; + if (vprot & VPROT_EXEC) + prot |= PROT_EXEC | PROT_READ; + if (vprot & VPROT_WRITEWATCH) + prot &= ~PROT_WRITE; + } + if (!prot) + prot = PROT_NONE; + return prot; } - /*********************************************************************** * dump_view */ -static void dump_view( struct file_view *view ) -{ - UINT i, count; - char *addr = view->base; - BYTE prot = get_page_vprot( addr ); - - TRACE( "View: %p - %p", addr, addr + view->size - 1 ); - if (view->protect & VPROT_SYSTEM) - TRACE( " (builtin image)\n" ); - else if (view->protect & VPROT_FREE_PLACEHOLDER) - TRACE( " (placeholder)\n" ); - else if (view->protect & SEC_IMAGE) - TRACE( " (image)\n" ); - else if (view->protect & SEC_FILE) - TRACE( " (file)\n" ); - else if (view->protect & (SEC_RESERVE | SEC_COMMIT)) - TRACE( " (anonymous)\n" ); - else - TRACE( " (valloc)\n"); - - for (count = i = 1; i < view->size >> page_shift; i++, count++) - { - BYTE next = get_page_vprot( addr + (count << page_shift) ); - if (next == prot) continue; - TRACE( " %p - %p %s\n", - addr, addr + (count << page_shift) - 1, get_prot_str(prot) ); - addr += (count << page_shift); - prot = next; - count = 0; - } - if (count) - TRACE( " %p - %p %s\n", - addr, addr + (count << page_shift) - 1, get_prot_str(prot) ); +static void dump_view(struct file_view *view) { + UINT i, count; + char *addr = view->base; + BYTE prot = get_page_vprot(addr); + + TRACE("View: %p - %p", addr, addr + view->size - 1); + if (view->protect & VPROT_SYSTEM) + TRACE(" (builtin image)\n"); + else if (view->protect & VPROT_FREE_PLACEHOLDER) + TRACE(" (placeholder)\n"); + else if (view->protect & SEC_IMAGE) + TRACE(" (image)\n"); + else if (view->protect & SEC_FILE) + TRACE(" (file)\n"); + else if (view->protect & (SEC_RESERVE | SEC_COMMIT)) + TRACE(" (anonymous)\n"); + else + TRACE(" (valloc)\n"); + + for (count = i = 1; i < view->size >> page_shift; i++, count++) { + BYTE next = get_page_vprot(addr + (count << page_shift)); + if (next == prot) + continue; + TRACE(" %p - %p %s\n", addr, addr + (count << page_shift) - 1, + get_prot_str(prot)); + addr += (count << page_shift); + prot = next; + count = 0; + } + if (count) + TRACE(" %p - %p %s\n", addr, addr + (count << page_shift) - 1, + get_prot_str(prot)); } - /*********************************************************************** * VIRTUAL_Dump */ #ifdef WINE_VM_DEBUG -static void VIRTUAL_Dump(void) -{ - sigset_t sigset; - struct file_view *view; +static void VIRTUAL_Dump(void) { + sigset_t sigset; + struct file_view *view; - TRACE( "Dump of all virtual memory views:\n" ); - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - WINE_RB_FOR_EACH_ENTRY( view, &views_tree, struct file_view, entry ) - { - dump_view( view ); - } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); + TRACE("Dump of all virtual memory views:\n"); + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + WINE_RB_FOR_EACH_ENTRY(view, &views_tree, struct file_view, entry) { + dump_view(view); + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); } #endif - /*********************************************************************** * find_view * - * Find the view containing a given address. virtual_mutex must be held by caller. + * Find the view containing a given address. virtual_mutex must be held by + * caller. * * PARAMS * addr [I] Address @@ -1218,180 +1210,174 @@ static void VIRTUAL_Dump(void) * View: Success * NULL: Failure */ -static struct file_view *find_view( const void *addr, size_t size ) -{ - struct wine_rb_entry *ptr = views_tree.root; +static struct file_view *find_view(const void *addr, size_t size) { + struct wine_rb_entry *ptr = views_tree.root; - if ((const char *)addr + size < (const char *)addr) return NULL; /* overflow */ + if ((const char *)addr + size < (const char *)addr) + return NULL; /* overflow */ - while (ptr) - { - struct file_view *view = WINE_RB_ENTRY_VALUE( ptr, struct file_view, entry ); + while (ptr) { + struct file_view *view = WINE_RB_ENTRY_VALUE(ptr, struct file_view, entry); - if (view->base > addr) ptr = ptr->left; - else if ((const char *)view->base + view->size <= (const char *)addr) ptr = ptr->right; - else if ((const char *)view->base + view->size < (const char *)addr + size) break; /* size too large */ - else return view; - } - return NULL; + if (view->base > addr) + ptr = ptr->left; + else if ((const char *)view->base + view->size <= (const char *)addr) + ptr = ptr->right; + else if ((const char *)view->base + view->size < (const char *)addr + size) + break; /* size too large */ + else + return view; + } + return NULL; } - /*********************************************************************** * is_write_watch_range */ -static inline BOOL is_write_watch_range( const void *addr, size_t size ) -{ - struct file_view *view = find_view( addr, size ); - return view && (view->protect & VPROT_WRITEWATCH); +static inline BOOL is_write_watch_range(const void *addr, size_t size) { + struct file_view *view = find_view(addr, size); + return view && (view->protect & VPROT_WRITEWATCH); } - /*********************************************************************** * find_view_range * * Find the first view overlapping at least part of the specified range. * virtual_mutex must be held by caller. */ -static struct file_view *find_view_range( const void *addr, size_t size ) -{ - struct wine_rb_entry *ptr = views_tree.root; +static struct file_view *find_view_range(const void *addr, size_t size) { + struct wine_rb_entry *ptr = views_tree.root; - while (ptr) - { - struct file_view *view = WINE_RB_ENTRY_VALUE( ptr, struct file_view, entry ); + while (ptr) { + struct file_view *view = WINE_RB_ENTRY_VALUE(ptr, struct file_view, entry); - if ((const char *)view->base >= (const char *)addr + size) ptr = ptr->left; - else if ((const char *)view->base + view->size <= (const char *)addr) ptr = ptr->right; - else return view; - } - return NULL; + if ((const char *)view->base >= (const char *)addr + size) + ptr = ptr->left; + else if ((const char *)view->base + view->size <= (const char *)addr) + ptr = ptr->right; + else + return view; + } + return NULL; } - /*********************************************************************** * find_view_inside_range * * Find first (resp. last, if top_down) view inside a range. * virtual_mutex must be held by caller. */ -static struct wine_rb_entry *find_view_inside_range( void **base_ptr, void **end_ptr, int top_down ) -{ - struct wine_rb_entry *first = NULL, *ptr = views_tree.root; - void *base = *base_ptr, *end = *end_ptr; +static struct wine_rb_entry * +find_view_inside_range(void **base_ptr, void **end_ptr, int top_down) { + struct wine_rb_entry *first = NULL, *ptr = views_tree.root; + void *base = *base_ptr, *end = *end_ptr; - /* find the first (resp. last) view inside the range */ - while (ptr) - { - struct file_view *view = WINE_RB_ENTRY_VALUE( ptr, struct file_view, entry ); - if ((char *)view->base + view->size >= (char *)end) - { - end = min( end, view->base ); - ptr = ptr->left; - } - else if (view->base <= base) - { - base = max( (char *)base, (char *)view->base + view->size ); - ptr = ptr->right; - } - else - { - first = ptr; - ptr = top_down ? ptr->right : ptr->left; - } + /* find the first (resp. last) view inside the range */ + while (ptr) { + struct file_view *view = WINE_RB_ENTRY_VALUE(ptr, struct file_view, entry); + if ((char *)view->base + view->size >= (char *)end) { + end = min(end, view->base); + ptr = ptr->left; + } else if (view->base <= base) { + base = max((char *)base, (char *)view->base + view->size); + ptr = ptr->right; + } else { + first = ptr; + ptr = top_down ? ptr->right : ptr->left; } + } - *base_ptr = base; - *end_ptr = end; - return first; + *base_ptr = base; + *end_ptr = end; + return first; } - /*********************************************************************** * try_map_free_area * * Try mmaping some expected free memory region, eventually stepping and * retrying inside it, and return where it actually succeeded, or NULL. */ -static void* try_map_free_area( void *base, void *end, ptrdiff_t step, - void *start, size_t size, int unix_prot ) -{ - while (start && base <= start && (char*)start + size <= (char*)end) - { - if (anon_mmap_tryfixed( start, size, unix_prot, 0 ) != MAP_FAILED) return start; - TRACE( "Found free area is already mapped, start %p.\n", start ); - if (errno != EEXIST) - { - ERR( "mmap() error %s, range %p-%p, unix_prot %#x.\n", - strerror(errno), start, (char *)start + size, unix_prot ); - return NULL; - } - if ((step > 0 && (char *)end - (char *)start < step) || - (step < 0 && (char *)start - (char *)base < -step) || - step == 0) - break; - start = (char *)start + step; +static void *try_map_free_area(void *base, void *end, ptrdiff_t step, + void *start, size_t size, int unix_prot) { + while (start && base <= start && (char *)start + size <= (char *)end) { + if (anon_mmap_tryfixed(start, size, unix_prot, 0) != MAP_FAILED) + return start; + TRACE("Found free area is already mapped, start %p.\n", start); + if (errno != EEXIST) { + ERR("mmap() error %s, range %p-%p, unix_prot %#x.\n", strerror(errno), + start, (char *)start + size, unix_prot); + return NULL; } + if ((step > 0 && (char *)end - (char *)start < step) || + (step < 0 && (char *)start - (char *)base < -step) || step == 0) + break; + start = (char *)start + step; + } - return NULL; + return NULL; } - /*********************************************************************** * map_free_area * * Find a free area between views inside the specified range and map it. * virtual_mutex must be held by caller. */ -static void *map_free_area( void *base, void *end, size_t size, int top_down, int unix_prot, size_t align_mask ) -{ - struct wine_rb_entry *first = find_view_inside_range( &base, &end, top_down ); - ptrdiff_t step = top_down ? -(align_mask + 1) : (align_mask + 1); - void *start; - - if (top_down) - { - start = ROUND_ADDR( (char *)end - size, align_mask ); - if (start >= end || start < base) return NULL; - - while (first) - { - struct file_view *view = WINE_RB_ENTRY_VALUE( first, struct file_view, entry ); - if ((start = try_map_free_area( (char *)view->base + view->size, (char *)start + size, step, - start, size, unix_prot ))) break; - start = ROUND_ADDR( (char *)view->base - size, align_mask ); - /* stop if remaining space is not large enough */ - if (!start || start >= end || start < base) return NULL; - first = rb_prev( first ); - } - } - else - { - start = ROUND_ADDR( (char *)base + align_mask, align_mask ); - if (!start || start >= end || (char *)end - (char *)start < size) return NULL; - - while (first) - { - struct file_view *view = WINE_RB_ENTRY_VALUE( first, struct file_view, entry ); - if ((start = try_map_free_area( start, view->base, step, - start, size, unix_prot ))) break; - start = ROUND_ADDR( (char *)view->base + view->size + align_mask, align_mask ); - /* stop if remaining space is not large enough */ - if (!start || start >= end || (char *)end - (char *)start < size) return NULL; - first = rb_next( first ); - } +static void *map_free_area(void *base, void *end, size_t size, int top_down, + int unix_prot, size_t align_mask) { + struct wine_rb_entry *first = find_view_inside_range(&base, &end, top_down); + ptrdiff_t step = top_down ? -(align_mask + 1) : (align_mask + 1); + void *start; + + if (top_down) { + start = ROUND_ADDR((char *)end - size, align_mask); + if (start >= end || start < base) + return NULL; + + while (first) { + struct file_view *view = + WINE_RB_ENTRY_VALUE(first, struct file_view, entry); + if ((start = try_map_free_area((char *)view->base + view->size, + (char *)start + size, step, start, size, + unix_prot))) + break; + start = ROUND_ADDR((char *)view->base - size, align_mask); + /* stop if remaining space is not large enough */ + if (!start || start >= end || start < base) + return NULL; + first = rb_prev(first); + } + } else { + start = ROUND_ADDR((char *)base + align_mask, align_mask); + if (!start || start >= end || (char *)end - (char *)start < size) + return NULL; + + while (first) { + struct file_view *view = + WINE_RB_ENTRY_VALUE(first, struct file_view, entry); + if ((start = try_map_free_area(start, view->base, step, start, size, + unix_prot))) + break; + start = + ROUND_ADDR((char *)view->base + view->size + align_mask, align_mask); + /* stop if remaining space is not large enough */ + if (!start || start >= end || (char *)end - (char *)start < size) + return NULL; + first = rb_next(first); } + } - if (!first) - start = try_map_free_area( base, end, step, start, size, unix_prot ); + if (!first) + start = try_map_free_area(base, end, step, start, size, unix_prot); - if (!start) - ERR( "couldn't map free area in range %p-%p, size %p\n", base, end, (void *)size ); + if (!start) + ERR("couldn't map free area in range %p-%p, size %p\n", base, end, + (void *)size); - return start; + return start; } - /*********************************************************************** * find_reserved_free_area * @@ -1399,49 +1385,51 @@ static void *map_free_area( void *base, void *end, size_t size, int top_down, in * virtual_mutex must be held by caller. * The range must be inside a reserved area. */ -static void *find_reserved_free_area( void *base, void *end, size_t size, int top_down, size_t align_mask ) -{ - struct range_entry *range; - void *start; +static void *find_reserved_free_area(void *base, void *end, size_t size, + int top_down, size_t align_mask) { + struct range_entry *range; + void *start; - base = ROUND_ADDR( (char *)base + align_mask, align_mask ); - end = (char *)ROUND_ADDR( (char *)end - size, align_mask ) + size; + base = ROUND_ADDR((char *)base + align_mask, align_mask); + end = (char *)ROUND_ADDR((char *)end - size, align_mask) + size; - if (top_down) - { - start = (char *)end - size; - range = free_ranges_lower_bound( start ); - assert(range != free_ranges_end && range->end >= start); - - if ((char *)range->end - (char *)start < size) start = ROUND_ADDR( (char *)range->end - size, align_mask ); - do - { - if (start >= end || start < base || (char *)end - (char *)start < size) return NULL; - if (start < range->end && start >= range->base && (char *)range->end - (char *)start >= size) break; - if (--range < free_ranges) return NULL; - start = ROUND_ADDR( (char *)range->end - size, align_mask ); - } - while (1); - } - else - { - start = base; - range = free_ranges_lower_bound( start ); - assert(range != free_ranges_end && range->end >= start); - - if (start < range->base) start = ROUND_ADDR( (char *)range->base + align_mask, align_mask ); - do - { - if (start >= end || start < base || (char *)end - (char *)start < size) return NULL; - if (start < range->end && start >= range->base && (char *)range->end - (char *)start >= size) break; - if (++range == free_ranges_end) return NULL; - start = ROUND_ADDR( (char *)range->base + align_mask, align_mask ); - } - while (1); - } - return start; -} + if (top_down) { + start = (char *)end - size; + range = free_ranges_lower_bound(start); + assert(range != free_ranges_end && range->end >= start); + if ((char *)range->end - (char *)start < size) + start = ROUND_ADDR((char *)range->end - size, align_mask); + do { + if (start >= end || start < base || (char *)end - (char *)start < size) + return NULL; + if (start < range->end && start >= range->base && + (char *)range->end - (char *)start >= size) + break; + if (--range < free_ranges) + return NULL; + start = ROUND_ADDR((char *)range->end - size, align_mask); + } while (1); + } else { + start = base; + range = free_ranges_lower_bound(start); + assert(range != free_ranges_end && range->end >= start); + + if (start < range->base) + start = ROUND_ADDR((char *)range->base + align_mask, align_mask); + do { + if (start >= end || start < base || (char *)end - (char *)start < size) + return NULL; + if (start < range->end && start >= range->base && + (char *)range->end - (char *)start >= size) + break; + if (++range == free_ranges_end) + return NULL; + start = ROUND_ADDR((char *)range->base + align_mask, align_mask); + } while (1); + } + return start; +} /*********************************************************************** * remove_reserved_area @@ -1449,448 +1437,440 @@ static void *find_reserved_free_area( void *base, void *end, size_t size, int to * Remove a reserved area from the list maintained by libwine. * virtual_mutex must be held by caller. */ -static void remove_reserved_area( void *addr, size_t size ) -{ - struct file_view *view; +static void remove_reserved_area(void *addr, size_t size) { + struct file_view *view; - TRACE( "removing %p-%p\n", addr, (char *)addr + size ); - mmap_remove_reserved_area( addr, size ); + TRACE("removing %p-%p\n", addr, (char *)addr + size); + mmap_remove_reserved_area(addr, size); - /* unmap areas not covered by an existing view */ - WINE_RB_FOR_EACH_ENTRY( view, &views_tree, struct file_view, entry ) - { - if ((char *)view->base >= (char *)addr + size) break; - if ((char *)view->base + view->size <= (char *)addr) continue; - if (view->base > addr) munmap( addr, (char *)view->base - (char *)addr ); - if ((char *)view->base + view->size > (char *)addr + size) return; - size = (char *)addr + size - ((char *)view->base + view->size); - addr = (char *)view->base + view->size; - } - munmap( addr, size ); + /* unmap areas not covered by an existing view */ + WINE_RB_FOR_EACH_ENTRY(view, &views_tree, struct file_view, entry) { + if ((char *)view->base >= (char *)addr + size) + break; + if ((char *)view->base + view->size <= (char *)addr) + continue; + if (view->base > addr) + munmap(addr, (char *)view->base - (char *)addr); + if ((char *)view->base + view->size > (char *)addr + size) + return; + size = (char *)addr + size - ((char *)view->base + view->size); + addr = (char *)view->base + view->size; + } + munmap(addr, size); } - /*********************************************************************** * unmap_area * * Unmap an area, or simply replace it by an empty mapping if it is * in a reserved area. virtual_mutex must be held by caller. */ -static void unmap_area( void *start, size_t size ) -{ - struct reserved_area *area; - void *end; +static void unmap_area(void *start, size_t size) { + struct reserved_area *area; + void *end; - if (!(size = unmap_area_above_user_limit( start, size ))) return; + if (!(size = unmap_area_above_user_limit(start, size))) + return; - end = (char *)start + size; + end = (char *)start + size; - LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) - { - void *area_start = area->base; - void *area_end = (char *)area_start + area->size; - - if (area_start >= end) break; - if (area_end <= start) continue; - if (area_start > start) - { - munmap( start, (char *)area_start - (char *)start ); - start = area_start; - } - if (area_end >= end) - { - anon_mmap_fixed( start, (char *)end - (char *)start, PROT_NONE, MAP_NORESERVE ); - return; - } - anon_mmap_fixed( start, (char *)area_end - (char *)start, PROT_NONE, MAP_NORESERVE ); - start = area_end; + LIST_FOR_EACH_ENTRY(area, &reserved_areas, struct reserved_area, entry) { + void *area_start = area->base; + void *area_end = (char *)area_start + area->size; + + if (area_start >= end) + break; + if (area_end <= start) + continue; + if (area_start > start) { + munmap(start, (char *)area_start - (char *)start); + start = area_start; } - munmap( start, (char *)end - (char *)start ); + if (area_end >= end) { + anon_mmap_fixed(start, (char *)end - (char *)start, PROT_NONE, + MAP_NORESERVE); + return; + } + anon_mmap_fixed(start, (char *)area_end - (char *)start, PROT_NONE, + MAP_NORESERVE); + start = area_end; + } + munmap(start, (char *)end - (char *)start); } - /*********************************************************************** * alloc_view * * Allocate a new view. virtual_mutex must be held by caller. */ -static struct file_view *alloc_view(void) -{ - if (next_free_view) - { - struct file_view *ret = next_free_view; - next_free_view = *(struct file_view **)ret; - return ret; - } - if (view_block_start == view_block_end) - { - void *ptr = anon_mmap_alloc( view_block_size, PROT_READ | PROT_WRITE ); - if (ptr == MAP_FAILED) return NULL; - view_block_start = ptr; - view_block_end = view_block_start + view_block_size / sizeof(*view_block_start); - } - return view_block_start++; +static struct file_view *alloc_view(void) { + if (next_free_view) { + struct file_view *ret = next_free_view; + next_free_view = *(struct file_view **)ret; + return ret; + } + if (view_block_start == view_block_end) { + void *ptr = anon_mmap_alloc(view_block_size, PROT_READ | PROT_WRITE); + if (ptr == MAP_FAILED) + return NULL; + view_block_start = ptr; + view_block_end = + view_block_start + view_block_size / sizeof(*view_block_start); + } + return view_block_start++; } - /*********************************************************************** * free_view * * Free memory for view structure. virtual_mutex must be held by caller. */ -static void free_view( struct file_view *view ) -{ - *(struct file_view **)view = next_free_view; - next_free_view = view; +static void free_view(struct file_view *view) { + *(struct file_view **)view = next_free_view; + next_free_view = view; } - /*********************************************************************** * unregister_view * - * Remove view from the tree and update free ranges. virtual_mutex must be held by caller. + * Remove view from the tree and update free ranges. virtual_mutex must be held + * by caller. */ -static void unregister_view( struct file_view *view ) -{ - if (mmap_is_in_reserved_area( view->base, view->size )) - free_ranges_remove_view( view ); - wine_rb_remove( &views_tree, &view->entry ); +static void unregister_view(struct file_view *view) { + if (mmap_is_in_reserved_area(view->base, view->size)) + free_ranges_remove_view(view); + wine_rb_remove(&views_tree, &view->entry); } - /*********************************************************************** * delete_view * * Deletes a view. virtual_mutex must be held by caller. */ -static void delete_view( struct file_view *view ) /* [in] View */ +static void delete_view(struct file_view *view) /* [in] View */ { - if (!(view->protect & VPROT_SYSTEM)) unmap_area( view->base, view->size ); - set_page_vprot( view->base, view->size, 0 ); - if (view->protect & VPROT_ARM64EC) clear_arm64ec_range( view->base, view->size ); - unregister_view( view ); - free_view( view ); + if (!(view->protect & VPROT_SYSTEM)) + unmap_area(view->base, view->size); + set_page_vprot(view->base, view->size, 0); + if (view->protect & VPROT_ARM64EC) + clear_arm64ec_range(view->base, view->size); + unregister_view(view); + free_view(view); } - /*********************************************************************** * register_view * - * Add view to the tree and update free ranges. virtual_mutex must be held by caller. + * Add view to the tree and update free ranges. virtual_mutex must be held by + * caller. */ -static void register_view( struct file_view *view ) -{ - wine_rb_put( &views_tree, view->base, &view->entry ); - if (mmap_is_in_reserved_area( view->base, view->size )) - free_ranges_insert_view( view ); +static void register_view(struct file_view *view) { + wine_rb_put(&views_tree, view->base, &view->entry); + if (mmap_is_in_reserved_area(view->base, view->size)) + free_ranges_insert_view(view); } - /*********************************************************************** * create_view * * Create a view. virtual_mutex must be held by caller. */ -static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t size, unsigned int vprot ) -{ - struct file_view *view; - int unix_prot = get_unix_prot( vprot ); +static NTSTATUS create_view(struct file_view **view_ret, void *base, + size_t size, unsigned int vprot) { + struct file_view *view; + int unix_prot = get_unix_prot(vprot); - assert( !((UINT_PTR)base & page_mask) ); - assert( !(size & page_mask) ); + assert(!((UINT_PTR)base & page_mask)); + assert(!(size & page_mask)); - /* Check for overlapping views. This can happen if the previous view - * was a system view that got unmapped behind our back. In that case - * we recover by simply deleting it. */ + /* Check for overlapping views. This can happen if the previous view + * was a system view that got unmapped behind our back. In that case + * we recover by simply deleting it. */ - while ((view = find_view_range( base, size ))) - { - TRACE( "overlapping view %p-%p for %p-%p\n", - view->base, (char *)view->base + view->size, base, (char *)base + size ); - assert( view->protect & VPROT_SYSTEM ); - delete_view( view ); - } + while ((view = find_view_range(base, size))) { + TRACE("overlapping view %p-%p for %p-%p\n", view->base, + (char *)view->base + view->size, base, (char *)base + size); + assert(view->protect & VPROT_SYSTEM); + delete_view(view); + } - if (!alloc_pages_vprot( base, size )) return STATUS_NO_MEMORY; + if (!alloc_pages_vprot(base, size)) + return STATUS_NO_MEMORY; - /* Create the view structure */ + /* Create the view structure */ - if (!(view = alloc_view())) - { - FIXME( "out of memory for %p-%p\n", base, (char *)base + size ); - return STATUS_NO_MEMORY; - } + if (!(view = alloc_view())) { + FIXME("out of memory for %p-%p\n", base, (char *)base + size); + return STATUS_NO_MEMORY; + } - view->base = base; - view->size = size; - view->protect = vprot; - set_page_vprot( base, size, vprot ); + view->base = base; + view->size = size; + view->protect = vprot; + set_page_vprot(base, size, vprot); - register_view( view ); + register_view(view); - *view_ret = view; + *view_ret = view; - if (force_exec_prot && (unix_prot & PROT_READ) && !(unix_prot & PROT_EXEC)) - { - TRACE( "forcing exec permission on %p-%p\n", base, (char *)base + size - 1 ); - mprotect( base, size, unix_prot | PROT_EXEC ); - } - return STATUS_SUCCESS; + if (force_exec_prot && (unix_prot & PROT_READ) && !(unix_prot & PROT_EXEC)) { + TRACE("forcing exec permission on %p-%p\n", base, (char *)base + size - 1); + mprotect(base, size, unix_prot | PROT_EXEC); + } + return STATUS_SUCCESS; } - /*********************************************************************** * get_win32_prot * * Convert page protections to Win32 flags. */ -static DWORD get_win32_prot( BYTE vprot, unsigned int map_prot ) -{ - DWORD ret = VIRTUAL_Win32Flags[vprot & 0x0f]; - if (vprot & VPROT_GUARD) ret |= PAGE_GUARD; - if (map_prot & SEC_NOCACHE) ret |= PAGE_NOCACHE; - return ret; +static DWORD get_win32_prot(BYTE vprot, unsigned int map_prot) { + DWORD ret = VIRTUAL_Win32Flags[vprot & 0x0f]; + if (vprot & VPROT_GUARD) + ret |= PAGE_GUARD; + if (map_prot & SEC_NOCACHE) + ret |= PAGE_NOCACHE; + return ret; } - /*********************************************************************** * get_vprot_flags * * Build page protections from Win32 flags. */ -static NTSTATUS get_vprot_flags( DWORD protect, unsigned int *vprot, BOOL image ) -{ - switch(protect & 0xff) - { - case PAGE_READONLY: - *vprot = VPROT_READ; - break; - case PAGE_READWRITE: - if (image) - *vprot = VPROT_READ | VPROT_WRITECOPY; - else - *vprot = VPROT_READ | VPROT_WRITE; - break; - case PAGE_WRITECOPY: - *vprot = VPROT_READ | VPROT_WRITECOPY; - break; - case PAGE_EXECUTE: - *vprot = VPROT_EXEC; - break; - case PAGE_EXECUTE_READ: - *vprot = VPROT_EXEC | VPROT_READ; - break; - case PAGE_EXECUTE_READWRITE: - if (image) - *vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY; - else - *vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE; - break; - case PAGE_EXECUTE_WRITECOPY: - *vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY; - break; - case PAGE_NOACCESS: - *vprot = 0; - break; - default: - return STATUS_INVALID_PAGE_PROTECTION; - } - if (protect & PAGE_GUARD) *vprot |= VPROT_GUARD; - return STATUS_SUCCESS; +static NTSTATUS get_vprot_flags(DWORD protect, unsigned int *vprot, + BOOL image) { + switch (protect & 0xff) { + case PAGE_READONLY: + *vprot = VPROT_READ; + break; + case PAGE_READWRITE: + if (image) + *vprot = VPROT_READ | VPROT_WRITECOPY; + else + *vprot = VPROT_READ | VPROT_WRITE; + break; + case PAGE_WRITECOPY: + *vprot = VPROT_READ | VPROT_WRITECOPY; + break; + case PAGE_EXECUTE: + *vprot = VPROT_EXEC; + break; + case PAGE_EXECUTE_READ: + *vprot = VPROT_EXEC | VPROT_READ; + break; + case PAGE_EXECUTE_READWRITE: + if (image) + *vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY; + else + *vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE; + break; + case PAGE_EXECUTE_WRITECOPY: + *vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY; + break; + case PAGE_NOACCESS: + *vprot = 0; + break; + default: + return STATUS_INVALID_PAGE_PROTECTION; + } + if (protect & PAGE_GUARD) + *vprot |= VPROT_GUARD; + return STATUS_SUCCESS; } - /*********************************************************************** * mprotect_exec * * Wrapper for mprotect, adds PROT_EXEC if forced by force_exec_prot */ -static inline int mprotect_exec( void *base, size_t size, int unix_prot ) -{ - if (force_exec_prot && (unix_prot & PROT_READ) && !(unix_prot & PROT_EXEC)) - { - TRACE( "forcing exec permission on %p-%p\n", base, (char *)base + size - 1 ); - if (!mprotect( base, size, unix_prot | PROT_EXEC )) return 0; - /* exec + write may legitimately fail, in that case fall back to write only */ - if (!(unix_prot & PROT_WRITE)) return -1; - } +static inline int mprotect_exec(void *base, size_t size, int unix_prot) { + if (force_exec_prot && (unix_prot & PROT_READ) && !(unix_prot & PROT_EXEC)) { + TRACE("forcing exec permission on %p-%p\n", base, (char *)base + size - 1); + if (!mprotect(base, size, unix_prot | PROT_EXEC)) + return 0; + /* exec + write may legitimately fail, in that case fall back to write only + */ + if (!(unix_prot & PROT_WRITE)) + return -1; + } - return mprotect( base, size, unix_prot ); + return mprotect(base, size, unix_prot); } - /*********************************************************************** * mprotect_range * - * Call mprotect on a page range, applying the protections from the per-page byte. - */ -static void mprotect_range( void *base, size_t size, BYTE set, BYTE clear ) -{ - size_t i, count; - char *addr = ROUND_ADDR( base, page_mask ); - int prot, next; - - size = ROUND_SIZE( base, size ); - prot = get_unix_prot( (get_page_vprot( addr ) & ~clear ) | set ); - for (count = i = 1; i < size >> page_shift; i++, count++) - { - next = get_unix_prot( (get_page_vprot( addr + (count << page_shift) ) & ~clear) | set ); - if (next == prot) continue; - mprotect_exec( addr, count << page_shift, prot ); - addr += count << page_shift; - prot = next; - count = 0; - } - if (count) mprotect_exec( addr, count << page_shift, prot ); + * Call mprotect on a page range, applying the protections from the per-page + * byte. + */ +static void mprotect_range(void *base, size_t size, BYTE set, BYTE clear) { + size_t i, count; + char *addr = ROUND_ADDR(base, page_mask); + int prot, next; + + size = ROUND_SIZE(base, size); + prot = get_unix_prot((get_page_vprot(addr) & ~clear) | set); + for (count = i = 1; i < size >> page_shift; i++, count++) { + next = get_unix_prot( + (get_page_vprot(addr + (count << page_shift)) & ~clear) | set); + if (next == prot) + continue; + mprotect_exec(addr, count << page_shift, prot); + addr += count << page_shift; + prot = next; + count = 0; + } + if (count) + mprotect_exec(addr, count << page_shift, prot); } - /*********************************************************************** * set_vprot * * Change the protection of a range of pages. */ -static BOOL set_vprot( struct file_view *view, void *base, size_t size, BYTE vprot ) -{ - if (view->protect & VPROT_WRITEWATCH) - { - /* each page may need different protections depending on write watch flag */ - set_page_vprot_bits( base, size, vprot & ~VPROT_WRITEWATCH, ~vprot & ~VPROT_WRITEWATCH ); - mprotect_range( base, size, 0, 0 ); - return TRUE; - } - if (enable_write_exceptions && is_vprot_exec_write( vprot )) vprot |= VPROT_WRITEWATCH; - if (mprotect_exec( base, size, get_unix_prot(vprot) )) return FALSE; - set_page_vprot( base, size, vprot ); +static BOOL set_vprot(struct file_view *view, void *base, size_t size, + BYTE vprot) { + if (view->protect & VPROT_WRITEWATCH) { + /* each page may need different protections depending on write watch flag */ + set_page_vprot_bits(base, size, vprot & ~VPROT_WRITEWATCH, + ~vprot & ~VPROT_WRITEWATCH); + mprotect_range(base, size, 0, 0); return TRUE; + } + if (enable_write_exceptions && is_vprot_exec_write(vprot)) + vprot |= VPROT_WRITEWATCH; + if (mprotect_exec(base, size, get_unix_prot(vprot))) + return FALSE; + set_page_vprot(base, size, vprot); + return TRUE; } - /*********************************************************************** * set_protection * * Set page protections on a range of pages */ -static NTSTATUS set_protection( struct file_view *view, void *base, SIZE_T size, ULONG protect ) -{ - unsigned int vprot; - NTSTATUS status; +static NTSTATUS set_protection(struct file_view *view, void *base, SIZE_T size, + ULONG protect) { + unsigned int vprot; + NTSTATUS status; - if ((status = get_vprot_flags( protect, &vprot, view->protect & SEC_IMAGE ))) return status; - if (is_view_valloc( view )) - { - if (vprot & VPROT_WRITECOPY) return STATUS_INVALID_PAGE_PROTECTION; - } - else - { - BYTE access = vprot & (VPROT_READ | VPROT_WRITE | VPROT_EXEC); - if ((view->protect & access) != access) return STATUS_INVALID_PAGE_PROTECTION; - } + if ((status = get_vprot_flags(protect, &vprot, view->protect & SEC_IMAGE))) + return status; + if (is_view_valloc(view)) { + if (vprot & VPROT_WRITECOPY) + return STATUS_INVALID_PAGE_PROTECTION; + } else { + BYTE access = vprot & (VPROT_READ | VPROT_WRITE | VPROT_EXEC); + if ((view->protect & access) != access) + return STATUS_INVALID_PAGE_PROTECTION; + } - if (!set_vprot( view, base, size, vprot | VPROT_COMMITTED )) return STATUS_ACCESS_DENIED; - return STATUS_SUCCESS; + if (!set_vprot(view, base, size, vprot | VPROT_COMMITTED)) + return STATUS_ACCESS_DENIED; + return STATUS_SUCCESS; } - /*********************************************************************** * commit_arm64ec_map * * Make sure that the pages corresponding to the address range of the view * are committed in the ARM64EC code map. */ -static void commit_arm64ec_map( struct file_view *view ) -{ - size_t start = ((size_t)view->base >> page_shift) / 8; - size_t end = (((size_t)view->base + view->size) >> page_shift) / 8; - size_t size = ROUND_SIZE( start, end + 1 - start ); - void *base = ROUND_ADDR( (char *)arm64ec_view->base + start, page_mask ); +static void commit_arm64ec_map(struct file_view *view) { + size_t start = ((size_t)view->base >> page_shift) / 8; + size_t end = (((size_t)view->base + view->size) >> page_shift) / 8; + size_t size = ROUND_SIZE(start, end + 1 - start); + void *base = ROUND_ADDR((char *)arm64ec_view->base + start, page_mask); - view->protect |= VPROT_ARM64EC; - set_vprot( arm64ec_view, base, size, VPROT_READ | VPROT_WRITE | VPROT_COMMITTED ); + view->protect |= VPROT_ARM64EC; + set_vprot(arm64ec_view, base, size, + VPROT_READ | VPROT_WRITE | VPROT_COMMITTED); } - /*********************************************************************** * update_write_watches */ -static void update_write_watches( void *base, size_t size, size_t accessed_size ) -{ - TRACE( "updating watch %p-%p-%p\n", base, (char *)base + accessed_size, (char *)base + size ); - /* clear write watch flag on accessed pages */ - set_page_vprot_bits( base, accessed_size, 0, VPROT_WRITEWATCH ); - /* restore page protections on the entire range */ - mprotect_range( base, size, 0, 0 ); +static void update_write_watches(void *base, size_t size, + size_t accessed_size) { + TRACE("updating watch %p-%p-%p\n", base, (char *)base + accessed_size, + (char *)base + size); + /* clear write watch flag on accessed pages */ + set_page_vprot_bits(base, accessed_size, 0, VPROT_WRITEWATCH); + /* restore page protections on the entire range */ + mprotect_range(base, size, 0, 0); } - /*********************************************************************** * reset_write_watches * * Reset write watches in a memory range. */ -static void reset_write_watches( void *base, SIZE_T size ) -{ - set_page_vprot_bits( base, size, VPROT_WRITEWATCH, 0 ); - mprotect_range( base, size, 0, 0 ); +static void reset_write_watches(void *base, SIZE_T size) { + set_page_vprot_bits(base, size, VPROT_WRITEWATCH, 0); + mprotect_range(base, size, 0, 0); } - /*********************************************************************** * unmap_extra_space * - * Release the extra memory while keeping the range starting on the alignment boundary. + * Release the extra memory while keeping the range starting on the alignment + * boundary. */ -static inline void *unmap_extra_space( void *ptr, size_t total_size, size_t wanted_size, size_t align_mask ) -{ - if ((ULONG_PTR)ptr & align_mask) - { - size_t extra = align_mask + 1 - ((ULONG_PTR)ptr & align_mask); - munmap( ptr, extra ); - ptr = (char *)ptr + extra; - total_size -= extra; - } - if (total_size > wanted_size) - munmap( (char *)ptr + wanted_size, total_size - wanted_size ); - return ptr; +static inline void *unmap_extra_space(void *ptr, size_t total_size, + size_t wanted_size, size_t align_mask) { + if ((ULONG_PTR)ptr & align_mask) { + size_t extra = align_mask + 1 - ((ULONG_PTR)ptr & align_mask); + munmap(ptr, extra); + ptr = (char *)ptr + extra; + total_size -= extra; + } + if (total_size > wanted_size) + munmap((char *)ptr + wanted_size, total_size - wanted_size); + return ptr; } - /*********************************************************************** * find_reserved_free_area_outside_preloader * - * Find a free area inside a reserved area, skipping the preloader reserved range. - * virtual_mutex must be held by caller. - */ -static void *find_reserved_free_area_outside_preloader( void *start, void *end, size_t size, - int top_down, size_t align_mask ) -{ - void *ret; - - if (preload_reserve_end >= end) - { - if (preload_reserve_start <= start) return NULL; /* no space in that area */ - if (preload_reserve_start < end) end = preload_reserve_start; - } - else if (preload_reserve_start <= start) - { - if (preload_reserve_end > start) start = preload_reserve_end; - } - else /* range is split in two by the preloader reservation, try both parts */ - { - if (top_down) - { - ret = find_reserved_free_area( preload_reserve_end, end, size, top_down, align_mask ); - if (ret) return ret; - end = preload_reserve_start; - } - else - { - ret = find_reserved_free_area( start, preload_reserve_start, size, top_down, align_mask ); - if (ret) return ret; - start = preload_reserve_end; - } + * Find a free area inside a reserved area, skipping the preloader reserved + * range. virtual_mutex must be held by caller. + */ +static void *find_reserved_free_area_outside_preloader(void *start, void *end, + size_t size, + int top_down, + size_t align_mask) { + void *ret; + + if (preload_reserve_end >= end) { + if (preload_reserve_start <= start) + return NULL; /* no space in that area */ + if (preload_reserve_start < end) + end = preload_reserve_start; + } else if (preload_reserve_start <= start) { + if (preload_reserve_end > start) + start = preload_reserve_end; + } else /* range is split in two by the preloader reservation, try both parts + */ + { + if (top_down) { + ret = find_reserved_free_area(preload_reserve_end, end, size, top_down, + align_mask); + if (ret) + return ret; + end = preload_reserve_start; + } else { + ret = find_reserved_free_area(start, preload_reserve_start, size, + top_down, align_mask); + if (ret) + return ret; + start = preload_reserve_end; } - return find_reserved_free_area( start, end, size, top_down, align_mask ); + } + return find_reserved_free_area(start, end, size, top_down, align_mask); } /*********************************************************************** @@ -1899,44 +1879,52 @@ static void *find_reserved_free_area_outside_preloader( void *start, void *end, * Try to map some space inside a reserved area. * virtual_mutex must be held by caller. */ -static void *map_reserved_area( void *limit_low, void *limit_high, size_t size, int top_down, - int unix_prot, size_t align_mask ) -{ - void *ptr = NULL; - struct reserved_area *area; +static void *map_reserved_area(void *limit_low, void *limit_high, size_t size, + int top_down, int unix_prot, size_t align_mask) { + void *ptr = NULL; + struct reserved_area *area; - if (top_down) - { - LIST_FOR_EACH_ENTRY_REV( area, &reserved_areas, struct reserved_area, entry ) - { - void *start = area->base; - void *end = (char *)start + area->size; - - if (start >= limit_high) continue; - if (end <= limit_low) return NULL; - if (start < limit_low) start = limit_low; - if (end > limit_high) end = limit_high; - ptr = find_reserved_free_area_outside_preloader( start, end, size, top_down, align_mask ); - if (ptr) break; - } + if (top_down) { + LIST_FOR_EACH_ENTRY_REV(area, &reserved_areas, struct reserved_area, + entry) { + void *start = area->base; + void *end = (char *)start + area->size; + + if (start >= limit_high) + continue; + if (end <= limit_low) + return NULL; + if (start < limit_low) + start = limit_low; + if (end > limit_high) + end = limit_high; + ptr = find_reserved_free_area_outside_preloader(start, end, size, + top_down, align_mask); + if (ptr) + break; } - else - { - LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) - { - void *start = area->base; - void *end = (char *)start + area->size; - - if (start >= limit_high) return NULL; - if (end <= limit_low) continue; - if (start < limit_low) start = limit_low; - if (end > limit_high) end = limit_high; - ptr = find_reserved_free_area_outside_preloader( start, end, size, top_down, align_mask ); - if (ptr) break; - } + } else { + LIST_FOR_EACH_ENTRY(area, &reserved_areas, struct reserved_area, entry) { + void *start = area->base; + void *end = (char *)start + area->size; + + if (start >= limit_high) + return NULL; + if (end <= limit_low) + continue; + if (start < limit_low) + start = limit_low; + if (end > limit_high) + end = limit_high; + ptr = find_reserved_free_area_outside_preloader(start, end, size, + top_down, align_mask); + if (ptr) + break; } - if (ptr && anon_mmap_fixed( ptr, size, unix_prot, 0 ) != ptr) ptr = NULL; - return ptr; + } + if (ptr && anon_mmap_fixed(ptr, size, unix_prot, 0) != ptr) + ptr = NULL; + return ptr; } /*********************************************************************** @@ -1945,54 +1933,56 @@ static void *map_reserved_area( void *limit_low, void *limit_high, size_t size, * Map a memory area at a fixed address. * virtual_mutex must be held by caller. */ -static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot ) -{ - int unix_prot = get_unix_prot(vprot); - struct reserved_area *area; - NTSTATUS status; - char *start = base, *end = (char *)base + size; - - if (find_view_range( base, size )) return STATUS_CONFLICTING_ADDRESSES; - - LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) - { - char *area_start = area->base; - char *area_end = area_start + area->size; - - if (area_start >= end) break; - if (area_end <= start) continue; - if (area_start > start) - { - if (anon_mmap_tryfixed( start, area_start - start, unix_prot, 0 ) == MAP_FAILED) goto failed; - start = area_start; - } - if (area_end >= end) - { - if (anon_mmap_fixed( start, end - start, unix_prot, 0 ) == MAP_FAILED) goto failed; - return STATUS_SUCCESS; - } - if (anon_mmap_fixed( start, area_end - start, unix_prot, 0 ) == MAP_FAILED) goto failed; - start = area_end; - } - - if (anon_mmap_tryfixed( start, end - start, unix_prot, 0 ) == MAP_FAILED) goto failed; - return STATUS_SUCCESS; +static NTSTATUS map_fixed_area(void *base, size_t size, unsigned int vprot) { + int unix_prot = get_unix_prot(vprot); + struct reserved_area *area; + NTSTATUS status; + char *start = base, *end = (char *)base + size; + + if (find_view_range(base, size)) + return STATUS_CONFLICTING_ADDRESSES; + + LIST_FOR_EACH_ENTRY(area, &reserved_areas, struct reserved_area, entry) { + char *area_start = area->base; + char *area_end = area_start + area->size; + + if (area_start >= end) + break; + if (area_end <= start) + continue; + if (area_start > start) { + if (anon_mmap_tryfixed(start, area_start - start, unix_prot, 0) == + MAP_FAILED) + goto failed; + start = area_start; + } + if (area_end >= end) { + if (anon_mmap_fixed(start, end - start, unix_prot, 0) == MAP_FAILED) + goto failed; + return STATUS_SUCCESS; + } + if (anon_mmap_fixed(start, area_end - start, unix_prot, 0) == MAP_FAILED) + goto failed; + start = area_end; + } + + if (anon_mmap_tryfixed(start, end - start, unix_prot, 0) == MAP_FAILED) + goto failed; + return STATUS_SUCCESS; failed: - if (errno == ENOMEM) - { - ERR( "out of memory for %p-%p\n", base, (char *)base + size ); - status = STATUS_NO_MEMORY; - } - else if (errno == EEXIST) status = STATUS_CONFLICTING_ADDRESSES; - else - { - ERR( "mmap error %s for %p-%p, unix_prot %#x\n", - strerror(errno), base, (char *)base + size, unix_prot ); - status = STATUS_INVALID_PARAMETER; - } - unmap_area( base, start - (char *)base ); - return status; + if (errno == ENOMEM) { + ERR("out of memory for %p-%p\n", base, (char *)base + size); + status = STATUS_NO_MEMORY; + } else if (errno == EEXIST) + status = STATUS_CONFLICTING_ADDRESSES; + else { + ERR("mmap error %s for %p-%p, unix_prot %#x\n", strerror(errno), base, + (char *)base + size, unix_prot); + status = STATUS_INVALID_PARAMETER; + } + unmap_area(base, start - (char *)base); + return status; } /*********************************************************************** @@ -2001,210 +1991,223 @@ static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot ) * Create a view and mmap the corresponding memory area. * virtual_mutex must be held by caller. */ -static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, - unsigned int alloc_type, unsigned int vprot, - ULONG_PTR limit_low, ULONG_PTR limit_high, size_t align_mask ) -{ - int top_down = alloc_type & MEM_TOP_DOWN; - void *ptr; - NTSTATUS status; +static NTSTATUS map_view(struct file_view **view_ret, void *base, size_t size, + unsigned int alloc_type, unsigned int vprot, + ULONG_PTR limit_low, ULONG_PTR limit_high, + size_t align_mask) { + int top_down = alloc_type & MEM_TOP_DOWN; + void *ptr; + NTSTATUS status; - if (alloc_type & MEM_REPLACE_PLACEHOLDER) - { - struct file_view *view; - - if (!(view = find_view( base, 0 ))) return STATUS_INVALID_PARAMETER; - if (view->base != base || view->size != size) return STATUS_CONFLICTING_ADDRESSES; - if (!(view->protect & VPROT_FREE_PLACEHOLDER)) return STATUS_INVALID_PARAMETER; - - TRACE( "found view %p, size %p, protect %#x.\n", view->base, (void *)view->size, view->protect ); + if (alloc_type & MEM_REPLACE_PLACEHOLDER) { + struct file_view *view; - view->protect = vprot | VPROT_PLACEHOLDER; - set_vprot( view, base, size, vprot ); - if (vprot & VPROT_WRITEWATCH) reset_write_watches( base, size ); - *view_ret = view; - return STATUS_SUCCESS; - } + if (!(view = find_view(base, 0))) + return STATUS_INVALID_PARAMETER; + if (view->base != base || view->size != size) + return STATUS_CONFLICTING_ADDRESSES; + if (!(view->protect & VPROT_FREE_PLACEHOLDER)) + return STATUS_INVALID_PARAMETER; - if (limit_high && limit_low >= limit_high) return STATUS_INVALID_PARAMETER; + TRACE("found view %p, size %p, protect %#x.\n", view->base, + (void *)view->size, view->protect); - if (base) - { - if (is_beyond_limit( base, size, address_space_limit )) return STATUS_WORKING_SET_LIMIT_RANGE; - if (limit_low && base < (void *)limit_low) return STATUS_CONFLICTING_ADDRESSES; - if (limit_high && is_beyond_limit( base, size, (void *)limit_high )) return STATUS_CONFLICTING_ADDRESSES; - if (is_beyond_limit( base, size, host_addr_space_limit )) return STATUS_CONFLICTING_ADDRESSES; - if ((status = map_fixed_area( base, size, vprot ))) return status; - if (is_beyond_limit( base, size, working_set_limit )) working_set_limit = address_space_limit; - ptr = base; + view->protect = vprot | VPROT_PLACEHOLDER; + set_vprot(view, base, size, vprot); + if (vprot & VPROT_WRITEWATCH) + reset_write_watches(base, size); + *view_ret = view; + return STATUS_SUCCESS; + } + + if (limit_high && limit_low >= limit_high) + return STATUS_INVALID_PARAMETER; + + if (base) { + if (is_beyond_limit(base, size, address_space_limit)) + return STATUS_WORKING_SET_LIMIT_RANGE; + if (limit_low && base < (void *)limit_low) + return STATUS_CONFLICTING_ADDRESSES; + if (limit_high && is_beyond_limit(base, size, (void *)limit_high)) + return STATUS_CONFLICTING_ADDRESSES; + if (is_beyond_limit(base, size, host_addr_space_limit)) + return STATUS_CONFLICTING_ADDRESSES; + if ((status = map_fixed_area(base, size, vprot))) + return status; + if (is_beyond_limit(base, size, working_set_limit)) + working_set_limit = address_space_limit; + ptr = base; + } else { + void *start = address_space_start; + void *end = min(user_space_limit, host_addr_space_limit); + size_t view_size, unmap_size; + + if (!align_mask) + align_mask = granularity_mask; + view_size = size + align_mask + 1; + + if (limit_low && (void *)limit_low > start) + start = (void *)limit_low; + if (limit_high && (void *)limit_high < end) + end = (char *)limit_high + 1; + + if ((ptr = map_reserved_area(start, end, size, top_down, + get_unix_prot(vprot), align_mask))) { + TRACE("got mem in reserved area %p-%p\n", ptr, (char *)ptr + size); + goto done; + } + + if (start > address_space_start || end < host_addr_space_limit || + top_down) { + if (!(ptr = map_free_area(start, end, size, top_down, + get_unix_prot(vprot), align_mask))) + return STATUS_NO_MEMORY; + TRACE("got mem with map_free_area %p-%p\n", ptr, (char *)ptr + size); + goto done; } - else - { - void *start = address_space_start; - void *end = min( user_space_limit, host_addr_space_limit ); - size_t view_size, unmap_size; - if (!align_mask) align_mask = granularity_mask; - view_size = size + align_mask + 1; - - if (limit_low && (void *)limit_low > start) start = (void *)limit_low; - if (limit_high && (void *)limit_high < end) end = (char *)limit_high + 1; - - if ((ptr = map_reserved_area( start, end, size, top_down, get_unix_prot(vprot), align_mask ))) - { - TRACE( "got mem in reserved area %p-%p\n", ptr, (char *)ptr + size ); - goto done; - } - - if (start > address_space_start || end < host_addr_space_limit || top_down) - { - if (!(ptr = map_free_area( start, end, size, top_down, get_unix_prot(vprot), align_mask ))) - return STATUS_NO_MEMORY; - TRACE( "got mem with map_free_area %p-%p\n", ptr, (char *)ptr + size ); - goto done; - } - - for (;;) - { - if ((ptr = anon_mmap_alloc( view_size, get_unix_prot(vprot) )) == MAP_FAILED) - { - status = (errno == ENOMEM) ? STATUS_NO_MEMORY : STATUS_INVALID_PARAMETER; - ERR( "anon mmap error %s, size %p, unix_prot %#x\n", - strerror(errno), (void *)view_size, get_unix_prot( vprot ) ); - return status; - } - TRACE( "got mem with anon mmap %p-%p\n", ptr, (char *)ptr + size ); - /* if we got something beyond the user limit, unmap it and retry */ - if (!is_beyond_limit( ptr, view_size, user_space_limit )) break; - unmap_size = unmap_area_above_user_limit( ptr, view_size ); - if (unmap_size) munmap( ptr, unmap_size ); - } - ptr = unmap_extra_space( ptr, view_size, size, align_mask ); + for (;;) { + if ((ptr = anon_mmap_alloc(view_size, get_unix_prot(vprot))) == + MAP_FAILED) { + status = + (errno == ENOMEM) ? STATUS_NO_MEMORY : STATUS_INVALID_PARAMETER; + ERR("anon mmap error %s, size %p, unix_prot %#x\n", strerror(errno), + (void *)view_size, get_unix_prot(vprot)); + return status; + } + TRACE("got mem with anon mmap %p-%p\n", ptr, (char *)ptr + size); + /* if we got something beyond the user limit, unmap it and retry */ + if (!is_beyond_limit(ptr, view_size, user_space_limit)) + break; + unmap_size = unmap_area_above_user_limit(ptr, view_size); + if (unmap_size) + munmap(ptr, unmap_size); } + ptr = unmap_extra_space(ptr, view_size, size, align_mask); + } done: - status = create_view( view_ret, ptr, size, vprot ); - if (status != STATUS_SUCCESS) unmap_area( ptr, size ); - return status; + status = create_view(view_ret, ptr, size, vprot); + if (status != STATUS_SUCCESS) + unmap_area(ptr, size); + return status; } - /*********************************************************************** * map_file_into_view * - * Wrapper for mmap() to map a file into a view, falling back to read if mmap fails. - * virtual_mutex must be held by caller. - */ -static NTSTATUS map_file_into_view( struct file_view *view, int fd, size_t start, size_t size, - off_t offset, unsigned int vprot, BOOL removable ) -{ - void *ptr; - int prot = get_unix_prot( vprot | VPROT_COMMITTED /* make sure it is accessible */ ); - unsigned int flags = MAP_FIXED | ((vprot & VPROT_WRITECOPY) ? MAP_PRIVATE : MAP_SHARED); - - assert( start < view->size ); - assert( start + size <= view->size ); - - if (force_exec_prot && (vprot & VPROT_READ)) - { - TRACE( "forcing exec permission on mapping %p-%p\n", - (char *)view->base + start, (char *)view->base + start + size - 1 ); - prot |= PROT_EXEC; - } - - /* only try mmap if media is not removable (or if we require write access) */ - if (!removable || (flags & MAP_SHARED)) - { - if (mmap( (char *)view->base + start, size, prot, flags, fd, offset ) != MAP_FAILED) - goto done; - - switch (errno) - { - case EINVAL: /* file offset is not page-aligned, fall back to read() */ - if (flags & MAP_SHARED) return STATUS_INVALID_PARAMETER; - break; - case ENOEXEC: - case ENODEV: /* filesystem doesn't support mmap(), fall back to read() */ - if (vprot & VPROT_WRITE) - { - ERR( "shared writable mmap not supported, broken filesystem?\n" ); - return STATUS_NOT_SUPPORTED; - } - break; - case EACCES: - case EPERM: /* noexec filesystem, fall back to read() */ - if (flags & MAP_SHARED) - { - if (prot & PROT_EXEC) ERR( "failed to set PROT_EXEC on file map, noexec filesystem?\n" ); - return STATUS_ACCESS_DENIED; - } - if (prot & PROT_EXEC) WARN( "failed to set PROT_EXEC on file map, noexec filesystem?\n" ); - break; - default: - ERR( "mmap error %s, range %p-%p, unix_prot %#x\n", - strerror(errno), (char *)view->base + start, (char *)view->base + start + size, prot ); - return STATUS_NO_MEMORY; - } - } - - /* Reserve the memory with an anonymous mmap */ - ptr = anon_mmap_fixed( (char *)view->base + start, size, PROT_READ | PROT_WRITE, 0 ); - if (ptr == MAP_FAILED) - { - ERR( "anon mmap error %s, range %p-%p\n", - strerror(errno), (char *)view->base + start, (char *)view->base + start + size ); - return STATUS_NO_MEMORY; - } - /* Now read in the file */ - pread( fd, ptr, size, offset ); - if (prot != (PROT_READ|PROT_WRITE)) mprotect( ptr, size, prot ); /* Set the right protection */ + * Wrapper for mmap() to map a file into a view, falling back to read if mmap + * fails. virtual_mutex must be held by caller. + */ +static NTSTATUS map_file_into_view(struct file_view *view, int fd, size_t start, + size_t size, off_t offset, + unsigned int vprot, BOOL removable) { + void *ptr; + int prot = + get_unix_prot(vprot | VPROT_COMMITTED /* make sure it is accessible */); + unsigned int flags = + MAP_FIXED | ((vprot & VPROT_WRITECOPY) ? MAP_PRIVATE : MAP_SHARED); + + assert(start < view->size); + assert(start + size <= view->size); + + if (force_exec_prot && (vprot & VPROT_READ)) { + TRACE("forcing exec permission on mapping %p-%p\n", + (char *)view->base + start, (char *)view->base + start + size - 1); + prot |= PROT_EXEC; + } + + /* only try mmap if media is not removable (or if we require write access) */ + if (!removable || (flags & MAP_SHARED)) { + if (mmap((char *)view->base + start, size, prot, flags, fd, offset) != + MAP_FAILED) + goto done; + + switch (errno) { + case EINVAL: /* file offset is not page-aligned, fall back to read() */ + if (flags & MAP_SHARED) + return STATUS_INVALID_PARAMETER; + break; + case ENOEXEC: + case ENODEV: /* filesystem doesn't support mmap(), fall back to read() */ + if (vprot & VPROT_WRITE) { + ERR("shared writable mmap not supported, broken filesystem?\n"); + return STATUS_NOT_SUPPORTED; + } + break; + case EACCES: + case EPERM: /* noexec filesystem, fall back to read() */ + if (prot & PROT_EXEC) { + if (flags & MAP_SHARED) + WARN("failed to set PROT_EXEC on shared file map, noexec filesystem? " + "falling back to read\n"); + else + WARN("failed to set PROT_EXEC on file map, noexec filesystem?\n"); + } else if (flags & MAP_SHARED) + return STATUS_ACCESS_DENIED; + break; + default: + ERR("mmap error %s, range %p-%p, unix_prot %#x\n", strerror(errno), + (char *)view->base + start, (char *)view->base + start + size, prot); + return STATUS_NO_MEMORY; + } + } + + /* Reserve the memory with an anonymous mmap */ + ptr = anon_mmap_fixed((char *)view->base + start, size, + PROT_READ | PROT_WRITE, 0); + if (ptr == MAP_FAILED) { + ERR("anon mmap error %s, range %p-%p\n", strerror(errno), + (char *)view->base + start, (char *)view->base + start + size); + return STATUS_NO_MEMORY; + } + /* Now read in the file */ + pread(fd, ptr, size, offset); + if (prot != (PROT_READ | PROT_WRITE)) + mprotect(ptr, size, prot); /* Set the right protection */ done: - set_page_vprot( (char *)view->base + start, size, vprot ); - return STATUS_SUCCESS; + set_page_vprot((char *)view->base + start, size, vprot); + return STATUS_SUCCESS; } - /*********************************************************************** * get_committed_size * - * Get the size of the committed range with equal masked vprot bytes starting at base. - * Also return the protections for the first page. - */ -static SIZE_T get_committed_size( struct file_view *view, void *base, size_t max_size, BYTE *vprot, BYTE vprot_mask ) -{ - SIZE_T offset, size; - - base = ROUND_ADDR( base, page_mask ); - offset = (char *)base - (char *)view->base; - - if (view->protect & SEC_RESERVE) - { - size = 0; - - *vprot = get_page_vprot( base ); - - SERVER_START_REQ( get_mapping_committed_range ) - { - req->base = wine_server_client_ptr( view->base ); - req->offset = offset; - if (!wine_server_call( req )) - { - size = min( reply->size, max_size ); - if (reply->committed) - { - *vprot |= VPROT_COMMITTED; - set_page_vprot_bits( base, size, VPROT_COMMITTED, 0 ); - } - } + * Get the size of the committed range with equal masked vprot bytes starting at + * base. Also return the protections for the first page. + */ +static SIZE_T get_committed_size(struct file_view *view, void *base, + size_t max_size, BYTE *vprot, + BYTE vprot_mask) { + SIZE_T offset, size; + + base = ROUND_ADDR(base, page_mask); + offset = (char *)base - (char *)view->base; + + if (view->protect & SEC_RESERVE) { + size = 0; + + *vprot = get_page_vprot(base); + + SERVER_START_REQ(get_mapping_committed_range) { + req->base = wine_server_client_ptr(view->base); + req->offset = offset; + if (!wine_server_call(req)) { + size = min(reply->size, max_size); + if (reply->committed) { + *vprot |= VPROT_COMMITTED; + set_page_vprot_bits(base, size, VPROT_COMMITTED, 0); } - SERVER_END_REQ; - - if (!size || !(vprot_mask & ~VPROT_COMMITTED)) return size; + } } - else size = min( view->size - offset, max_size ); + SERVER_END_REQ; - return get_vprot_range_size( base, size, vprot_mask, vprot ); -} + if (!size || !(vprot_mask & ~VPROT_COMMITTED)) + return size; + } else + size = min(view->size - offset, max_size); + return get_vprot_range_size(base, size, vprot_mask, vprot); +} /*********************************************************************** * decommit_pages @@ -2212,257 +2215,251 @@ static SIZE_T get_committed_size( struct file_view *view, void *base, size_t max * Decommit some pages of a given view. * virtual_mutex must be held by caller. */ -static NTSTATUS decommit_pages( struct file_view *view, size_t start, size_t size ) -{ - if (!size) size = view->size; - if (anon_mmap_fixed( (char *)view->base + start, size, PROT_NONE, 0 ) != MAP_FAILED) - { - set_page_vprot_bits( (char *)view->base + start, size, 0, VPROT_COMMITTED ); - return STATUS_SUCCESS; - } - return STATUS_NO_MEMORY; +static NTSTATUS decommit_pages(struct file_view *view, size_t start, + size_t size) { + if (!size) + size = view->size; + if (anon_mmap_fixed((char *)view->base + start, size, PROT_NONE, 0) != + MAP_FAILED) { + set_page_vprot_bits((char *)view->base + start, size, 0, VPROT_COMMITTED); + return STATUS_SUCCESS; + } + return STATUS_NO_MEMORY; } - /*********************************************************************** * remove_pages_from_view * * Remove some pages of a given view. * virtual_mutex must be held by caller. */ -static NTSTATUS remove_pages_from_view( struct file_view *view, char *base, size_t size ) -{ - assert( size < view->size ); +static NTSTATUS remove_pages_from_view(struct file_view *view, char *base, + size_t size) { + assert(size < view->size); - if (view->base != base && base + size != (char *)view->base + view->size) - { - struct file_view *new_view = alloc_view(); + if (view->base != base && base + size != (char *)view->base + view->size) { + struct file_view *new_view = alloc_view(); - if (!new_view) - { - ERR( "out of memory for %p-%p\n", base, base + size ); - return STATUS_NO_MEMORY; - } - new_view->base = base + size; - new_view->size = (char *)view->base + view->size - (char *)new_view->base; - new_view->protect = view->protect; + if (!new_view) { + ERR("out of memory for %p-%p\n", base, base + size); + return STATUS_NO_MEMORY; + } + new_view->base = base + size; + new_view->size = (char *)view->base + view->size - (char *)new_view->base; + new_view->protect = view->protect; - unregister_view( view ); - view->size = base - (char *)view->base; - register_view( view ); - register_view( new_view ); + unregister_view(view); + view->size = base - (char *)view->base; + register_view(view); + register_view(new_view); - VIRTUAL_DEBUG_DUMP_VIEW( view ); - VIRTUAL_DEBUG_DUMP_VIEW( new_view ); - } - else - { - unregister_view( view ); - if (view->base == base) - { - view->base = base + size; - view->size -= size; - } - else view->size = base - (char *)view->base; + VIRTUAL_DEBUG_DUMP_VIEW(view); + VIRTUAL_DEBUG_DUMP_VIEW(new_view); + } else { + unregister_view(view); + if (view->base == base) { + view->base = base + size; + view->size -= size; + } else + view->size = base - (char *)view->base; - register_view( view ); - VIRTUAL_DEBUG_DUMP_VIEW( view ); - } - return STATUS_SUCCESS; + register_view(view); + VIRTUAL_DEBUG_DUMP_VIEW(view); + } + return STATUS_SUCCESS; } - /*********************************************************************** * free_pages_preserve_placeholder * * Turn pages of a given view into a placeholder. * virtual_mutex must be held by caller. */ -static NTSTATUS free_pages_preserve_placeholder( struct file_view *view, char *base, size_t size ) -{ - NTSTATUS status; +static NTSTATUS free_pages_preserve_placeholder(struct file_view *view, + char *base, size_t size) { + NTSTATUS status; - if (!size) return STATUS_INVALID_PARAMETER_3; - if (!(view->protect & VPROT_PLACEHOLDER)) return STATUS_CONFLICTING_ADDRESSES; - if (view->protect & VPROT_FREE_PLACEHOLDER && size == view->size) return STATUS_CONFLICTING_ADDRESSES; + if (!size) + return STATUS_INVALID_PARAMETER_3; + if (!(view->protect & VPROT_PLACEHOLDER)) + return STATUS_CONFLICTING_ADDRESSES; + if (view->protect & VPROT_FREE_PLACEHOLDER && size == view->size) + return STATUS_CONFLICTING_ADDRESSES; - if (size < view->size) - { - status = remove_pages_from_view( view, base, size ); - if (status) return status; + if (size < view->size) { + status = remove_pages_from_view(view, base, size); + if (status) + return status; - status = create_view( &view, base, size, VPROT_PLACEHOLDER | VPROT_FREE_PLACEHOLDER ); - if (status) return status; - } + status = create_view(&view, base, size, + VPROT_PLACEHOLDER | VPROT_FREE_PLACEHOLDER); + if (status) + return status; + } - view->protect = VPROT_PLACEHOLDER | VPROT_FREE_PLACEHOLDER; - set_page_vprot( view->base, view->size, 0 ); - anon_mmap_fixed( view->base, view->size, PROT_NONE, 0 ); - return STATUS_SUCCESS; + view->protect = VPROT_PLACEHOLDER | VPROT_FREE_PLACEHOLDER; + set_page_vprot(view->base, view->size, 0); + anon_mmap_fixed(view->base, view->size, PROT_NONE, 0); + return STATUS_SUCCESS; } - /*********************************************************************** * free_pages * * Free some pages of a given view. * virtual_mutex must be held by caller. */ -static NTSTATUS free_pages( struct file_view *view, char *base, size_t size ) -{ - NTSTATUS status; +static NTSTATUS free_pages(struct file_view *view, char *base, size_t size) { + NTSTATUS status; - if (size == view->size) - { - assert( base == view->base ); - delete_view( view ); - return STATUS_SUCCESS; - } + if (size == view->size) { + assert(base == view->base); + delete_view(view); + return STATUS_SUCCESS; + } - status = remove_pages_from_view( view, base, size ); - if (!status) - { - set_page_vprot( base, size, 0 ); - if (view->protect & VPROT_ARM64EC) clear_arm64ec_range( base, size ); - unmap_area( base, size ); - } - return status; + status = remove_pages_from_view(view, base, size); + if (!status) { + set_page_vprot(base, size, 0); + if (view->protect & VPROT_ARM64EC) + clear_arm64ec_range(base, size); + unmap_area(base, size); + } + return status; } - /*********************************************************************** * coalesce_placeholders * * Coalesce placeholder views. * virtual_mutex must be held by caller. */ -static NTSTATUS coalesce_placeholders( struct file_view *view, char *base, size_t size ) -{ - struct rb_entry *next; - struct file_view *curr_view, *next_view; - unsigned int i, view_count = 0; - size_t views_size = 0; +static NTSTATUS coalesce_placeholders(struct file_view *view, char *base, + size_t size) { + struct rb_entry *next; + struct file_view *curr_view, *next_view; + unsigned int i, view_count = 0; + size_t views_size = 0; - if (!size) return STATUS_INVALID_PARAMETER_3; - if (base != view->base) return STATUS_CONFLICTING_ADDRESSES; + if (!size) + return STATUS_INVALID_PARAMETER_3; + if (base != view->base) + return STATUS_CONFLICTING_ADDRESSES; - curr_view = view; - while (curr_view->protect & VPROT_FREE_PLACEHOLDER) - { - ++view_count; - views_size += curr_view->size; - if (views_size >= size) break; - if (!(next = rb_next( &curr_view->entry ))) break; - next_view = RB_ENTRY_VALUE( next, struct file_view, entry ); - if ((char *)curr_view->base + curr_view->size != next_view->base) break; - curr_view = next_view; - } + curr_view = view; + while (curr_view->protect & VPROT_FREE_PLACEHOLDER) { + ++view_count; + views_size += curr_view->size; + if (views_size >= size) + break; + if (!(next = rb_next(&curr_view->entry))) + break; + next_view = RB_ENTRY_VALUE(next, struct file_view, entry); + if ((char *)curr_view->base + curr_view->size != next_view->base) + break; + curr_view = next_view; + } - if (view_count < 2 || size != views_size) return STATUS_CONFLICTING_ADDRESSES; + if (view_count < 2 || size != views_size) + return STATUS_CONFLICTING_ADDRESSES; - for (i = 1; i < view_count; ++i) - { - curr_view = RB_ENTRY_VALUE( rb_next( &view->entry ), struct file_view, entry ); - unregister_view( curr_view ); - free_view( curr_view ); - } + for (i = 1; i < view_count; ++i) { + curr_view = RB_ENTRY_VALUE(rb_next(&view->entry), struct file_view, entry); + unregister_view(curr_view); + free_view(curr_view); + } - unregister_view( view ); - view->size = views_size; - register_view( view ); + unregister_view(view); + view->size = views_size; + register_view(view); - VIRTUAL_DEBUG_DUMP_VIEW( view ); + VIRTUAL_DEBUG_DUMP_VIEW(view); - return STATUS_SUCCESS; + return STATUS_SUCCESS; } - /*********************************************************************** * allocate_dos_memory * * Allocate the DOS memory range. */ -static NTSTATUS allocate_dos_memory( struct file_view **view, unsigned int vprot ) -{ - size_t size; - void *addr = NULL; - void * const low_64k = (void *)0x10000; - const size_t dosmem_size = 0x110000; - int unix_prot = get_unix_prot( vprot ); +static NTSTATUS allocate_dos_memory(struct file_view **view, + unsigned int vprot) { + size_t size; + void *addr = NULL; + void *const low_64k = (void *)0x10000; + const size_t dosmem_size = 0x110000; + int unix_prot = get_unix_prot(vprot); - /* check for existing view */ + /* check for existing view */ - if (find_view_range( 0, dosmem_size )) return STATUS_CONFLICTING_ADDRESSES; + if (find_view_range(0, dosmem_size)) + return STATUS_CONFLICTING_ADDRESSES; - /* check without the first 64K */ + /* check without the first 64K */ - if (mmap_is_in_reserved_area( low_64k, dosmem_size - 0x10000 ) != 1) - { - addr = anon_mmap_tryfixed( low_64k, dosmem_size - 0x10000, unix_prot, 0 ); - if (addr == MAP_FAILED) return map_view( view, NULL, dosmem_size, 0, vprot, 0, 0, 0 ); - } + if (mmap_is_in_reserved_area(low_64k, dosmem_size - 0x10000) != 1) { + addr = anon_mmap_tryfixed(low_64k, dosmem_size - 0x10000, unix_prot, 0); + if (addr == MAP_FAILED) + return map_view(view, NULL, dosmem_size, 0, vprot, 0, 0, 0); + } - /* now try to allocate the low 64K too */ + /* now try to allocate the low 64K too */ - if (mmap_is_in_reserved_area( NULL, 0x10000 ) != 1) - { - addr = anon_mmap_tryfixed( (void *)page_size, 0x10000 - page_size, unix_prot, 0 ); - if (addr != MAP_FAILED) - { - if (!anon_mmap_fixed( NULL, page_size, unix_prot, 0 )) - { - addr = NULL; - TRACE( "successfully mapped low 64K range\n" ); - } - else TRACE( "failed to map page 0\n" ); - } - else - { - addr = low_64k; - TRACE( "failed to map low 64K range\n" ); - } + if (mmap_is_in_reserved_area(NULL, 0x10000) != 1) { + addr = anon_mmap_tryfixed((void *)page_size, 0x10000 - page_size, unix_prot, + 0); + if (addr != MAP_FAILED) { + if (!anon_mmap_fixed(NULL, page_size, unix_prot, 0)) { + addr = NULL; + TRACE("successfully mapped low 64K range\n"); + } else + TRACE("failed to map page 0\n"); + } else { + addr = low_64k; + TRACE("failed to map low 64K range\n"); } + } - /* now reserve the whole range */ + /* now reserve the whole range */ - size = (char *)dosmem_size - (char *)addr; - anon_mmap_fixed( addr, size, unix_prot, 0 ); - return create_view( view, addr, size, vprot ); + size = (char *)dosmem_size - (char *)addr; + anon_mmap_fixed(addr, size, unix_prot, 0); + return create_view(view, addr, size, vprot); } - /*********************************************************************** * map_pe_header * * Map the header of a PE file into memory. */ -static NTSTATUS map_pe_header( void *ptr, size_t size, int fd, BOOL *removable ) -{ - if (!size) return STATUS_INVALID_IMAGE_FORMAT; - - if (!*removable) - { - if (mmap( ptr, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, fd, 0 ) != MAP_FAILED) - return STATUS_SUCCESS; - - switch (errno) - { - case EPERM: - case EACCES: - WARN( "noexec file system, falling back to read\n" ); - break; - case ENOEXEC: - case ENODEV: - WARN( "file system doesn't support mmap, falling back to read\n" ); - break; - default: - ERR( "mmap error %s, range %p-%p\n", strerror(errno), ptr, (char *)ptr + size ); - return STATUS_NO_MEMORY; - } - *removable = TRUE; +static NTSTATUS map_pe_header(void *ptr, size_t size, int fd, BOOL *removable) { + if (!size) + return STATUS_INVALID_IMAGE_FORMAT; + + if (!*removable) { + if (mmap(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, fd, 0) != MAP_FAILED) + return STATUS_SUCCESS; + + switch (errno) { + case EPERM: + case EACCES: + WARN("noexec file system, falling back to read\n"); + break; + case ENOEXEC: + case ENODEV: + WARN("file system doesn't support mmap, falling back to read\n"); + break; + default: + ERR("mmap error %s, range %p-%p\n", strerror(errno), ptr, + (char *)ptr + size); + return STATUS_NO_MEMORY; } - pread( fd, ptr, size, 0 ); - return STATUS_SUCCESS; /* page protections will be updated later */ + *removable = TRUE; + } + pread(fd, ptr, size, 0); + return STATUS_SUCCESS; /* page protections will be updated later */ } #ifdef _WIN64 @@ -2470,27 +2467,25 @@ static NTSTATUS map_pe_header( void *ptr, size_t size, int fd, BOOL *removable ) /*********************************************************************** * get_host_addr_space_limit */ -static void *get_host_addr_space_limit(void) -{ - unsigned int flags = MAP_PRIVATE | MAP_ANON; - UINT_PTR addr = (UINT_PTR)1 << 63; +static void *get_host_addr_space_limit(void) { + unsigned int flags = MAP_PRIVATE | MAP_ANON; + UINT_PTR addr = (UINT_PTR)1 << 63; #ifdef MAP_FIXED_NOREPLACE - flags |= MAP_FIXED_NOREPLACE; + flags |= MAP_FIXED_NOREPLACE; #endif - while (addr >> 32) - { - void *ret = mmap( (void *)addr, page_size, PROT_NONE, flags, -1, 0 ); - if (ret != MAP_FAILED) - { - munmap( ret, page_size ); - if (ret >= (void *)addr) break; - } - else if (errno == EEXIST) break; - addr >>= 1; - } - return (void *)((addr << 1) - (granularity_mask + 1)); + while (addr >> 32) { + void *ret = mmap((void *)addr, page_size, PROT_NONE, flags, -1, 0); + if (ret != MAP_FAILED) { + munmap(ret, page_size); + if (ret >= (void *)addr) + break; + } else if (errno == EEXIST) + break; + addr >>= 1; + } + return (void *)((addr << 1) - (granularity_mask + 1)); } #endif /* _WIN64 */ @@ -2500,1854 +2495,1884 @@ static void *get_host_addr_space_limit(void) /*********************************************************************** * alloc_arm64ec_map */ -static void alloc_arm64ec_map(void) -{ - unsigned int status; - SIZE_T size = ((ULONG_PTR)address_space_limit + page_size) >> (page_shift + 3); /* one bit per page */ +static void alloc_arm64ec_map(void) { + unsigned int status; + SIZE_T size = ((ULONG_PTR)address_space_limit + page_size) >> + (page_shift + 3); /* one bit per page */ - size = ROUND_SIZE( 0, size ); - status = map_view( &arm64ec_view, NULL, size, MEM_TOP_DOWN, VPROT_READ | VPROT_COMMITTED, 0, 0, granularity_mask ); - if (status) - { - ERR( "failed to allocate ARM64EC map: %08x\n", status ); - exit(1); - } - peb->EcCodeBitMap = arm64ec_view->base; + size = ROUND_SIZE(0, size); + status = map_view(&arm64ec_view, NULL, size, MEM_TOP_DOWN, + VPROT_READ | VPROT_COMMITTED, 0, 0, granularity_mask); + if (status) { + ERR("failed to allocate ARM64EC map: %08x\n", status); + exit(1); + } + peb->EcCodeBitMap = arm64ec_view->base; } - /*********************************************************************** * update_arm64ec_ranges */ -static void update_arm64ec_ranges( struct file_view *view, IMAGE_NT_HEADERS *nt, - const IMAGE_DATA_DIRECTORY *dir, UINT *entry_point ) -{ - const IMAGE_ARM64EC_METADATA *metadata; - const IMAGE_CHPE_RANGE_ENTRY *map; - char *base = view->base; - const IMAGE_LOAD_CONFIG_DIRECTORY *cfg = (void *)(base + dir->VirtualAddress); - ULONG i, size = min( dir->Size, cfg->Size ); - - if (size <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, CHPEMetadataPointer )) return; - if (!cfg->CHPEMetadataPointer) return; - if (!arm64ec_view) alloc_arm64ec_map(); - commit_arm64ec_map( view ); - metadata = (void *)(base + (cfg->CHPEMetadataPointer - nt->OptionalHeader.ImageBase)); - *entry_point = redirect_arm64ec_rva( base, nt->OptionalHeader.AddressOfEntryPoint, metadata ); - if (!metadata->CodeMap) return; - map = (void *)(base + metadata->CodeMap); - - for (i = 0; i < metadata->CodeMapCount; i++) - { - if ((map[i].StartOffset & 0x3) != 1 /* arm64ec */) continue; - set_arm64ec_range( base + (map[i].StartOffset & ~3), map[i].Length ); - } +static void update_arm64ec_ranges(struct file_view *view, IMAGE_NT_HEADERS *nt, + const IMAGE_DATA_DIRECTORY *dir, + UINT *entry_point) { + const IMAGE_ARM64EC_METADATA *metadata; + const IMAGE_CHPE_RANGE_ENTRY *map; + char *base = view->base; + const IMAGE_LOAD_CONFIG_DIRECTORY *cfg = (void *)(base + dir->VirtualAddress); + ULONG i, size = min(dir->Size, cfg->Size); + + if (size <= offsetof(IMAGE_LOAD_CONFIG_DIRECTORY, CHPEMetadataPointer)) + return; + if (!cfg->CHPEMetadataPointer) + return; + if (!arm64ec_view) + alloc_arm64ec_map(); + commit_arm64ec_map(view); + metadata = (void *)(base + (cfg->CHPEMetadataPointer - + nt->OptionalHeader.ImageBase)); + *entry_point = redirect_arm64ec_rva( + base, nt->OptionalHeader.AddressOfEntryPoint, metadata); + if (!metadata->CodeMap) + return; + map = (void *)(base + metadata->CodeMap); + + for (i = 0; i < metadata->CodeMapCount; i++) { + if ((map[i].StartOffset & 0x3) != 1 /* arm64ec */) + continue; + set_arm64ec_range(base + (map[i].StartOffset & ~3), map[i].Length); + } } - /*********************************************************************** * apply_arm64x_relocations */ -static void apply_arm64x_relocations( char *base, const IMAGE_BASE_RELOCATION *reloc, size_t size ) -{ - const IMAGE_BASE_RELOCATION *reloc_end = (const IMAGE_BASE_RELOCATION *)((const char *)reloc + size); - - while (reloc < reloc_end - 1 && reloc->SizeOfBlock) - { - const USHORT *rel = (const USHORT *)(reloc + 1); - const USHORT *rel_end = (const USHORT *)reloc + reloc->SizeOfBlock / sizeof(USHORT); - char *page = base + reloc->VirtualAddress; - - while (rel < rel_end && *rel) - { - USHORT offset = *rel & 0xfff; - USHORT type = (*rel >> 12) & 3; - USHORT arg = *rel >> 14; - int val; - rel++; - switch (type) - { - case IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL: - memset( page + offset, 0, 1 << arg ); - break; - case IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE: - memcpy( page + offset, rel, 1 << arg ); - rel += (1 << arg) / sizeof(USHORT); - break; - case IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA: - val = (unsigned int)*rel++ * ((arg & 2) ? 8 : 4); - if (arg & 1) val = -val; - *(int *)(page + offset) += val; - break; - } - } - reloc = (const IMAGE_BASE_RELOCATION *)rel_end; +static void apply_arm64x_relocations(char *base, + const IMAGE_BASE_RELOCATION *reloc, + size_t size) { + const IMAGE_BASE_RELOCATION *reloc_end = + (const IMAGE_BASE_RELOCATION *)((const char *)reloc + size); + + while (reloc < reloc_end - 1 && reloc->SizeOfBlock) { + const USHORT *rel = (const USHORT *)(reloc + 1); + const USHORT *rel_end = + (const USHORT *)reloc + reloc->SizeOfBlock / sizeof(USHORT); + char *page = base + reloc->VirtualAddress; + + while (rel < rel_end && *rel) { + USHORT offset = *rel & 0xfff; + USHORT type = (*rel >> 12) & 3; + USHORT arg = *rel >> 14; + int val; + rel++; + switch (type) { + case IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL: + memset(page + offset, 0, 1 << arg); + break; + case IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE: + memcpy(page + offset, rel, 1 << arg); + rel += (1 << arg) / sizeof(USHORT); + break; + case IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA: + val = (unsigned int)*rel++ * ((arg & 2) ? 8 : 4); + if (arg & 1) + val = -val; + *(int *)(page + offset) += val; + break; + } } + reloc = (const IMAGE_BASE_RELOCATION *)rel_end; + } } - /*********************************************************************** * update_arm64x_mapping */ -static void update_arm64x_mapping( struct file_view *view, IMAGE_NT_HEADERS *nt, - const IMAGE_DATA_DIRECTORY *dir, IMAGE_SECTION_HEADER *sections ) -{ - const IMAGE_DYNAMIC_RELOCATION_TABLE *table; - const char *ptr, *end; - char *base = view->base; - const IMAGE_LOAD_CONFIG_DIRECTORY *cfg = (void *)(base + dir->VirtualAddress); - ULONG sec, offset, size = min( dir->Size, cfg->Size ); - - if (size <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, DynamicValueRelocTableSection )) return; - offset = cfg->DynamicValueRelocTableOffset; - sec = cfg->DynamicValueRelocTableSection; - if (!sec || sec > nt->FileHeader.NumberOfSections) return; - if (offset >= sections[sec - 1].Misc.VirtualSize) return; - table = (const IMAGE_DYNAMIC_RELOCATION_TABLE *)(base + sections[sec - 1].VirtualAddress + offset); - ptr = (const char *)(table + 1); - end = ptr + table->Size; - switch (table->Version) - { - case 1: - while (ptr < end) - { - const IMAGE_DYNAMIC_RELOCATION64 *dyn = (const IMAGE_DYNAMIC_RELOCATION64 *)ptr; - if (dyn->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X) - { - apply_arm64x_relocations( base, (const IMAGE_BASE_RELOCATION *)(dyn + 1), - dyn->BaseRelocSize ); - break; - } - ptr += sizeof(*dyn) + dyn->BaseRelocSize; - } +static void update_arm64x_mapping(struct file_view *view, IMAGE_NT_HEADERS *nt, + const IMAGE_DATA_DIRECTORY *dir, + IMAGE_SECTION_HEADER *sections) { + const IMAGE_DYNAMIC_RELOCATION_TABLE *table; + const char *ptr, *end; + char *base = view->base; + const IMAGE_LOAD_CONFIG_DIRECTORY *cfg = (void *)(base + dir->VirtualAddress); + ULONG sec, offset, size = min(dir->Size, cfg->Size); + + if (size <= + offsetof(IMAGE_LOAD_CONFIG_DIRECTORY, DynamicValueRelocTableSection)) + return; + offset = cfg->DynamicValueRelocTableOffset; + sec = cfg->DynamicValueRelocTableSection; + if (!sec || sec > nt->FileHeader.NumberOfSections) + return; + if (offset >= sections[sec - 1].Misc.VirtualSize) + return; + table = (const IMAGE_DYNAMIC_RELOCATION_TABLE + *)(base + sections[sec - 1].VirtualAddress + offset); + ptr = (const char *)(table + 1); + end = ptr + table->Size; + switch (table->Version) { + case 1: + while (ptr < end) { + const IMAGE_DYNAMIC_RELOCATION64 *dyn = + (const IMAGE_DYNAMIC_RELOCATION64 *)ptr; + if (dyn->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X) { + apply_arm64x_relocations(base, (const IMAGE_BASE_RELOCATION *)(dyn + 1), + dyn->BaseRelocSize); break; - case 2: - while (ptr < end) - { - const IMAGE_DYNAMIC_RELOCATION64_V2 *dyn = (const IMAGE_DYNAMIC_RELOCATION64_V2 *)ptr; - if (dyn->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X) - { - apply_arm64x_relocations( base, (const IMAGE_BASE_RELOCATION *)(dyn + 1), - dyn->FixupInfoSize ); - break; - } - ptr += dyn->HeaderSize + dyn->FixupInfoSize; - } - break; - default: - FIXME( "unsupported version %u\n", table->Version ); + } + ptr += sizeof(*dyn) + dyn->BaseRelocSize; + } + break; + case 2: + while (ptr < end) { + const IMAGE_DYNAMIC_RELOCATION64_V2 *dyn = + (const IMAGE_DYNAMIC_RELOCATION64_V2 *)ptr; + if (dyn->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X) { + apply_arm64x_relocations(base, (const IMAGE_BASE_RELOCATION *)(dyn + 1), + dyn->FixupInfoSize); break; + } + ptr += dyn->HeaderSize + dyn->FixupInfoSize; } + break; + default: + FIXME("unsupported version %u\n", table->Version); + break; + } } -#endif /* __aarch64__ */ +#endif /* __aarch64__ */ /*********************************************************************** * get_data_dir */ -static IMAGE_DATA_DIRECTORY *get_data_dir( IMAGE_NT_HEADERS *nt, SIZE_T total_size, ULONG dir ) -{ - IMAGE_DATA_DIRECTORY *data; - - switch (nt->OptionalHeader.Magic) - { - case IMAGE_NT_OPTIONAL_HDR64_MAGIC: - if (dir >= ((IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.NumberOfRvaAndSizes) return NULL; - data = &((IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.DataDirectory[dir]; - break; - case IMAGE_NT_OPTIONAL_HDR32_MAGIC: - if (dir >= ((IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.NumberOfRvaAndSizes) return NULL; - data = &((IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.DataDirectory[dir]; - break; - default: - return NULL; - } - if (!data->Size) return NULL; - if (!data->VirtualAddress) return NULL; - if (data->VirtualAddress >= total_size) return NULL; - if (data->Size > total_size - data->VirtualAddress) return NULL; - return data; +static IMAGE_DATA_DIRECTORY *get_data_dir(IMAGE_NT_HEADERS *nt, + SIZE_T total_size, ULONG dir) { + IMAGE_DATA_DIRECTORY *data; + + switch (nt->OptionalHeader.Magic) { + case IMAGE_NT_OPTIONAL_HDR64_MAGIC: + if (dir >= ((IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.NumberOfRvaAndSizes) + return NULL; + data = &((IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.DataDirectory[dir]; + break; + case IMAGE_NT_OPTIONAL_HDR32_MAGIC: + if (dir >= ((IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.NumberOfRvaAndSizes) + return NULL; + data = &((IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.DataDirectory[dir]; + break; + default: + return NULL; + } + if (!data->Size) + return NULL; + if (!data->VirtualAddress) + return NULL; + if (data->VirtualAddress >= total_size) + return NULL; + if (data->Size > total_size - data->VirtualAddress) + return NULL; + return data; } - /*********************************************************************** * process_relocation_block * * Reimplementation of LdrProcessRelocationBlock. */ -static IMAGE_BASE_RELOCATION *process_relocation_block( char *page, IMAGE_BASE_RELOCATION *rel, - INT_PTR delta ) -{ - USHORT *reloc = (USHORT *)(rel + 1); - unsigned int count; - - for (count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT); count; count--, reloc++) - { - USHORT offset = *reloc & 0xfff; - switch (*reloc >> 12) - { - case IMAGE_REL_BASED_ABSOLUTE: - break; - case IMAGE_REL_BASED_HIGH: - *(short *)(page + offset) += HIWORD(delta); - break; - case IMAGE_REL_BASED_LOW: - *(short *)(page + offset) += LOWORD(delta); - break; - case IMAGE_REL_BASED_HIGHLOW: - *(int *)(page + offset) += delta; - break; - case IMAGE_REL_BASED_DIR64: - *(INT64 *)(page + offset) += delta; - break; - case IMAGE_REL_BASED_THUMB_MOV32: - { - DWORD *inst = (DWORD *)(page + offset); - WORD lo = ((inst[0] << 1) & 0x0800) + ((inst[0] << 12) & 0xf000) + - ((inst[0] >> 20) & 0x0700) + ((inst[0] >> 16) & 0x00ff); - WORD hi = ((inst[1] << 1) & 0x0800) + ((inst[1] << 12) & 0xf000) + - ((inst[1] >> 20) & 0x0700) + ((inst[1] >> 16) & 0x00ff); - DWORD imm = MAKELONG( lo, hi ) + delta; - - lo = LOWORD( imm ); - hi = HIWORD( imm ); - inst[0] = (inst[0] & 0x8f00fbf0) + ((lo >> 1) & 0x0400) + ((lo >> 12) & 0x000f) + - ((lo << 20) & 0x70000000) + ((lo << 16) & 0xff0000); - inst[1] = (inst[1] & 0x8f00fbf0) + ((hi >> 1) & 0x0400) + ((hi >> 12) & 0x000f) + - ((hi << 20) & 0x70000000) + ((hi << 16) & 0xff0000); - break; - } - default: - FIXME( "Unknown/unsupported relocation %x\n", *reloc ); - return NULL; - } +static IMAGE_BASE_RELOCATION * +process_relocation_block(char *page, IMAGE_BASE_RELOCATION *rel, + INT_PTR delta) { + USHORT *reloc = (USHORT *)(rel + 1); + unsigned int count; + + for (count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT); count; + count--, reloc++) { + USHORT offset = *reloc & 0xfff; + switch (*reloc >> 12) { + case IMAGE_REL_BASED_ABSOLUTE: + break; + case IMAGE_REL_BASED_HIGH: + *(short *)(page + offset) += HIWORD(delta); + break; + case IMAGE_REL_BASED_LOW: + *(short *)(page + offset) += LOWORD(delta); + break; + case IMAGE_REL_BASED_HIGHLOW: + *(int *)(page + offset) += delta; + break; + case IMAGE_REL_BASED_DIR64: + *(INT64 *)(page + offset) += delta; + break; + case IMAGE_REL_BASED_THUMB_MOV32: { + DWORD *inst = (DWORD *)(page + offset); + WORD lo = ((inst[0] << 1) & 0x0800) + ((inst[0] << 12) & 0xf000) + + ((inst[0] >> 20) & 0x0700) + ((inst[0] >> 16) & 0x00ff); + WORD hi = ((inst[1] << 1) & 0x0800) + ((inst[1] << 12) & 0xf000) + + ((inst[1] >> 20) & 0x0700) + ((inst[1] >> 16) & 0x00ff); + DWORD imm = MAKELONG(lo, hi) + delta; + + lo = LOWORD(imm); + hi = HIWORD(imm); + inst[0] = (inst[0] & 0x8f00fbf0) + ((lo >> 1) & 0x0400) + + ((lo >> 12) & 0x000f) + ((lo << 20) & 0x70000000) + + ((lo << 16) & 0xff0000); + inst[1] = (inst[1] & 0x8f00fbf0) + ((hi >> 1) & 0x0400) + + ((hi >> 12) & 0x000f) + ((hi << 20) & 0x70000000) + + ((hi << 16) & 0xff0000); + break; } - return (IMAGE_BASE_RELOCATION *)reloc; /* return address of next block */ + default: + FIXME("Unknown/unsupported relocation %x\n", *reloc); + return NULL; + } + } + return (IMAGE_BASE_RELOCATION *)reloc; /* return address of next block */ } - /*********************************************************************** * map_image_into_view * * Map an executable (PE format) image into an existing view. * virtual_mutex must be held by caller. */ -static NTSTATUS map_image_into_view( struct file_view *view, const WCHAR *filename, int fd, - struct pe_image_info *image_info, USHORT machine, - int shared_fd, BOOL removable ) -{ - IMAGE_DOS_HEADER *dos; - IMAGE_NT_HEADERS *nt; - IMAGE_SECTION_HEADER sections[96]; - IMAGE_SECTION_HEADER *sec; - IMAGE_DATA_DIRECTORY *imports, *dir; - NTSTATUS status = STATUS_CONFLICTING_ADDRESSES; - int i; - off_t pos; - struct stat st; - char *header_end; - char *ptr = view->base; - SIZE_T header_size, total_size = view->size; - INT_PTR delta; - - TRACE_(module)( "mapping PE file %s at %p-%p\n", debugstr_w(filename), ptr, ptr + total_size ); - - /* map the header */ - - fstat( fd, &st ); - header_size = min( image_info->header_size, st.st_size ); - if ((status = map_pe_header( view->base, header_size, fd, &removable ))) return status; - - status = STATUS_INVALID_IMAGE_FORMAT; /* generic error */ - dos = (IMAGE_DOS_HEADER *)ptr; - nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew); - header_end = ptr + ROUND_SIZE( 0, header_size ); - memset( ptr + header_size, 0, header_end - (ptr + header_size) ); - if ((char *)(nt + 1) > header_end) return status; - if (nt->FileHeader.NumberOfSections > ARRAY_SIZE( sections )) return status; - sec = IMAGE_FIRST_SECTION( nt ); - if ((char *)(sec + nt->FileHeader.NumberOfSections) > header_end) return status; - /* Some applications (e.g. the Steam version of Borderlands) map over the top of the section headers, - * copying the headers into local memory is necessary to properly load such applications. */ - memcpy(sections, sec, sizeof(*sections) * nt->FileHeader.NumberOfSections); - sec = sections; - imports = get_data_dir( nt, total_size, IMAGE_DIRECTORY_ENTRY_IMPORT ); - - /* check for non page-aligned binary */ - - if (image_info->image_flags & IMAGE_FLAGS_ImageMappedFlat) - { - /* unaligned sections, this happens for native subsystem binaries */ - /* in that case Windows simply maps in the whole file */ - - total_size = min( total_size, ROUND_SIZE( 0, st.st_size )); - if (map_file_into_view( view, fd, 0, total_size, 0, VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY, - removable ) != STATUS_SUCCESS) return status; - - /* check that all sections are loaded at the right offset */ - if (nt->OptionalHeader.FileAlignment != nt->OptionalHeader.SectionAlignment) return status; - for (i = 0; i < nt->FileHeader.NumberOfSections; i++) - { - if (sec[i].VirtualAddress != sec[i].PointerToRawData) - return status; /* Windows refuses to load in that case too */ - } +static NTSTATUS map_image_into_view(struct file_view *view, + const WCHAR *filename, int fd, + struct pe_image_info *image_info, + USHORT machine, int shared_fd, + BOOL removable) { + IMAGE_DOS_HEADER *dos; + IMAGE_NT_HEADERS *nt; + IMAGE_SECTION_HEADER sections[96]; + IMAGE_SECTION_HEADER *sec; + IMAGE_DATA_DIRECTORY *imports, *dir; + NTSTATUS status = STATUS_CONFLICTING_ADDRESSES; + int i; + off_t pos; + struct stat st; + char *header_end; + char *ptr = view->base; + SIZE_T header_size, total_size = view->size; + INT_PTR delta; + + TRACE_(module)("mapping PE file %s at %p-%p\n", debugstr_w(filename), ptr, + ptr + total_size); + + /* map the header */ + + fstat(fd, &st); + header_size = min(image_info->header_size, st.st_size); + if ((status = map_pe_header(view->base, header_size, fd, &removable))) + return status; + + status = STATUS_INVALID_IMAGE_FORMAT; /* generic error */ + dos = (IMAGE_DOS_HEADER *)ptr; + nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew); + header_end = ptr + ROUND_SIZE(0, header_size); + memset(ptr + header_size, 0, header_end - (ptr + header_size)); + if ((char *)(nt + 1) > header_end) + return status; + if (nt->FileHeader.NumberOfSections > ARRAY_SIZE(sections)) + return status; + sec = IMAGE_FIRST_SECTION(nt); + if ((char *)(sec + nt->FileHeader.NumberOfSections) > header_end) + return status; + /* Some applications (e.g. the Steam version of Borderlands) map over the top + * of the section headers, copying the headers into local memory is necessary + * to properly load such applications. */ + memcpy(sections, sec, sizeof(*sections) * nt->FileHeader.NumberOfSections); + sec = sections; + imports = get_data_dir(nt, total_size, IMAGE_DIRECTORY_ENTRY_IMPORT); - /* set the image protections */ - set_vprot( view, ptr, total_size, VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY | VPROT_EXEC ); + /* check for non page-aligned binary */ - /* no relocations are performed on non page-aligned binaries */ - return STATUS_SUCCESS; - } + if (image_info->image_flags & IMAGE_FLAGS_ImageMappedFlat) { + /* unaligned sections, this happens for native subsystem binaries */ + /* in that case Windows simply maps in the whole file */ + total_size = min(total_size, ROUND_SIZE(0, st.st_size)); + if (map_file_into_view(view, fd, 0, total_size, 0, + VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY, + removable) != STATUS_SUCCESS) + return status; - /* map all the sections */ + /* check that all sections are loaded at the right offset */ + if (nt->OptionalHeader.FileAlignment != nt->OptionalHeader.SectionAlignment) + return status; + for (i = 0; i < nt->FileHeader.NumberOfSections; i++) { + if (sec[i].VirtualAddress != sec[i].PointerToRawData) + return status; /* Windows refuses to load in that case too */ + } - for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) - { - static const SIZE_T sector_align = 0x1ff; - SIZE_T map_size, file_start, file_size, end; + /* set the image protections */ + set_vprot(view, ptr, total_size, + VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY | VPROT_EXEC); - if (!sec->Misc.VirtualSize) - map_size = ROUND_SIZE( 0, sec->SizeOfRawData ); - else - map_size = ROUND_SIZE( 0, sec->Misc.VirtualSize ); - - /* file positions are rounded to sector boundaries regardless of OptionalHeader.FileAlignment */ - file_start = sec->PointerToRawData & ~sector_align; - file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align) + sector_align) & ~sector_align; - if (file_size > map_size) file_size = map_size; - - /* a few sanity checks */ - end = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, map_size ); - if (sec->VirtualAddress > total_size || end > total_size || end < sec->VirtualAddress) - { - WARN_(module)( "%s section %.8s too large (%x+%lx/%lx)\n", - debugstr_w(filename), sec->Name, (int)sec->VirtualAddress, map_size, total_size ); - return status; - } + /* no relocations are performed on non page-aligned binaries */ + return STATUS_SUCCESS; + } - if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) && - (sec->Characteristics & IMAGE_SCN_MEM_WRITE)) - { - TRACE_(module)( "%s mapping shared section %.8s at %p off %x (%x) size %lx (%lx) flags %x\n", - debugstr_w(filename), sec->Name, ptr + sec->VirtualAddress, - (int)sec->PointerToRawData, (int)pos, file_size, map_size, - (int)sec->Characteristics ); - if (map_file_into_view( view, shared_fd, sec->VirtualAddress, map_size, pos, - VPROT_COMMITTED | VPROT_READ | VPROT_WRITE, FALSE ) != STATUS_SUCCESS) - { - ERR_(module)( "Could not map %s shared section %.8s\n", debugstr_w(filename), sec->Name ); - return status; - } - - /* check if the import directory falls inside this section */ - if (imports && imports->VirtualAddress >= sec->VirtualAddress && - imports->VirtualAddress < sec->VirtualAddress + map_size) - { - UINT_PTR base = imports->VirtualAddress & ~page_mask; - UINT_PTR end = base + ROUND_SIZE( imports->VirtualAddress, imports->Size ); - if (end > sec->VirtualAddress + map_size) end = sec->VirtualAddress + map_size; - if (end > base) - map_file_into_view( view, shared_fd, base, end - base, - pos + (base - sec->VirtualAddress), - VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY, FALSE ); - } - pos += map_size; - continue; - } + /* map all the sections */ - TRACE_(module)( "mapping %s section %.8s at %p off %x size %x virt %x flags %x\n", - debugstr_w(filename), sec->Name, ptr + sec->VirtualAddress, - (int)sec->PointerToRawData, (int)sec->SizeOfRawData, - (int)sec->Misc.VirtualSize, (int)sec->Characteristics ); - - if (!sec->PointerToRawData || !file_size) continue; - - /* Note: if the section is not aligned properly map_file_into_view will magically - * fall back to read(), so we don't need to check anything here. - */ - end = file_start + file_size; - if (sec->PointerToRawData >= st.st_size || - end > ((st.st_size + sector_align) & ~sector_align) || - end < file_start || - map_file_into_view( view, fd, sec->VirtualAddress, file_size, file_start, - VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY, - removable ) != STATUS_SUCCESS) - { - ERR_(module)( "Could not map %s section %.8s, file probably truncated\n", - debugstr_w(filename), sec->Name ); - return status; - } + for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) { + static const SIZE_T sector_align = 0x1ff; + SIZE_T map_size, file_start, file_size, end; - if (file_size & page_mask) - { - end = ROUND_SIZE( 0, file_size ); - if (end > map_size) end = map_size; - TRACE_(module)("clearing %p - %p\n", - ptr + sec->VirtualAddress + file_size, - ptr + sec->VirtualAddress + end ); - memset( ptr + sec->VirtualAddress + file_size, 0, end - file_size ); - } - } + if (!sec->Misc.VirtualSize) + map_size = ROUND_SIZE(0, sec->SizeOfRawData); + else + map_size = ROUND_SIZE(0, sec->Misc.VirtualSize); + + /* file positions are rounded to sector boundaries regardless of + * OptionalHeader.FileAlignment */ + file_start = sec->PointerToRawData & ~sector_align; + file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align) + + sector_align) & + ~sector_align; + if (file_size > map_size) + file_size = map_size; + + /* a few sanity checks */ + end = sec->VirtualAddress + ROUND_SIZE(sec->VirtualAddress, map_size); + if (sec->VirtualAddress > total_size || end > total_size || + end < sec->VirtualAddress) { + WARN_(module)("%s section %.8s too large (%x+%lx/%lx)\n", + debugstr_w(filename), sec->Name, (int)sec->VirtualAddress, + map_size, total_size); + return status; + } + + if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) && + (sec->Characteristics & IMAGE_SCN_MEM_WRITE)) { + TRACE_(module)("%s mapping shared section %.8s at %p off %x (%x) size " + "%lx (%lx) flags %x\n", + debugstr_w(filename), sec->Name, ptr + sec->VirtualAddress, + (int)sec->PointerToRawData, (int)pos, file_size, map_size, + (int)sec->Characteristics); + if (map_file_into_view(view, shared_fd, sec->VirtualAddress, map_size, + pos, VPROT_COMMITTED | VPROT_READ | VPROT_WRITE, + FALSE) != STATUS_SUCCESS) { + ERR_(module)("Could not map %s shared section %.8s\n", + debugstr_w(filename), sec->Name); + return status; + } + + /* check if the import directory falls inside this section */ + if (imports && imports->VirtualAddress >= sec->VirtualAddress && + imports->VirtualAddress < sec->VirtualAddress + map_size) { + UINT_PTR base = imports->VirtualAddress & ~page_mask; + UINT_PTR end = + base + ROUND_SIZE(imports->VirtualAddress, imports->Size); + if (end > sec->VirtualAddress + map_size) + end = sec->VirtualAddress + map_size; + if (end > base) + map_file_into_view(view, shared_fd, base, end - base, + pos + (base - sec->VirtualAddress), + VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY, + FALSE); + } + pos += map_size; + continue; + } + + TRACE_(module)( + "mapping %s section %.8s at %p off %x size %x virt %x flags %x\n", + debugstr_w(filename), sec->Name, ptr + sec->VirtualAddress, + (int)sec->PointerToRawData, (int)sec->SizeOfRawData, + (int)sec->Misc.VirtualSize, (int)sec->Characteristics); + + if (!sec->PointerToRawData || !file_size) + continue; + + /* Note: if the section is not aligned properly map_file_into_view will + * magically fall back to read(), so we don't need to check anything here. + */ + end = file_start + file_size; + if (sec->PointerToRawData >= st.st_size || + end > ((st.st_size + sector_align) & ~sector_align) || + end < file_start || + map_file_into_view(view, fd, sec->VirtualAddress, file_size, file_start, + VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY, + removable) != STATUS_SUCCESS) { + ERR_(module)("Could not map %s section %.8s, file probably truncated\n", + debugstr_w(filename), sec->Name); + return status; + } + + if (file_size & page_mask) { + end = ROUND_SIZE(0, file_size); + if (end > map_size) + end = map_size; + TRACE_(module)("clearing %p - %p\n", + ptr + sec->VirtualAddress + file_size, + ptr + sec->VirtualAddress + end); + memset(ptr + sec->VirtualAddress + file_size, 0, end - file_size); + } + } #ifdef __aarch64__ - if ((dir = get_data_dir( nt, total_size, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG ))) - { - if (image_info->machine == IMAGE_FILE_MACHINE_ARM64 && - (machine == IMAGE_FILE_MACHINE_AMD64 || - (!machine && main_image_info.Machine == IMAGE_FILE_MACHINE_AMD64))) - { - update_arm64x_mapping( view, nt, dir, sections ); - /* reload changed machine from NT header */ - image_info->machine = nt->FileHeader.Machine; - } - if (image_info->machine == IMAGE_FILE_MACHINE_AMD64) - update_arm64ec_ranges( view, nt, dir, &image_info->entry_point ); - } + if ((dir = get_data_dir(nt, total_size, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG))) { + if (image_info->machine == IMAGE_FILE_MACHINE_ARM64 && + (machine == IMAGE_FILE_MACHINE_AMD64 || + (!machine && main_image_info.Machine == IMAGE_FILE_MACHINE_AMD64))) { + update_arm64x_mapping(view, nt, dir, sections); + /* reload changed machine from NT header */ + image_info->machine = nt->FileHeader.Machine; + } + if (image_info->machine == IMAGE_FILE_MACHINE_AMD64) + update_arm64ec_ranges(view, nt, dir, &image_info->entry_point); + } #endif - if (machine && machine != nt->FileHeader.Machine) return STATUS_NOT_SUPPORTED; + if (machine && machine != nt->FileHeader.Machine) + return STATUS_NOT_SUPPORTED; - /* relocate to dynamic base */ + /* relocate to dynamic base */ - if (image_info->map_addr && (delta = image_info->map_addr - image_info->base)) - { - TRACE_(module)( "relocating %s dynamic base %lx -> %lx mapped at %p\n", debugstr_w(filename), - (ULONG_PTR)image_info->base, (ULONG_PTR)image_info->map_addr, ptr ); + if (image_info->map_addr && + (delta = image_info->map_addr - image_info->base)) { + TRACE_(module)("relocating %s dynamic base %lx -> %lx mapped at %p\n", + debugstr_w(filename), (ULONG_PTR)image_info->base, + (ULONG_PTR)image_info->map_addr, ptr); - if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) - ((IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.ImageBase = image_info->map_addr; - else - ((IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.ImageBase = image_info->map_addr; + if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + ((IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.ImageBase = + image_info->map_addr; + else + ((IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.ImageBase = + image_info->map_addr; - if ((dir = get_data_dir( nt, total_size, IMAGE_DIRECTORY_ENTRY_BASERELOC ))) - { - IMAGE_BASE_RELOCATION *rel = (IMAGE_BASE_RELOCATION *)(ptr + dir->VirtualAddress); - IMAGE_BASE_RELOCATION *end = (IMAGE_BASE_RELOCATION *)((char *)rel + dir->Size); + if ((dir = get_data_dir(nt, total_size, IMAGE_DIRECTORY_ENTRY_BASERELOC))) { + IMAGE_BASE_RELOCATION *rel = + (IMAGE_BASE_RELOCATION *)(ptr + dir->VirtualAddress); + IMAGE_BASE_RELOCATION *end = + (IMAGE_BASE_RELOCATION *)((char *)rel + dir->Size); - while (rel && rel < end - 1 && rel->SizeOfBlock && rel->VirtualAddress < total_size) - rel = process_relocation_block( ptr + rel->VirtualAddress, rel, delta ); - } + while (rel && rel < end - 1 && rel->SizeOfBlock && + rel->VirtualAddress < total_size) + rel = process_relocation_block(ptr + rel->VirtualAddress, rel, delta); } + } - /* set the image protections */ - - set_vprot( view, ptr, ROUND_SIZE( 0, header_size ), VPROT_COMMITTED | VPROT_READ ); + /* set the image protections */ - sec = sections; - for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) - { - SIZE_T size; - BYTE vprot = VPROT_COMMITTED; - - if (sec->Misc.VirtualSize) - size = ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize ); - else - size = ROUND_SIZE( sec->VirtualAddress, sec->SizeOfRawData ); + set_vprot(view, ptr, ROUND_SIZE(0, header_size), + VPROT_COMMITTED | VPROT_READ); - if (sec->Characteristics & IMAGE_SCN_MEM_READ) vprot |= VPROT_READ; - if (sec->Characteristics & IMAGE_SCN_MEM_WRITE) vprot |= VPROT_WRITECOPY; - if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) vprot |= VPROT_EXEC; + sec = sections; + for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) { + SIZE_T size; + BYTE vprot = VPROT_COMMITTED; - if (!set_vprot( view, ptr + sec->VirtualAddress, size, vprot ) && (vprot & VPROT_EXEC)) - ERR( "failed to set %08x protection on %s section %.8s, noexec filesystem?\n", - (int)sec->Characteristics, debugstr_w(filename), sec->Name ); - } + if (sec->Misc.VirtualSize) + size = ROUND_SIZE(sec->VirtualAddress, sec->Misc.VirtualSize); + else + size = ROUND_SIZE(sec->VirtualAddress, sec->SizeOfRawData); + + if (sec->Characteristics & IMAGE_SCN_MEM_READ) + vprot |= VPROT_READ; + if (sec->Characteristics & IMAGE_SCN_MEM_WRITE) + vprot |= VPROT_WRITECOPY; + if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) + vprot |= VPROT_EXEC; + + if (!set_vprot(view, ptr + sec->VirtualAddress, size, vprot) && + (vprot & VPROT_EXEC)) + ERR("failed to set %08x protection on %s section %.8s, noexec " + "filesystem?\n", + (int)sec->Characteristics, debugstr_w(filename), sec->Name); + } #ifdef VALGRIND_LOAD_PDB_DEBUGINFO - VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, ptr - (char *)wine_server_get_ptr( image_info->base )); + VALGRIND_LOAD_PDB_DEBUGINFO( + fd, ptr, total_size, ptr - (char *)wine_server_get_ptr(image_info->base)); #endif - return STATUS_SUCCESS; + return STATUS_SUCCESS; } - /*********************************************************************** * get_mapping_info */ -static unsigned int get_mapping_info( HANDLE handle, ACCESS_MASK access, unsigned int *sec_flags, - mem_size_t *full_size, HANDLE *shared_file, struct pe_image_info **info ) -{ - struct pe_image_info *image_info; - SIZE_T total, size = 1024; - unsigned int status; - - for (;;) - { - if (!(image_info = malloc( size ))) return STATUS_NO_MEMORY; - - SERVER_START_REQ( get_mapping_info ) - { - req->handle = wine_server_obj_handle( handle ); - req->access = access; - wine_server_set_reply( req, image_info, size ); - status = wine_server_call( req ); - *sec_flags = reply->flags; - *full_size = reply->size; - total = reply->total; - *shared_file = wine_server_ptr_handle( reply->shared_file ); - } - SERVER_END_REQ; - if (!status && total <= size - sizeof(WCHAR)) break; - free( image_info ); - if (status) return status; - if (*shared_file) NtClose( *shared_file ); - size = total + sizeof(WCHAR); +static unsigned int get_mapping_info(HANDLE handle, ACCESS_MASK access, + unsigned int *sec_flags, + mem_size_t *full_size, HANDLE *shared_file, + struct pe_image_info **info) { + struct pe_image_info *image_info; + SIZE_T total, size = 1024; + unsigned int status; + + for (;;) { + if (!(image_info = malloc(size))) + return STATUS_NO_MEMORY; + + SERVER_START_REQ(get_mapping_info) { + req->handle = wine_server_obj_handle(handle); + req->access = access; + wine_server_set_reply(req, image_info, size); + status = wine_server_call(req); + *sec_flags = reply->flags; + *full_size = reply->size; + total = reply->total; + *shared_file = wine_server_ptr_handle(reply->shared_file); } + SERVER_END_REQ; + if (!status && total <= size - sizeof(WCHAR)) + break; + free(image_info); + if (status) + return status; + if (*shared_file) + NtClose(*shared_file); + size = total + sizeof(WCHAR); + } - if (total) - { - WCHAR *filename = (WCHAR *)(image_info + 1); + if (total) { + WCHAR *filename = (WCHAR *)(image_info + 1); - assert( total >= sizeof(*image_info) ); - total -= sizeof(*image_info); - filename[total / sizeof(WCHAR)] = 0; - *info = image_info; - } - else free( image_info ); + assert(total >= sizeof(*image_info)); + total -= sizeof(*image_info); + filename[total / sizeof(WCHAR)] = 0; + *info = image_info; + } else + free(image_info); - return STATUS_SUCCESS; + return STATUS_SUCCESS; } - /*********************************************************************** * map_image_view * * Map a view for a PE image at an appropriate address. */ -static NTSTATUS map_image_view( struct file_view **view_ret, struct pe_image_info *image_info, SIZE_T size, - ULONG_PTR limit_low, ULONG_PTR limit_high, ULONG alloc_type ) -{ - unsigned int vprot = SEC_IMAGE | SEC_FILE | VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY; - void *base; - NTSTATUS status; - ULONG_PTR start, end; - BOOL top_down = (image_info->image_charact & IMAGE_FILE_DLL) && - (image_info->image_flags & IMAGE_FLAGS_ImageDynamicallyRelocated); - - limit_low = max( limit_low, (ULONG_PTR)address_space_start ); /* make sure the DOS area remains free */ - if (!limit_high) limit_high = (ULONG_PTR)user_space_limit; - - /* first try the specified base */ - - if (image_info->map_addr) - { - base = wine_server_get_ptr( image_info->map_addr ); - if ((ULONG_PTR)base != image_info->map_addr) base = NULL; - } - else - { - base = wine_server_get_ptr( image_info->base ); - if ((ULONG_PTR)base != image_info->base) base = NULL; - } - if (base) - { - status = map_view( view_ret, base, size, alloc_type, vprot, limit_low, limit_high, 0 ); - if (!status) return status; - } - - /* then some appropriate address range */ - - if (image_info->base >= limit_4g) - { - start = max( limit_low, limit_4g ); - end = limit_high; - } - else - { - start = limit_low; - end = min( limit_high, get_wow_user_space_limit() ); - } - if (start < end && (start != limit_low || end != limit_high)) - { - status = map_view( view_ret, NULL, size, top_down ? MEM_TOP_DOWN : 0, vprot, start, end, 0 ); - if (!status) return status; - } +static NTSTATUS map_image_view(struct file_view **view_ret, + struct pe_image_info *image_info, SIZE_T size, + ULONG_PTR limit_low, ULONG_PTR limit_high, + ULONG alloc_type) { + unsigned int vprot = SEC_IMAGE | SEC_FILE | VPROT_COMMITTED | VPROT_READ | + VPROT_EXEC | VPROT_WRITECOPY; + void *base; + NTSTATUS status; + ULONG_PTR start, end; + BOOL top_down = + (image_info->image_charact & IMAGE_FILE_DLL) && + (image_info->image_flags & IMAGE_FLAGS_ImageDynamicallyRelocated); + + limit_low = max( + limit_low, + (ULONG_PTR)address_space_start); /* make sure the DOS area remains free */ + if (!limit_high) + limit_high = (ULONG_PTR)user_space_limit; + + /* first try the specified base */ + + if (image_info->map_addr) { + base = wine_server_get_ptr(image_info->map_addr); + if ((ULONG_PTR)base != image_info->map_addr) + base = NULL; + } else { + base = wine_server_get_ptr(image_info->base); + if ((ULONG_PTR)base != image_info->base) + base = NULL; + } + if (base) { + status = map_view(view_ret, base, size, alloc_type, vprot, limit_low, + limit_high, 0); + if (!status) + return status; + } + + /* then some appropriate address range */ + + if (image_info->base >= limit_4g) { + start = max(limit_low, limit_4g); + end = limit_high; + } else { + start = limit_low; + end = min(limit_high, get_wow_user_space_limit()); + } + if (start < end && (start != limit_low || end != limit_high)) { + status = map_view(view_ret, NULL, size, top_down ? MEM_TOP_DOWN : 0, vprot, + start, end, 0); + if (!status) + return status; + } - /* then any suitable address */ + /* then any suitable address */ - return map_view( view_ret, NULL, size, top_down ? MEM_TOP_DOWN : 0, vprot, limit_low, limit_high, 0 ); + return map_view(view_ret, NULL, size, top_down ? MEM_TOP_DOWN : 0, vprot, + limit_low, limit_high, 0); } - /*********************************************************************** * virtual_map_image * * Map a PE image section into memory. */ -static NTSTATUS virtual_map_image( HANDLE mapping, void **addr_ptr, SIZE_T *size_ptr, HANDLE shared_file, - ULONG_PTR limit_low, ULONG_PTR limit_high, ULONG alloc_type, - USHORT machine, struct pe_image_info *image_info, - WCHAR *filename, BOOL is_builtin ) -{ - int unix_fd = -1, needs_close; - int shared_fd = -1, shared_needs_close = 0; - SIZE_T size = image_info->map_size; - struct file_view *view; - unsigned int status; - sigset_t sigset; - - if ((status = server_get_unix_fd( mapping, 0, &unix_fd, &needs_close, NULL, NULL ))) - return status; - - if (shared_file && ((status = server_get_unix_fd( shared_file, FILE_READ_DATA|FILE_WRITE_DATA, - &shared_fd, &shared_needs_close, NULL, NULL )))) - { - if (needs_close) close( unix_fd ); - return status; - } - - if (!image_info->map_addr && - (image_info->image_charact & IMAGE_FILE_DLL) && - (image_info->image_flags & IMAGE_FLAGS_ImageDynamicallyRelocated)) - { - SERVER_START_REQ( get_image_map_address ) - { - req->handle = wine_server_obj_handle( mapping ); - if (!wine_server_call( req )) image_info->map_addr = reply->addr; - } - SERVER_END_REQ; - } - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); +static NTSTATUS virtual_map_image(HANDLE mapping, void **addr_ptr, + SIZE_T *size_ptr, HANDLE shared_file, + ULONG_PTR limit_low, ULONG_PTR limit_high, + ULONG alloc_type, USHORT machine, + struct pe_image_info *image_info, + WCHAR *filename, BOOL is_builtin) { + int unix_fd = -1, needs_close; + int shared_fd = -1, shared_needs_close = 0; + SIZE_T size = image_info->map_size; + struct file_view *view; + unsigned int status; + sigset_t sigset; + + if ((status = + server_get_unix_fd(mapping, 0, &unix_fd, &needs_close, NULL, NULL))) + return status; - status = map_image_view( &view, image_info, size, limit_low, limit_high, alloc_type ); - if (status) goto done; + if (shared_file && ((status = server_get_unix_fd( + shared_file, FILE_READ_DATA | FILE_WRITE_DATA, + &shared_fd, &shared_needs_close, NULL, NULL)))) { + if (needs_close) + close(unix_fd); + return status; + } - status = map_image_into_view( view, filename, unix_fd, image_info, machine, shared_fd, needs_close ); - if (status == STATUS_SUCCESS) - { - SERVER_START_REQ( map_image_view ) - { - req->mapping = wine_server_obj_handle( mapping ); - req->base = wine_server_client_ptr( view->base ); - req->size = size; - req->entry = image_info->entry_point; - req->machine = image_info->machine; - status = wine_server_call( req ); - } - SERVER_END_REQ; + if (!image_info->map_addr && (image_info->image_charact & IMAGE_FILE_DLL) && + (image_info->image_flags & IMAGE_FLAGS_ImageDynamicallyRelocated)) { + SERVER_START_REQ(get_image_map_address) { + req->handle = wine_server_obj_handle(mapping); + if (!wine_server_call(req)) + image_info->map_addr = reply->addr; } - if (NT_SUCCESS(status)) - { - if (is_builtin) add_builtin_module( view->base, NULL ); - *addr_ptr = view->base; - *size_ptr = size; - VIRTUAL_DEBUG_DUMP_VIEW( view ); + SERVER_END_REQ; + } + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + + status = map_image_view(&view, image_info, size, limit_low, limit_high, + alloc_type); + if (status) + goto done; + + status = map_image_into_view(view, filename, unix_fd, image_info, machine, + shared_fd, needs_close); + if (status == STATUS_SUCCESS) { + SERVER_START_REQ(map_image_view) { + req->mapping = wine_server_obj_handle(mapping); + req->base = wine_server_client_ptr(view->base); + req->size = size; + req->entry = image_info->entry_point; + req->machine = image_info->machine; + status = wine_server_call(req); } - else delete_view( view ); + SERVER_END_REQ; + } + if (NT_SUCCESS(status)) { + if (is_builtin) + add_builtin_module(view->base, NULL); + *addr_ptr = view->base; + *size_ptr = size; + VIRTUAL_DEBUG_DUMP_VIEW(view); + } else + delete_view(view); done: - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - if (needs_close) close( unix_fd ); - if (shared_needs_close) close( shared_fd ); - return status; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + if (needs_close) + close(unix_fd); + if (shared_needs_close) + close(shared_fd); + return status; } - /*********************************************************************** * virtual_map_section * * Map a file section into memory. */ -static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_PTR limit_low, - ULONG_PTR limit_high, SIZE_T commit_size, - const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, - ULONG alloc_type, ULONG protect, USHORT machine ) -{ - unsigned int res; - mem_size_t full_size; - ACCESS_MASK access; - SIZE_T size; - struct pe_image_info *image_info = NULL; - WCHAR *filename; - void *base; - int unix_handle = -1, needs_close; - unsigned int vprot, sec_flags; - struct file_view *view; - HANDLE shared_file; - LARGE_INTEGER offset; - sigset_t sigset; - - switch(protect) - { - case PAGE_NOACCESS: - case PAGE_READONLY: - case PAGE_WRITECOPY: - access = SECTION_MAP_READ; - break; - case PAGE_READWRITE: - access = SECTION_MAP_WRITE; - break; - case PAGE_EXECUTE: - case PAGE_EXECUTE_READ: - case PAGE_EXECUTE_WRITECOPY: - access = SECTION_MAP_READ | SECTION_MAP_EXECUTE; - break; - case PAGE_EXECUTE_READWRITE: - access = SECTION_MAP_WRITE | SECTION_MAP_EXECUTE; - break; - default: - return STATUS_INVALID_PAGE_PROTECTION; - } - - res = get_mapping_info( handle, access, &sec_flags, &full_size, &shared_file, &image_info ); - if (res) return res; - - if (image_info) - { - SECTION_IMAGE_INFORMATION info; - ULONG64 prev = 0; +static unsigned int +virtual_map_section(HANDLE handle, PVOID *addr_ptr, ULONG_PTR limit_low, + ULONG_PTR limit_high, SIZE_T commit_size, + const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, + ULONG alloc_type, ULONG protect, USHORT machine) { + unsigned int res; + mem_size_t full_size; + ACCESS_MASK access; + SIZE_T size; + struct pe_image_info *image_info = NULL; + WCHAR *filename; + void *base; + int unix_handle = -1, needs_close; + unsigned int vprot, sec_flags; + struct file_view *view; + HANDLE shared_file; + LARGE_INTEGER offset; + sigset_t sigset; + + switch (protect) { + case PAGE_NOACCESS: + case PAGE_READONLY: + case PAGE_WRITECOPY: + access = SECTION_MAP_READ; + break; + case PAGE_READWRITE: + access = SECTION_MAP_WRITE; + break; + case PAGE_EXECUTE: + case PAGE_EXECUTE_READ: + case PAGE_EXECUTE_WRITECOPY: + access = SECTION_MAP_READ | SECTION_MAP_EXECUTE; + break; + case PAGE_EXECUTE_READWRITE: + access = SECTION_MAP_WRITE | SECTION_MAP_EXECUTE; + break; + default: + return STATUS_INVALID_PAGE_PROTECTION; + } + + res = get_mapping_info(handle, access, &sec_flags, &full_size, &shared_file, + &image_info); + if (res) + return res; - if (NtCurrentTeb64()) - { - prev = NtCurrentTeb64()->Tib.ArbitraryUserPointer; - NtCurrentTeb64()->Tib.ArbitraryUserPointer = PtrToUlong(NtCurrentTeb()->Tib.ArbitraryUserPointer); - } - filename = (WCHAR *)(image_info + 1); - /* check if we can replace that mapping with the builtin */ - res = load_builtin( image_info, filename, machine, &info, - addr_ptr, size_ptr, limit_low, limit_high ); - if (res == STATUS_IMAGE_ALREADY_LOADED) - res = virtual_map_image( handle, addr_ptr, size_ptr, shared_file, limit_low, limit_high, - alloc_type, machine, image_info, filename, FALSE ); - if (shared_file) NtClose( shared_file ); - free( image_info ); - if (NtCurrentTeb64()) NtCurrentTeb64()->Tib.ArbitraryUserPointer = prev; - return res; - } + if (image_info) { + SECTION_IMAGE_INFORMATION info; + ULONG64 prev = 0; - base = *addr_ptr; - offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0; - if (offset.QuadPart >= full_size) return STATUS_INVALID_PARAMETER; - if (*size_ptr) - { - size = *size_ptr; - if (size > full_size - offset.QuadPart) return STATUS_INVALID_VIEW_SIZE; - } - else - { - size = full_size - offset.QuadPart; - if (size != full_size - offset.QuadPart) /* truncated */ - { - WARN( "Files larger than 4Gb (%s) not supported on this platform\n", - wine_dbgstr_longlong(full_size) ); - return STATUS_INVALID_PARAMETER; - } + if (NtCurrentTeb64()) { + prev = NtCurrentTeb64()->Tib.ArbitraryUserPointer; + NtCurrentTeb64()->Tib.ArbitraryUserPointer = + PtrToUlong(NtCurrentTeb()->Tib.ArbitraryUserPointer); } - if (!(size = ROUND_SIZE( 0, size ))) return STATUS_INVALID_PARAMETER; /* wrap-around */ - - get_vprot_flags( protect, &vprot, FALSE ); - vprot |= sec_flags; - if (!(sec_flags & SEC_RESERVE)) vprot |= VPROT_COMMITTED; - - if ((res = server_get_unix_fd( handle, 0, &unix_handle, &needs_close, NULL, NULL ))) return res; - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); + filename = (WCHAR *)(image_info + 1); + /* check if we can replace that mapping with the builtin */ + res = load_builtin(image_info, filename, machine, &info, addr_ptr, size_ptr, + limit_low, limit_high); + if (res == STATUS_IMAGE_ALREADY_LOADED) + res = virtual_map_image(handle, addr_ptr, size_ptr, shared_file, + limit_low, limit_high, alloc_type, machine, + image_info, filename, FALSE); + if (shared_file) + NtClose(shared_file); + free(image_info); + if (NtCurrentTeb64()) + NtCurrentTeb64()->Tib.ArbitraryUserPointer = prev; + return res; + } - res = map_view( &view, base, size, alloc_type, vprot, limit_low, limit_high, 0 ); - if (res) goto done; + base = *addr_ptr; + offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0; + if (offset.QuadPart >= full_size) + return STATUS_INVALID_PARAMETER; + if (*size_ptr) { + size = *size_ptr; + if (size > full_size - offset.QuadPart) + return STATUS_INVALID_VIEW_SIZE; + } else { + size = full_size - offset.QuadPart; + if (size != full_size - offset.QuadPart) /* truncated */ + { + WARN("Files larger than 4Gb (%s) not supported on this platform\n", + wine_dbgstr_longlong(full_size)); + return STATUS_INVALID_PARAMETER; + } + } + if (!(size = ROUND_SIZE(0, size))) + return STATUS_INVALID_PARAMETER; /* wrap-around */ + + get_vprot_flags(protect, &vprot, FALSE); + vprot |= sec_flags; + if (!(sec_flags & SEC_RESERVE)) + vprot |= VPROT_COMMITTED; + + if ((res = server_get_unix_fd(handle, 0, &unix_handle, &needs_close, NULL, + NULL))) + return res; - TRACE( "handle=%p size=%lx offset=%s\n", handle, size, wine_dbgstr_longlong(offset.QuadPart) ); - res = map_file_into_view( view, unix_handle, 0, size, offset.QuadPart, vprot, needs_close ); - if (res == STATUS_SUCCESS) - { - SERVER_START_REQ( map_view ) - { - req->mapping = wine_server_obj_handle( handle ); - req->access = access; - req->base = wine_server_client_ptr( view->base ); - req->size = size; - req->start = offset.QuadPart; - res = wine_server_call( req ); - } - SERVER_END_REQ; + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + + res = + map_view(&view, base, size, alloc_type, vprot, limit_low, limit_high, 0); + if (res) + goto done; + + TRACE("handle=%p size=%lx offset=%s\n", handle, size, + wine_dbgstr_longlong(offset.QuadPart)); + res = map_file_into_view(view, unix_handle, 0, size, offset.QuadPart, vprot, + needs_close); + if (res == STATUS_SUCCESS) { + SERVER_START_REQ(map_view) { + req->mapping = wine_server_obj_handle(handle); + req->access = access; + req->base = wine_server_client_ptr(view->base); + req->size = size; + req->start = offset.QuadPart; + res = wine_server_call(req); } - else ERR( "mapping %p %lx %s failed\n", view->base, size, wine_dbgstr_longlong(offset.QuadPart) ); + SERVER_END_REQ; + } else + ERR("mapping %p %lx %s failed\n", view->base, size, + wine_dbgstr_longlong(offset.QuadPart)); - if (NT_SUCCESS(res)) - { - *addr_ptr = view->base; - *size_ptr = size; - VIRTUAL_DEBUG_DUMP_VIEW( view ); - } - else delete_view( view ); + if (NT_SUCCESS(res)) { + *addr_ptr = view->base; + *size_ptr = size; + VIRTUAL_DEBUG_DUMP_VIEW(view); + } else + delete_view(view); done: - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - if (needs_close) close( unix_handle ); - return res; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + if (needs_close) + close(unix_handle); + return res; } - /* allocate some space for the virtual heap, if possible from a reserved area */ -static void *alloc_virtual_heap( SIZE_T size ) -{ - struct reserved_area *area; - void *ret; - - LIST_FOR_EACH_ENTRY_REV( area, &reserved_areas, struct reserved_area, entry ) - { - void *base = area->base; - void *end = (char *)base + area->size; - - if (is_beyond_limit( base, area->size, address_space_limit )) - address_space_limit = host_addr_space_limit = end; - if (is_win64 && base < (void *)0x80000000) break; - if (preload_reserve_end >= end) - { - if (preload_reserve_start <= base) continue; /* no space in that area */ - if (preload_reserve_start < end) end = preload_reserve_start; - } - else if (preload_reserve_end > base) - { - if (preload_reserve_start <= base) base = preload_reserve_end; - else if ((char *)end - (char *)preload_reserve_end >= size) base = preload_reserve_end; - else end = preload_reserve_start; - } - if ((char *)end - (char *)base < size) continue; - ret = anon_mmap_fixed( (char *)end - size, size, PROT_READ | PROT_WRITE, 0 ); - if (ret == MAP_FAILED) continue; - mmap_remove_reserved_area( ret, size ); - return ret; - } - return anon_mmap_alloc( size, PROT_READ | PROT_WRITE ); +static void *alloc_virtual_heap(SIZE_T size) { + struct reserved_area *area; + void *ret; + + LIST_FOR_EACH_ENTRY_REV(area, &reserved_areas, struct reserved_area, entry) { + void *base = area->base; + void *end = (char *)base + area->size; + + if (is_beyond_limit(base, area->size, address_space_limit)) + address_space_limit = host_addr_space_limit = end; + if (is_win64 && base < (void *)0x80000000) + break; + if (preload_reserve_end >= end) { + if (preload_reserve_start <= base) + continue; /* no space in that area */ + if (preload_reserve_start < end) + end = preload_reserve_start; + } else if (preload_reserve_end > base) { + if (preload_reserve_start <= base) + base = preload_reserve_end; + else if ((char *)end - (char *)preload_reserve_end >= size) + base = preload_reserve_end; + else + end = preload_reserve_start; + } + if ((char *)end - (char *)base < size) + continue; + ret = anon_mmap_fixed((char *)end - size, size, PROT_READ | PROT_WRITE, 0); + if (ret == MAP_FAILED) + continue; + mmap_remove_reserved_area(ret, size); + return ret; + } + return anon_mmap_alloc(size, PROT_READ | PROT_WRITE); } /*********************************************************************** * virtual_init */ -void virtual_init(void) -{ - const struct preload_info **preload_info = dlsym( RTLD_DEFAULT, "wine_main_preload_info" ); - const char *preload; - size_t size; - int i; - pthread_mutexattr_t attr; +void virtual_init(void) { + const struct preload_info **preload_info = + dlsym(RTLD_DEFAULT, "wine_main_preload_info"); + const char *preload; + size_t size; + int i; + pthread_mutexattr_t attr; - pthread_mutexattr_init( &attr ); - pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); - pthread_mutex_init( &virtual_mutex, &attr ); - pthread_mutexattr_destroy( &attr ); + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&virtual_mutex, &attr); + pthread_mutexattr_destroy(&attr); #ifdef _WIN64 - host_addr_space_limit = get_host_addr_space_limit(); - TRACE( "host addr space limit: %p\n", host_addr_space_limit ); + host_addr_space_limit = get_host_addr_space_limit(); + TRACE("host addr space limit: %p\n", host_addr_space_limit); #else - host_addr_space_limit = address_space_limit; + host_addr_space_limit = address_space_limit; #endif - if (preload_info && *preload_info) - for (i = 0; (*preload_info)[i].size; i++) - mmap_add_reserved_area( (*preload_info)[i].addr, (*preload_info)[i].size ); + if (preload_info && *preload_info) + for (i = 0; (*preload_info)[i].size; i++) + mmap_add_reserved_area((*preload_info)[i].addr, (*preload_info)[i].size); - mmap_init( preload_info ? *preload_info : NULL ); + mmap_init(preload_info ? *preload_info : NULL); - if ((preload = getenv("WINEPRELOADRESERVE"))) - { - unsigned long start, end; - if (sscanf( preload, "%lx-%lx", &start, &end ) == 2) - { - preload_reserve_start = (void *)start; - preload_reserve_end = (void *)end; - /* some apps start inside the DOS area */ - if (preload_reserve_start) - address_space_start = min( address_space_start, preload_reserve_start ); - } + if ((preload = getenv("WINEPRELOADRESERVE"))) { + unsigned long start, end; + if (sscanf(preload, "%lx-%lx", &start, &end) == 2) { + preload_reserve_start = (void *)start; + preload_reserve_end = (void *)end; + /* some apps start inside the DOS area */ + if (preload_reserve_start) + address_space_start = min(address_space_start, preload_reserve_start); } + } - /* try to find space in a reserved area for the views and pages protection table */ + /* try to find space in a reserved area for the views and pages protection + * table */ #ifdef _WIN64 - pages_vprot_size = ((size_t)host_addr_space_limit >> page_shift >> pages_vprot_shift) + 1; - size = 2 * view_block_size + pages_vprot_size * sizeof(*pages_vprot); + pages_vprot_size = + ((size_t)host_addr_space_limit >> page_shift >> pages_vprot_shift) + 1; + size = 2 * view_block_size + pages_vprot_size * sizeof(*pages_vprot); #else - size = 2 * view_block_size + (1U << (32 - page_shift)); + size = 2 * view_block_size + (1U << (32 - page_shift)); #endif - view_block_start = alloc_virtual_heap( size ); - assert( view_block_start != MAP_FAILED ); - view_block_end = view_block_start + view_block_size / sizeof(*view_block_start); - free_ranges = (void *)((char *)view_block_start + view_block_size); - pages_vprot = (void *)((char *)view_block_start + 2 * view_block_size); - wine_rb_init( &views_tree, compare_view ); + view_block_start = alloc_virtual_heap(size); + assert(view_block_start != MAP_FAILED); + view_block_end = + view_block_start + view_block_size / sizeof(*view_block_start); + free_ranges = (void *)((char *)view_block_start + view_block_size); + pages_vprot = (void *)((char *)view_block_start + 2 * view_block_size); + wine_rb_init(&views_tree, compare_view); - free_ranges[0].base = (void *)0; - free_ranges[0].end = (void *)~0; - free_ranges_end = free_ranges + 1; + free_ranges[0].base = (void *)0; + free_ranges[0].end = (void *)~0; + free_ranges_end = free_ranges + 1; - /* make the DOS area accessible (except the low 64K) to hide bugs in broken apps like Excel 2003 */ - size = (char *)address_space_start - (char *)0x10000; - if (size && mmap_is_in_reserved_area( (void*)0x10000, size ) == 1) - anon_mmap_fixed( (void *)0x10000, size, PROT_READ | PROT_WRITE, 0 ); + /* make the DOS area accessible (except the low 64K) to hide bugs in broken + * apps like Excel 2003 */ + size = (char *)address_space_start - (char *)0x10000; + if (size && mmap_is_in_reserved_area((void *)0x10000, size) == 1) + anon_mmap_fixed((void *)0x10000, size, PROT_READ | PROT_WRITE, 0); } - /*********************************************************************** * get_system_affinity_mask */ -ULONG_PTR get_system_affinity_mask(void) -{ - ULONG num_cpus = peb->NumberOfProcessors; - if (num_cpus >= sizeof(ULONG_PTR) * 8) return ~(ULONG_PTR)0; - return ((ULONG_PTR)1 << num_cpus) - 1; +ULONG_PTR get_system_affinity_mask(void) { + ULONG num_cpus = peb->NumberOfProcessors; + if (num_cpus >= sizeof(ULONG_PTR) * 8) + return ~(ULONG_PTR)0; + return ((ULONG_PTR)1 << num_cpus) - 1; } /*********************************************************************** * virtual_get_system_info */ -void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info, BOOL wow64 ) -{ -#if defined(HAVE_SYSINFO) \ - && defined(HAVE_STRUCT_SYSINFO_TOTALRAM) && defined(HAVE_STRUCT_SYSINFO_MEM_UNIT) - struct sysinfo sinfo; +void virtual_get_system_info(SYSTEM_BASIC_INFORMATION *info, BOOL wow64) { +#if defined(HAVE_SYSINFO) && defined(HAVE_STRUCT_SYSINFO_TOTALRAM) && \ + defined(HAVE_STRUCT_SYSINFO_MEM_UNIT) + struct sysinfo sinfo; - if (!sysinfo(&sinfo)) - { - ULONG64 total = (ULONG64)sinfo.totalram * sinfo.mem_unit; - info->MmHighestPhysicalPage = max(1, total / page_size); - } + if (!sysinfo(&sinfo)) { + ULONG64 total = (ULONG64)sinfo.totalram * sinfo.mem_unit; + info->MmHighestPhysicalPage = max(1, total / page_size); + } #elif defined(__APPLE__) - /* sysconf(_SC_PHYS_PAGES) is buggy on macOS: in a 32-bit process, it - * returns an error on Macs with >4GB of RAM. - */ - INT64 memsize; - size_t len = sizeof(memsize); - - if (!sysctlbyname( "hw.memsize", &memsize, &len, NULL, 0 )) - info->MmHighestPhysicalPage = max(1, memsize / page_size); + /* sysconf(_SC_PHYS_PAGES) is buggy on macOS: in a 32-bit process, it + * returns an error on Macs with >4GB of RAM. + */ + INT64 memsize; + size_t len = sizeof(memsize); + + if (!sysctlbyname("hw.memsize", &memsize, &len, NULL, 0)) + info->MmHighestPhysicalPage = max(1, memsize / page_size); #elif defined(_SC_PHYS_PAGES) - LONG64 phys_pages = sysconf( _SC_PHYS_PAGES ); + LONG64 phys_pages = sysconf(_SC_PHYS_PAGES); - info->MmHighestPhysicalPage = max(1, phys_pages); + info->MmHighestPhysicalPage = max(1, phys_pages); #else - info->MmHighestPhysicalPage = 0x7fffffff / page_size; + info->MmHighestPhysicalPage = 0x7fffffff / page_size; #endif - info->unknown = 0; - info->KeMaximumIncrement = 0; /* FIXME */ - info->PageSize = page_size; - info->MmLowestPhysicalPage = 1; - info->MmNumberOfPhysicalPages = info->MmHighestPhysicalPage - info->MmLowestPhysicalPage; - info->AllocationGranularity = granularity_mask + 1; - info->LowestUserAddress = (void *)0x10000; - info->ActiveProcessorsAffinityMask = get_system_affinity_mask(); - info->NumberOfProcessors = peb->NumberOfProcessors; - if (wow64) info->HighestUserAddress = (char *)get_wow_user_space_limit() - 1; - else info->HighestUserAddress = (char *)user_space_limit - 1; + info->unknown = 0; + info->KeMaximumIncrement = 0; /* FIXME */ + info->PageSize = page_size; + info->MmLowestPhysicalPage = 1; + info->MmNumberOfPhysicalPages = + info->MmHighestPhysicalPage - info->MmLowestPhysicalPage; + info->AllocationGranularity = granularity_mask + 1; + info->LowestUserAddress = (void *)0x10000; + info->ActiveProcessorsAffinityMask = get_system_affinity_mask(); + info->NumberOfProcessors = peb->NumberOfProcessors; + if (wow64) + info->HighestUserAddress = (char *)get_wow_user_space_limit() - 1; + else + info->HighestUserAddress = (char *)user_space_limit - 1; } - /*********************************************************************** * virtual_map_builtin_module */ -NTSTATUS virtual_map_builtin_module( HANDLE mapping, void **module, SIZE_T *size, - SECTION_IMAGE_INFORMATION *info, ULONG_PTR limit_low, - ULONG_PTR limit_high, WORD machine, BOOL prefer_native ) -{ - mem_size_t full_size; - unsigned int sec_flags; - HANDLE shared_file; - struct pe_image_info *image_info = NULL; - NTSTATUS status; - WCHAR *filename; - - if ((status = get_mapping_info( mapping, SECTION_MAP_READ, - &sec_flags, &full_size, &shared_file, &image_info ))) - return status; - - if (!image_info) return STATUS_INVALID_PARAMETER; - - *module = NULL; - *size = 0; - filename = (WCHAR *)(image_info + 1); - - if (!image_info->wine_builtin) /* ignore non-builtins */ - { - WARN_(module)( "%s found in WINEDLLPATH but not a builtin, ignoring\n", debugstr_w(filename) ); - status = STATUS_DLL_NOT_FOUND; - } - else if (prefer_native && (image_info->dll_charact & IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE)) - { - TRACE_(module)( "%s has prefer-native flag, ignoring builtin\n", debugstr_w(filename) ); - status = STATUS_IMAGE_ALREADY_LOADED; - } - else - { - status = virtual_map_image( mapping, module, size, shared_file, limit_low, limit_high, 0, - machine, image_info, filename, TRUE ); - virtual_fill_image_information( image_info, info ); - } - - if (shared_file) NtClose( shared_file ); - free( image_info ); - return status; -} +NTSTATUS virtual_map_builtin_module(HANDLE mapping, void **module, SIZE_T *size, + SECTION_IMAGE_INFORMATION *info, + ULONG_PTR limit_low, ULONG_PTR limit_high, + WORD machine, BOOL prefer_native) { + mem_size_t full_size; + unsigned int sec_flags; + HANDLE shared_file; + struct pe_image_info *image_info = NULL; + NTSTATUS status; + WCHAR *filename; + + if ((status = get_mapping_info(mapping, SECTION_MAP_READ, &sec_flags, + &full_size, &shared_file, &image_info))) + return status; + if (!image_info) + return STATUS_INVALID_PARAMETER; + + *module = NULL; + *size = 0; + filename = (WCHAR *)(image_info + 1); + + if (!image_info->wine_builtin) /* ignore non-builtins */ + { + WARN_(module)("%s found in WINEDLLPATH but not a builtin, ignoring\n", + debugstr_w(filename)); + status = STATUS_DLL_NOT_FOUND; + } else if (prefer_native && (image_info->dll_charact & + IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE)) { + TRACE_(module)("%s has prefer-native flag, ignoring builtin\n", + debugstr_w(filename)); + status = STATUS_IMAGE_ALREADY_LOADED; + } else { + status = + virtual_map_image(mapping, module, size, shared_file, limit_low, + limit_high, 0, machine, image_info, filename, TRUE); + virtual_fill_image_information(image_info, info); + } + + if (shared_file) + NtClose(shared_file); + free(image_info); + return status; +} /*********************************************************************** * virtual_map_module */ -NTSTATUS virtual_map_module( HANDLE mapping, void **module, SIZE_T *size, SECTION_IMAGE_INFORMATION *info, - ULONG_PTR limit_low, ULONG_PTR limit_high, USHORT machine ) -{ - unsigned int status; - mem_size_t full_size; - unsigned int sec_flags; - HANDLE shared_file; - struct pe_image_info *image_info = NULL; - WCHAR *filename; - - if ((status = get_mapping_info( mapping, SECTION_MAP_READ, - &sec_flags, &full_size, &shared_file, &image_info ))) - return status; +NTSTATUS virtual_map_module(HANDLE mapping, void **module, SIZE_T *size, + SECTION_IMAGE_INFORMATION *info, + ULONG_PTR limit_low, ULONG_PTR limit_high, + USHORT machine) { + unsigned int status; + mem_size_t full_size; + unsigned int sec_flags; + HANDLE shared_file; + struct pe_image_info *image_info = NULL; + WCHAR *filename; + + if ((status = get_mapping_info(mapping, SECTION_MAP_READ, &sec_flags, + &full_size, &shared_file, &image_info))) + return status; - if (!image_info) return STATUS_INVALID_PARAMETER; + if (!image_info) + return STATUS_INVALID_PARAMETER; - *module = NULL; - *size = 0; - filename = (WCHAR *)(image_info + 1); + *module = NULL; + *size = 0; + filename = (WCHAR *)(image_info + 1); - /* check if we can replace that mapping with the builtin */ - status = load_builtin( image_info, filename, machine, info, module, size, limit_low, limit_high ); - if (status == STATUS_IMAGE_ALREADY_LOADED) - { - status = virtual_map_image( mapping, module, size, shared_file, limit_low, limit_high, 0, - machine, image_info, filename, FALSE ); - virtual_fill_image_information( image_info, info ); - } - if (shared_file) NtClose( shared_file ); - free( image_info ); - return status; + /* check if we can replace that mapping with the builtin */ + status = load_builtin(image_info, filename, machine, info, module, size, + limit_low, limit_high); + if (status == STATUS_IMAGE_ALREADY_LOADED) { + status = + virtual_map_image(mapping, module, size, shared_file, limit_low, + limit_high, 0, machine, image_info, filename, FALSE); + virtual_fill_image_information(image_info, info); + } + if (shared_file) + NtClose(shared_file); + free(image_info); + return status; } - /*********************************************************************** * virtual_create_builtin_view */ -NTSTATUS virtual_create_builtin_view( void *module, const UNICODE_STRING *nt_name, - struct pe_image_info *info, void *so_handle ) -{ - NTSTATUS status; - sigset_t sigset; - IMAGE_DOS_HEADER *dos = module; - IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew); - SIZE_T size = info->map_size; - IMAGE_SECTION_HEADER *sec; - struct file_view *view; - void *base = wine_server_get_ptr( info->base ); - int i; - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - status = create_view( &view, base, size, SEC_IMAGE | SEC_FILE | VPROT_SYSTEM | - VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY | VPROT_EXEC ); - if (!status) - { - TRACE( "created %p-%p for %s\n", base, (char *)base + size, debugstr_us(nt_name) ); - - /* The PE header is always read-only, no write, no execute. */ - set_page_vprot( base, page_size, VPROT_COMMITTED | VPROT_READ ); - - sec = IMAGE_FIRST_SECTION( nt ); - for (i = 0; i < nt->FileHeader.NumberOfSections; i++) - { - BYTE flags = VPROT_COMMITTED; - - if (sec[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) flags |= VPROT_EXEC; - if (sec[i].Characteristics & IMAGE_SCN_MEM_READ) flags |= VPROT_READ; - if (sec[i].Characteristics & IMAGE_SCN_MEM_WRITE) flags |= VPROT_WRITE; - set_page_vprot( (char *)base + sec[i].VirtualAddress, sec[i].Misc.VirtualSize, flags ); - } - - SERVER_START_REQ( map_builtin_view ) - { - wine_server_add_data( req, info, sizeof(*info) ); - wine_server_add_data( req, nt_name->Buffer, nt_name->Length ); - status = wine_server_call( req ); - } - SERVER_END_REQ; - - if (!status) - { - add_builtin_module( view->base, so_handle ); - VIRTUAL_DEBUG_DUMP_VIEW( view ); - if (is_beyond_limit( base, size, working_set_limit )) working_set_limit = address_space_limit; - } - else delete_view( view ); +NTSTATUS virtual_create_builtin_view(void *module, + const UNICODE_STRING *nt_name, + struct pe_image_info *info, + void *so_handle) { + NTSTATUS status; + sigset_t sigset; + IMAGE_DOS_HEADER *dos = module; + IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew); + SIZE_T size = info->map_size; + IMAGE_SECTION_HEADER *sec; + struct file_view *view; + void *base = wine_server_get_ptr(info->base); + int i; + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + status = create_view(&view, base, size, + SEC_IMAGE | SEC_FILE | VPROT_SYSTEM | VPROT_COMMITTED | + VPROT_READ | VPROT_WRITECOPY | VPROT_EXEC); + if (!status) { + TRACE("created %p-%p for %s\n", base, (char *)base + size, + debugstr_us(nt_name)); + + /* The PE header is always read-only, no write, no execute. */ + set_page_vprot(base, page_size, VPROT_COMMITTED | VPROT_READ); + + sec = IMAGE_FIRST_SECTION(nt); + for (i = 0; i < nt->FileHeader.NumberOfSections; i++) { + BYTE flags = VPROT_COMMITTED; + + if (sec[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) + flags |= VPROT_EXEC; + if (sec[i].Characteristics & IMAGE_SCN_MEM_READ) + flags |= VPROT_READ; + if (sec[i].Characteristics & IMAGE_SCN_MEM_WRITE) + flags |= VPROT_WRITE; + set_page_vprot((char *)base + sec[i].VirtualAddress, + sec[i].Misc.VirtualSize, flags); + } + + SERVER_START_REQ(map_builtin_view) { + wine_server_add_data(req, info, sizeof(*info)); + wine_server_add_data(req, nt_name->Buffer, nt_name->Length); + status = wine_server_call(req); } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); + SERVER_END_REQ; - return status; -} + if (!status) { + add_builtin_module(view->base, so_handle); + VIRTUAL_DEBUG_DUMP_VIEW(view); + if (is_beyond_limit(base, size, working_set_limit)) + working_set_limit = address_space_limit; + } else + delete_view(view); + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return status; +} /*********************************************************************** * virtual_relocate_module */ -NTSTATUS virtual_relocate_module( void *module ) -{ - char *ptr = module; - IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(ptr + ((IMAGE_DOS_HEADER *)module)->e_lfanew); - IMAGE_DATA_DIRECTORY *relocs; - IMAGE_BASE_RELOCATION *rel, *end; - IMAGE_SECTION_HEADER *sec; - ULONG total_size = ROUND_SIZE( 0, nt->OptionalHeader.SizeOfImage ); - ULONG protect_old[96], i; - ULONG_PTR image_base; - INT_PTR delta; - - if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) - image_base = ((const IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.ImageBase; - else - image_base = ((const IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.ImageBase; - - - if (!(delta = (ULONG_PTR)module - image_base)) return STATUS_SUCCESS; - - if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) - { - ERR( "Need to relocate module from %p to %p, but relocation records are stripped\n", - (void *)image_base, module ); - return STATUS_CONFLICTING_ADDRESSES; - } +NTSTATUS virtual_relocate_module(void *module) { + char *ptr = module; + IMAGE_NT_HEADERS *nt = + (IMAGE_NT_HEADERS *)(ptr + ((IMAGE_DOS_HEADER *)module)->e_lfanew); + IMAGE_DATA_DIRECTORY *relocs; + IMAGE_BASE_RELOCATION *rel, *end; + IMAGE_SECTION_HEADER *sec; + ULONG total_size = ROUND_SIZE(0, nt->OptionalHeader.SizeOfImage); + ULONG protect_old[96], i; + ULONG_PTR image_base; + INT_PTR delta; + + if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + image_base = ((const IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.ImageBase; + else + image_base = ((const IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.ImageBase; + + if (!(delta = (ULONG_PTR)module - image_base)) + return STATUS_SUCCESS; - TRACE( "%p -> %p\n", (void *)image_base, module ); + if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) { + ERR("Need to relocate module from %p to %p, but relocation records are " + "stripped\n", + (void *)image_base, module); + return STATUS_CONFLICTING_ADDRESSES; + } - if (!(relocs = get_data_dir( nt, total_size, IMAGE_DIRECTORY_ENTRY_BASERELOC ))) return STATUS_SUCCESS; + TRACE("%p -> %p\n", (void *)image_base, module); - sec = IMAGE_FIRST_SECTION( nt ); - for (i = 0; i < nt->FileHeader.NumberOfSections; i++) - { - void *addr = (char *)module + sec[i].VirtualAddress; - SIZE_T size = sec[i].SizeOfRawData; - NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, PAGE_READWRITE, &protect_old[i] ); - } + if (!(relocs = get_data_dir(nt, total_size, IMAGE_DIRECTORY_ENTRY_BASERELOC))) + return STATUS_SUCCESS; + sec = IMAGE_FIRST_SECTION(nt); + for (i = 0; i < nt->FileHeader.NumberOfSections; i++) { + void *addr = (char *)module + sec[i].VirtualAddress; + SIZE_T size = sec[i].SizeOfRawData; + NtProtectVirtualMemory(NtCurrentProcess(), &addr, &size, PAGE_READWRITE, + &protect_old[i]); + } - rel = (IMAGE_BASE_RELOCATION *)((char *)module + relocs->VirtualAddress); - end = (IMAGE_BASE_RELOCATION *)((char *)rel + relocs->Size); + rel = (IMAGE_BASE_RELOCATION *)((char *)module + relocs->VirtualAddress); + end = (IMAGE_BASE_RELOCATION *)((char *)rel + relocs->Size); - while (rel && rel < end - 1 && rel->SizeOfBlock && rel->VirtualAddress < total_size) - rel = process_relocation_block( (char *)module + rel->VirtualAddress, rel, delta ); + while (rel && rel < end - 1 && rel->SizeOfBlock && + rel->VirtualAddress < total_size) + rel = process_relocation_block((char *)module + rel->VirtualAddress, rel, + delta); - for (i = 0; i < nt->FileHeader.NumberOfSections; i++) - { - void *addr = (char *)module + sec[i].VirtualAddress; - SIZE_T size = sec[i].SizeOfRawData; - NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, protect_old[i], &protect_old[i] ); - } - return STATUS_SUCCESS; + for (i = 0; i < nt->FileHeader.NumberOfSections; i++) { + void *addr = (char *)module + sec[i].VirtualAddress; + SIZE_T size = sec[i].SizeOfRawData; + NtProtectVirtualMemory(NtCurrentProcess(), &addr, &size, protect_old[i], + &protect_old[i]); + } + return STATUS_SUCCESS; } - /* set some initial values in a new TEB */ -static TEB *init_teb( void *ptr, BOOL is_wow ) -{ - struct ntdll_thread_data *thread_data; - TEB *teb; - TEB64 *teb64 = ptr; - TEB32 *teb32 = (TEB32 *)((char *)ptr + teb_offset); +static TEB *init_teb(void *ptr, BOOL is_wow) { + struct ntdll_thread_data *thread_data; + TEB *teb; + TEB64 *teb64 = ptr; + TEB32 *teb32 = (TEB32 *)((char *)ptr + teb_offset); #ifdef _WIN64 - teb = (TEB *)teb64; - teb32->Peb = PtrToUlong( (char *)peb + page_size ); - teb32->Tib.Self = PtrToUlong( teb32 ); - teb32->Tib.ExceptionList = ~0u; - teb32->ActivationContextStackPointer = PtrToUlong( &teb32->ActivationContextStack ); - teb32->ActivationContextStack.FrameListCache.Flink = - teb32->ActivationContextStack.FrameListCache.Blink = - PtrToUlong( &teb32->ActivationContextStack.FrameListCache ); - teb32->StaticUnicodeString.Buffer = PtrToUlong( teb32->StaticUnicodeBuffer ); - teb32->StaticUnicodeString.MaximumLength = sizeof( teb32->StaticUnicodeBuffer ); - teb32->GdiBatchCount = PtrToUlong( teb64 ); - teb32->WowTebOffset = -teb_offset; - if (is_wow) teb64->WowTebOffset = teb_offset; -#else - teb = (TEB *)teb32; - teb32->Tib.ExceptionList = ~0u; - teb64->Peb = PtrToUlong( (char *)peb - page_size ); - teb64->Tib.Self = PtrToUlong( teb64 ); - teb64->Tib.ExceptionList = PtrToUlong( teb32 ); - teb64->ActivationContextStackPointer = PtrToUlong( &teb64->ActivationContextStack ); - teb64->ActivationContextStack.FrameListCache.Flink = - teb64->ActivationContextStack.FrameListCache.Blink = - PtrToUlong( &teb64->ActivationContextStack.FrameListCache ); - teb64->StaticUnicodeString.Buffer = PtrToUlong( teb64->StaticUnicodeBuffer ); - teb64->StaticUnicodeString.MaximumLength = sizeof( teb64->StaticUnicodeBuffer ); + teb = (TEB *)teb64; + teb32->Peb = PtrToUlong((char *)peb + page_size); + teb32->Tib.Self = PtrToUlong(teb32); + teb32->Tib.ExceptionList = ~0u; + teb32->ActivationContextStackPointer = + PtrToUlong(&teb32->ActivationContextStack); + teb32->ActivationContextStack.FrameListCache.Flink = + teb32->ActivationContextStack.FrameListCache.Blink = + PtrToUlong(&teb32->ActivationContextStack.FrameListCache); + teb32->StaticUnicodeString.Buffer = PtrToUlong(teb32->StaticUnicodeBuffer); + teb32->StaticUnicodeString.MaximumLength = sizeof(teb32->StaticUnicodeBuffer); + teb32->GdiBatchCount = PtrToUlong(teb64); + teb32->WowTebOffset = -teb_offset; + if (is_wow) teb64->WowTebOffset = teb_offset; - if (is_wow) - { - teb32->GdiBatchCount = PtrToUlong( teb64 ); - teb32->WowTebOffset = -teb_offset; - } +#else + teb = (TEB *)teb32; + teb32->Tib.ExceptionList = ~0u; + teb64->Peb = PtrToUlong((char *)peb - page_size); + teb64->Tib.Self = PtrToUlong(teb64); + teb64->Tib.ExceptionList = PtrToUlong(teb32); + teb64->ActivationContextStackPointer = + PtrToUlong(&teb64->ActivationContextStack); + teb64->ActivationContextStack.FrameListCache.Flink = + teb64->ActivationContextStack.FrameListCache.Blink = + PtrToUlong(&teb64->ActivationContextStack.FrameListCache); + teb64->StaticUnicodeString.Buffer = PtrToUlong(teb64->StaticUnicodeBuffer); + teb64->StaticUnicodeString.MaximumLength = sizeof(teb64->StaticUnicodeBuffer); + teb64->WowTebOffset = teb_offset; + if (is_wow) { + teb32->GdiBatchCount = PtrToUlong(teb64); + teb32->WowTebOffset = -teb_offset; + } #endif - teb->Peb = peb; - teb->Tib.Self = &teb->Tib; - teb->Tib.StackBase = (void *)~0ul; - teb->ActivationContextStackPointer = &teb->ActivationContextStack; - InitializeListHead( &teb->ActivationContextStack.FrameListCache ); - teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; - teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); - thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; - thread_data->esync_apc_fd = -1; - thread_data->request_fd = -1; - thread_data->reply_fd = -1; - thread_data->wait_fd[0] = -1; - thread_data->wait_fd[1] = -1; - list_add_head( &teb_list, &thread_data->entry ); - return teb; + teb->Peb = peb; + teb->Tib.Self = &teb->Tib; + teb->Tib.StackBase = (void *)~0ul; + teb->ActivationContextStackPointer = &teb->ActivationContextStack; + InitializeListHead(&teb->ActivationContextStack.FrameListCache); + teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; + teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); + thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; + thread_data->esync_apc_fd = -1; + thread_data->request_fd = -1; + thread_data->reply_fd = -1; + thread_data->wait_fd[0] = -1; + thread_data->wait_fd[1] = -1; + list_add_head(&teb_list, &thread_data->entry); + return teb; } - /*********************************************************************** * virtual_alloc_first_teb */ -TEB *virtual_alloc_first_teb(void) -{ - void *ptr; - TEB *teb; - unsigned int status; - SIZE_T data_size = page_size; - SIZE_T block_size = signal_stack_mask + 1; - SIZE_T total = 32 * block_size; - - /* reserve space for shared user data */ - status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&user_shared_data, 0, &data_size, - MEM_RESERVE | MEM_COMMIT, PAGE_READONLY ); - if (status) - { - ERR( "wine: failed to map the shared user data: %08x\n", status ); - exit(1); - } - - NtAllocateVirtualMemory( NtCurrentProcess(), &teb_block, is_win64 ? limit_2g - 1 : 0, &total, - MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); - teb_block_pos = 30; - ptr = (char *)teb_block + 30 * block_size; - data_size = 2 * block_size; - NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&ptr, 0, &data_size, MEM_COMMIT, PAGE_READWRITE ); - peb = (PEB *)((char *)teb_block + 31 * block_size + (is_win64 ? 0 : page_size)); - teb = init_teb( ptr, FALSE ); - pthread_key_create( &teb_key, NULL ); - pthread_setspecific( teb_key, teb ); - return teb; +TEB *virtual_alloc_first_teb(void) { + void *ptr; + TEB *teb; + unsigned int status; + SIZE_T data_size = page_size; + SIZE_T block_size = signal_stack_mask + 1; + SIZE_T total = 32 * block_size; + + /* reserve space for shared user data */ + status = NtAllocateVirtualMemory(NtCurrentProcess(), + (void **)&user_shared_data, 0, &data_size, + MEM_RESERVE | MEM_COMMIT, PAGE_READONLY); + if (status) { + ERR("wine: failed to map the shared user data: %08x\n", status); + exit(1); + } + + NtAllocateVirtualMemory(NtCurrentProcess(), &teb_block, + is_win64 ? limit_2g - 1 : 0, &total, + MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE); + teb_block_pos = 30; + ptr = (char *)teb_block + 30 * block_size; + data_size = 2 * block_size; + NtAllocateVirtualMemory(NtCurrentProcess(), (void **)&ptr, 0, &data_size, + MEM_COMMIT, PAGE_READWRITE); + peb = + (PEB *)((char *)teb_block + 31 * block_size + (is_win64 ? 0 : page_size)); + teb = init_teb(ptr, FALSE); + pthread_key_create(&teb_key, NULL); + pthread_setspecific(teb_key, teb); + return teb; } - /*********************************************************************** * virtual_alloc_teb */ -NTSTATUS virtual_alloc_teb( TEB **ret_teb ) -{ - sigset_t sigset; - TEB *teb; - void *ptr = NULL; - NTSTATUS status = STATUS_SUCCESS; - SIZE_T block_size = signal_stack_mask + 1; - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if (next_free_teb) - { - ptr = next_free_teb; - next_free_teb = *(void **)ptr; - memset( ptr, 0, teb_size ); - } - else - { - if (!teb_block_pos) - { - SIZE_T total = 32 * block_size; - - if ((status = NtAllocateVirtualMemory( NtCurrentProcess(), &ptr, user_space_wow_limit, - &total, MEM_RESERVE, PAGE_READWRITE ))) - { - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return status; - } - teb_block = ptr; - teb_block_pos = 32; - } - ptr = ((char *)teb_block + --teb_block_pos * block_size); - NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&ptr, 0, &block_size, - MEM_COMMIT, PAGE_READWRITE ); - } - *ret_teb = teb = init_teb( ptr, is_wow64() ); - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - - if ((status = signal_alloc_thread( teb ))) - { - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - *(void **)ptr = next_free_teb; - next_free_teb = ptr; - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - } - return status; +NTSTATUS virtual_alloc_teb(TEB **ret_teb) { + sigset_t sigset; + TEB *teb; + void *ptr = NULL; + NTSTATUS status = STATUS_SUCCESS; + SIZE_T block_size = signal_stack_mask + 1; + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + if (next_free_teb) { + ptr = next_free_teb; + next_free_teb = *(void **)ptr; + memset(ptr, 0, teb_size); + } else { + if (!teb_block_pos) { + SIZE_T total = 32 * block_size; + + if ((status = NtAllocateVirtualMemory(NtCurrentProcess(), &ptr, + user_space_wow_limit, &total, + MEM_RESERVE, PAGE_READWRITE))) { + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return status; + } + teb_block = ptr; + teb_block_pos = 32; + } + ptr = ((char *)teb_block + --teb_block_pos * block_size); + NtAllocateVirtualMemory(NtCurrentProcess(), (void **)&ptr, 0, &block_size, + MEM_COMMIT, PAGE_READWRITE); + } + *ret_teb = teb = init_teb(ptr, is_wow64()); + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + + if ((status = signal_alloc_thread(teb))) { + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + *(void **)ptr = next_free_teb; + next_free_teb = ptr; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + } + return status; } - /*********************************************************************** * virtual_free_teb */ -void virtual_free_teb( TEB *teb ) -{ - struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; - void *ptr; - SIZE_T size; - sigset_t sigset; - WOW_TEB *wow_teb = get_wow_teb( teb ); - - signal_free_thread( teb ); - if (teb->DeallocationStack) - { - size = 0; - NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); - } +void virtual_free_teb(TEB *teb) { + struct ntdll_thread_data *thread_data = + (struct ntdll_thread_data *)&teb->GdiTebBatch; + void *ptr; + SIZE_T size; + sigset_t sigset; + WOW_TEB *wow_teb = get_wow_teb(teb); + + signal_free_thread(teb); + if (teb->DeallocationStack) { + size = 0; + NtFreeVirtualMemory(GetCurrentProcess(), &teb->DeallocationStack, &size, + MEM_RELEASE); + } #ifdef __aarch64__ - if (teb->ChpeV2CpuAreaInfo) - { - size = 0; - NtFreeVirtualMemory( GetCurrentProcess(), (void **)&teb->ChpeV2CpuAreaInfo, &size, MEM_RELEASE ); - } + if (teb->ChpeV2CpuAreaInfo) { + size = 0; + NtFreeVirtualMemory(GetCurrentProcess(), (void **)&teb->ChpeV2CpuAreaInfo, + &size, MEM_RELEASE); + } #endif - if (thread_data->kernel_stack) - { - size = 0; - NtFreeVirtualMemory( GetCurrentProcess(), &thread_data->kernel_stack, &size, MEM_RELEASE ); - } - if (wow_teb && (ptr = ULongToPtr( wow_teb->DeallocationStack ))) - { - size = 0; - NtFreeVirtualMemory( GetCurrentProcess(), &ptr, &size, MEM_RELEASE ); - } - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - list_remove( &thread_data->entry ); - ptr = teb; - if (!is_win64) ptr = (char *)ptr - teb_offset; - *(void **)ptr = next_free_teb; - next_free_teb = ptr; - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); + if (thread_data->kernel_stack) { + size = 0; + NtFreeVirtualMemory(GetCurrentProcess(), &thread_data->kernel_stack, &size, + MEM_RELEASE); + } + if (wow_teb && (ptr = ULongToPtr(wow_teb->DeallocationStack))) { + size = 0; + NtFreeVirtualMemory(GetCurrentProcess(), &ptr, &size, MEM_RELEASE); + } + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + list_remove(&thread_data->entry); + ptr = teb; + if (!is_win64) + ptr = (char *)ptr - teb_offset; + *(void **)ptr = next_free_teb; + next_free_teb = ptr; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); } - /*********************************************************************** * virtual_clear_tls_index */ -NTSTATUS virtual_clear_tls_index( ULONG index ) -{ - struct ntdll_thread_data *thread_data; - sigset_t sigset; +NTSTATUS virtual_clear_tls_index(ULONG index) { + struct ntdll_thread_data *thread_data; + sigset_t sigset; - if (index < TLS_MINIMUM_AVAILABLE) - { - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - LIST_FOR_EACH_ENTRY( thread_data, &teb_list, struct ntdll_thread_data, entry ) - { - TEB *teb = CONTAINING_RECORD( thread_data, TEB, GdiTebBatch ); + if (index < TLS_MINIMUM_AVAILABLE) { + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + LIST_FOR_EACH_ENTRY(thread_data, &teb_list, struct ntdll_thread_data, + entry) { + TEB *teb = CONTAINING_RECORD(thread_data, TEB, GdiTebBatch); #ifdef _WIN64 - WOW_TEB *wow_teb = get_wow_teb( teb ); - if (wow_teb) wow_teb->TlsSlots[index] = 0; - else + WOW_TEB *wow_teb = get_wow_teb(teb); + if (wow_teb) + wow_teb->TlsSlots[index] = 0; + else #endif - teb->TlsSlots[index] = 0; - } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - } - else - { - index -= TLS_MINIMUM_AVAILABLE; - if (index >= 8 * sizeof(peb->TlsExpansionBitmapBits)) return STATUS_INVALID_PARAMETER; - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - LIST_FOR_EACH_ENTRY( thread_data, &teb_list, struct ntdll_thread_data, entry ) - { - TEB *teb = CONTAINING_RECORD( thread_data, TEB, GdiTebBatch ); + teb->TlsSlots[index] = 0; + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + } else { + index -= TLS_MINIMUM_AVAILABLE; + if (index >= 8 * sizeof(peb->TlsExpansionBitmapBits)) + return STATUS_INVALID_PARAMETER; + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + LIST_FOR_EACH_ENTRY(thread_data, &teb_list, struct ntdll_thread_data, + entry) { + TEB *teb = CONTAINING_RECORD(thread_data, TEB, GdiTebBatch); #ifdef _WIN64 - WOW_TEB *wow_teb = get_wow_teb( teb ); - if (wow_teb) - { - if (wow_teb->TlsExpansionSlots) - ((ULONG *)ULongToPtr( wow_teb->TlsExpansionSlots ))[index] = 0; - } - else + WOW_TEB *wow_teb = get_wow_teb(teb); + if (wow_teb) { + if (wow_teb->TlsExpansionSlots) + ((ULONG *)ULongToPtr(wow_teb->TlsExpansionSlots))[index] = 0; + } else #endif - if (teb->TlsExpansionSlots) teb->TlsExpansionSlots[index] = 0; - } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); + if (teb->TlsExpansionSlots) + teb->TlsExpansionSlots[index] = 0; } - return STATUS_SUCCESS; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + } + return STATUS_SUCCESS; } - /*********************************************************************** * virtual_alloc_thread_stack */ -NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR limit_low, ULONG_PTR limit_high, - SIZE_T reserve_size, SIZE_T commit_size, BOOL guard_page ) -{ - struct file_view *view; - NTSTATUS status; - sigset_t sigset; - SIZE_T size; +NTSTATUS virtual_alloc_thread_stack(INITIAL_TEB *stack, ULONG_PTR limit_low, + ULONG_PTR limit_high, SIZE_T reserve_size, + SIZE_T commit_size, BOOL guard_page) { + struct file_view *view; + NTSTATUS status; + sigset_t sigset; + SIZE_T size; - if (!reserve_size) reserve_size = main_image_info.MaximumStackSize; - if (!commit_size) commit_size = main_image_info.CommittedStackSize; + if (!reserve_size) + reserve_size = main_image_info.MaximumStackSize; + if (!commit_size) + commit_size = main_image_info.CommittedStackSize; - size = max( reserve_size, commit_size ); - if (size < 1024 * 1024) size = 1024 * 1024; /* Xlib needs a large stack */ - size = (size + 0xffff) & ~0xffff; /* round to 64K boundary */ + size = max(reserve_size, commit_size); + if (size < 1024 * 1024) + size = 1024 * 1024; /* Xlib needs a large stack */ + size = (size + 0xffff) & ~0xffff; /* round to 64K boundary */ - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); + server_enter_uninterrupted_section(&virtual_mutex, &sigset); - status = map_view( &view, NULL, size, 0, VPROT_READ | VPROT_WRITE | VPROT_COMMITTED, - limit_low, limit_high, 0 ); - if (status != STATUS_SUCCESS) goto done; + status = + map_view(&view, NULL, size, 0, VPROT_READ | VPROT_WRITE | VPROT_COMMITTED, + limit_low, limit_high, 0); + if (status != STATUS_SUCCESS) + goto done; #ifdef VALGRIND_STACK_REGISTER - VALGRIND_STACK_REGISTER( view->base, (char *)view->base + view->size ); + VALGRIND_STACK_REGISTER(view->base, (char *)view->base + view->size); #endif - /* setup no access guard page */ - if (guard_page) - { - set_page_vprot( view->base, page_size, VPROT_COMMITTED ); - set_page_vprot( (char *)view->base + page_size, page_size, - VPROT_READ | VPROT_WRITE | VPROT_COMMITTED | VPROT_GUARD ); - mprotect_range( view->base, 2 * page_size , 0, 0 ); - } - VIRTUAL_DEBUG_DUMP_VIEW( view ); - - /* note: limit is lower than base since the stack grows down */ - stack->OldStackBase = 0; - stack->OldStackLimit = 0; - stack->DeallocationStack = view->base; - stack->StackBase = (char *)view->base + view->size; - stack->StackLimit = (char *)view->base + (guard_page ? 2 * page_size : 0); + /* setup no access guard page */ + if (guard_page) { + set_page_vprot(view->base, page_size, VPROT_COMMITTED); + set_page_vprot((char *)view->base + page_size, page_size, + VPROT_READ | VPROT_WRITE | VPROT_COMMITTED | VPROT_GUARD); + mprotect_range(view->base, 2 * page_size, 0, 0); + } + VIRTUAL_DEBUG_DUMP_VIEW(view); + + /* note: limit is lower than base since the stack grows down */ + stack->OldStackBase = 0; + stack->OldStackLimit = 0; + stack->DeallocationStack = view->base; + stack->StackBase = (char *)view->base + view->size; + stack->StackLimit = (char *)view->base + (guard_page ? 2 * page_size : 0); done: - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return status; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return status; } - /*********************************************************************** * virtual_map_user_shared_data */ -void virtual_map_user_shared_data(void) -{ - static const WCHAR nameW[] = {'\\','K','e','r','n','e','l','O','b','j','e','c','t','s', - '\\','_','_','w','i','n','e','_','u','s','e','r','_','s','h','a','r','e','d','_','d','a','t','a',0}; - UNICODE_STRING name_str = RTL_CONSTANT_STRING( nameW ); - OBJECT_ATTRIBUTES attr = { sizeof(attr), 0, &name_str }; - unsigned int status; - HANDLE section; - int res, fd, needs_close; - - if ((status = NtOpenSection( §ion, SECTION_ALL_ACCESS, &attr ))) - { - ERR( "failed to open the USD section: %08x\n", status ); - exit(1); - } - if ((res = server_get_unix_fd( section, 0, &fd, &needs_close, NULL, NULL )) || - (user_shared_data != mmap( user_shared_data, page_size, PROT_READ, MAP_SHARED|MAP_FIXED, fd, 0 ))) - { - ERR( "failed to remap the process USD: %d\n", res ); - exit(1); - } - if (needs_close) close( fd ); - NtClose( section ); -} - - -struct thread_stack_info -{ - char *start; - char *limit; - char *end; - SIZE_T guaranteed; - BOOL is_wow; +void virtual_map_user_shared_data(void) { + static const WCHAR nameW[] = { + '\\', 'K', 'e', 'r', 'n', 'e', 'l', 'O', 'b', 'j', 'e', 'c', 't', + 's', '\\', '_', '_', 'w', 'i', 'n', 'e', '_', 'u', 's', 'e', 'r', + '_', 's', 'h', 'a', 'r', 'e', 'd', '_', 'd', 'a', 't', 'a', 0}; + UNICODE_STRING name_str = RTL_CONSTANT_STRING(nameW); + OBJECT_ATTRIBUTES attr = {sizeof(attr), 0, &name_str}; + unsigned int status; + HANDLE section; + int res, fd, needs_close; + + if ((status = NtOpenSection(§ion, SECTION_ALL_ACCESS, &attr))) { + ERR("failed to open the USD section: %08x\n", status); + exit(1); + } + if ((res = server_get_unix_fd(section, 0, &fd, &needs_close, NULL, NULL)) || + (user_shared_data != mmap(user_shared_data, page_size, PROT_READ, + MAP_SHARED | MAP_FIXED, fd, 0))) { + ERR("failed to remap the process USD: %d\n", res); + exit(1); + } + if (needs_close) + close(fd); + NtClose(section); +} + +struct thread_stack_info { + char *start; + char *limit; + char *end; + SIZE_T guaranteed; + BOOL is_wow; }; /*********************************************************************** * is_inside_thread_stack */ -static BOOL is_inside_thread_stack( void *ptr, struct thread_stack_info *stack ) -{ - TEB *teb = NtCurrentTeb(); - WOW_TEB *wow_teb = get_wow_teb( teb ); - - stack->start = teb->DeallocationStack; - stack->limit = teb->Tib.StackLimit; - stack->end = teb->Tib.StackBase; - stack->guaranteed = max( teb->GuaranteedStackBytes, page_size * (is_win64 ? 2 : 1) ); - stack->is_wow = FALSE; - if ((char *)ptr > stack->start && (char *)ptr <= stack->end) return TRUE; +static BOOL is_inside_thread_stack(void *ptr, struct thread_stack_info *stack) { + TEB *teb = NtCurrentTeb(); + WOW_TEB *wow_teb = get_wow_teb(teb); + + stack->start = teb->DeallocationStack; + stack->limit = teb->Tib.StackLimit; + stack->end = teb->Tib.StackBase; + stack->guaranteed = + max(teb->GuaranteedStackBytes, page_size * (is_win64 ? 2 : 1)); + stack->is_wow = FALSE; + if ((char *)ptr > stack->start && (char *)ptr <= stack->end) + return TRUE; - if (!wow_teb) return FALSE; - stack->start = ULongToPtr( wow_teb->DeallocationStack ); - stack->limit = ULongToPtr( wow_teb->Tib.StackLimit ); - stack->end = ULongToPtr( wow_teb->Tib.StackBase ); - stack->guaranteed = max( wow_teb->GuaranteedStackBytes, page_size * (is_win64 ? 1 : 2) ); - stack->is_wow = TRUE; - return ((char *)ptr > stack->start && (char *)ptr <= stack->end); + if (!wow_teb) + return FALSE; + stack->start = ULongToPtr(wow_teb->DeallocationStack); + stack->limit = ULongToPtr(wow_teb->Tib.StackLimit); + stack->end = ULongToPtr(wow_teb->Tib.StackBase); + stack->guaranteed = + max(wow_teb->GuaranteedStackBytes, page_size * (is_win64 ? 1 : 2)); + stack->is_wow = TRUE; + return ((char *)ptr > stack->start && (char *)ptr <= stack->end); } - /*********************************************************************** * grow_thread_stack */ -static NTSTATUS grow_thread_stack( char *page, struct thread_stack_info *stack_info ) -{ - NTSTATUS ret = 0; - - set_page_vprot_bits( page, page_size, 0, VPROT_GUARD ); - mprotect_range( page, page_size, 0, 0 ); - if (page >= stack_info->start + page_size + stack_info->guaranteed) - { - set_page_vprot_bits( page - page_size, page_size, VPROT_COMMITTED | VPROT_GUARD, 0 ); - mprotect_range( page - page_size, page_size, 0, 0 ); - } - else /* inside guaranteed space -> overflow exception */ - { - page = stack_info->start + page_size; - set_page_vprot_bits( page, stack_info->guaranteed, VPROT_COMMITTED, VPROT_GUARD ); - mprotect_range( page, stack_info->guaranteed, 0, 0 ); - ret = STATUS_STACK_OVERFLOW; - } - if (stack_info->is_wow) - { - WOW_TEB *wow_teb = get_wow_teb( NtCurrentTeb() ); - wow_teb->Tib.StackLimit = PtrToUlong( page ); - } - else NtCurrentTeb()->Tib.StackLimit = page; - return ret; +static NTSTATUS grow_thread_stack(char *page, + struct thread_stack_info *stack_info) { + NTSTATUS ret = 0; + + set_page_vprot_bits(page, page_size, 0, VPROT_GUARD); + mprotect_range(page, page_size, 0, 0); + if (page >= stack_info->start + page_size + stack_info->guaranteed) { + set_page_vprot_bits(page - page_size, page_size, + VPROT_COMMITTED | VPROT_GUARD, 0); + mprotect_range(page - page_size, page_size, 0, 0); + } else /* inside guaranteed space -> overflow exception */ + { + page = stack_info->start + page_size; + set_page_vprot_bits(page, stack_info->guaranteed, VPROT_COMMITTED, + VPROT_GUARD); + mprotect_range(page, stack_info->guaranteed, 0, 0); + ret = STATUS_STACK_OVERFLOW; + } + if (stack_info->is_wow) { + WOW_TEB *wow_teb = get_wow_teb(NtCurrentTeb()); + wow_teb->Tib.StackLimit = PtrToUlong(page); + } else + NtCurrentTeb()->Tib.StackLimit = page; + return ret; } - /*********************************************************************** * virtual_handle_fault */ -NTSTATUS virtual_handle_fault( EXCEPTION_RECORD *rec, void *stack ) -{ - NTSTATUS ret = STATUS_ACCESS_VIOLATION; - ULONG_PTR err = rec->ExceptionInformation[0]; - void *addr = (void *)rec->ExceptionInformation[1]; - char *page = ROUND_ADDR( addr, page_mask ); - BYTE vprot; +NTSTATUS virtual_handle_fault(EXCEPTION_RECORD *rec, void *stack) { + NTSTATUS ret = STATUS_ACCESS_VIOLATION; + ULONG_PTR err = rec->ExceptionInformation[0]; + void *addr = (void *)rec->ExceptionInformation[1]; + char *page = ROUND_ADDR(addr, page_mask); + BYTE vprot; - mutex_lock( &virtual_mutex ); /* no need for signal masking inside signal handler */ - vprot = get_page_vprot( page ); + mutex_lock( + &virtual_mutex); /* no need for signal masking inside signal handler */ + vprot = get_page_vprot(page); #ifdef __APPLE__ - /* Rosetta on Apple Silicon misreports certain write faults as read faults. */ - if (err == EXCEPTION_READ_FAULT && (get_unix_prot( vprot ) & PROT_READ)) - { - WARN( "treating read fault in a readable page as a write fault, addr %p\n", addr ); - err = EXCEPTION_WRITE_FAULT; - } + /* Rosetta on Apple Silicon misreports certain write faults as read faults. */ + if (err == EXCEPTION_READ_FAULT && (get_unix_prot(vprot) & PROT_READ)) { + WARN("treating read fault in a readable page as a write fault, addr %p\n", + addr); + err = EXCEPTION_WRITE_FAULT; + } #endif - if (!is_inside_signal_stack( stack ) && (vprot & VPROT_GUARD)) - { - struct thread_stack_info stack_info; - if (!is_inside_thread_stack( page, &stack_info )) - { - set_page_vprot_bits( page, page_size, 0, VPROT_GUARD ); - mprotect_range( page, page_size, 0, 0 ); - ret = STATUS_GUARD_PAGE_VIOLATION; - } - else ret = grow_thread_stack( page, &stack_info ); - } - else if (err & EXCEPTION_WRITE_FAULT) - { - if (vprot & VPROT_WRITEWATCH) - { - if (enable_write_exceptions && is_vprot_exec_write( vprot ) && !ntdll_get_thread_data()->allow_writes) - { - rec->NumberParameters = 3; - rec->ExceptionInformation[2] = STATUS_EXECUTABLE_MEMORY_WRITE; - ret = STATUS_IN_PAGE_ERROR; - } - else - { - set_page_vprot_bits( page, page_size, 0, VPROT_WRITEWATCH ); - mprotect_range( page, page_size, 0, 0 ); - } - } - /* ignore fault if page is writable now */ - if (get_unix_prot( get_page_vprot( page )) & PROT_WRITE) - { - if ((vprot & VPROT_WRITEWATCH) || is_write_watch_range( page, page_size )) - ret = STATUS_SUCCESS; - } - } - mutex_unlock( &virtual_mutex ); - rec->ExceptionCode = ret; - return ret; + if (!is_inside_signal_stack(stack) && (vprot & VPROT_GUARD)) { + struct thread_stack_info stack_info; + if (!is_inside_thread_stack(page, &stack_info)) { + set_page_vprot_bits(page, page_size, 0, VPROT_GUARD); + mprotect_range(page, page_size, 0, 0); + ret = STATUS_GUARD_PAGE_VIOLATION; + } else + ret = grow_thread_stack(page, &stack_info); + } else if (err & EXCEPTION_WRITE_FAULT) { + if (vprot & VPROT_WRITEWATCH) { + if (enable_write_exceptions && is_vprot_exec_write(vprot) && + !ntdll_get_thread_data()->allow_writes) { + rec->NumberParameters = 3; + rec->ExceptionInformation[2] = STATUS_EXECUTABLE_MEMORY_WRITE; + ret = STATUS_IN_PAGE_ERROR; + } else { + set_page_vprot_bits(page, page_size, 0, VPROT_WRITEWATCH); + mprotect_range(page, page_size, 0, 0); + } + } + /* ignore fault if page is writable now */ + if (get_unix_prot(get_page_vprot(page)) & PROT_WRITE) { + if ((vprot & VPROT_WRITEWATCH) || is_write_watch_range(page, page_size)) + ret = STATUS_SUCCESS; + } + } + mutex_unlock(&virtual_mutex); + rec->ExceptionCode = ret; + return ret; } - /*********************************************************************** * virtual_setup_exception */ -void *virtual_setup_exception( void *stack_ptr, size_t size, EXCEPTION_RECORD *rec ) -{ - char *stack = stack_ptr; - struct thread_stack_info stack_info; - - if (!is_inside_thread_stack( stack, &stack_info )) - { - if (is_inside_signal_stack( stack )) - { - ERR( "nested exception on signal stack addr %p stack %p\n", rec->ExceptionAddress, stack ); - abort_thread(1); - } - WARN( "exception outside of stack limits addr %p stack %p (%p-%p-%p)\n", - rec->ExceptionAddress, stack, NtCurrentTeb()->DeallocationStack, - NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); - return stack - size; - } - - stack -= size; - - if (stack < stack_info.start + 4096) - { - /* stack overflow on last page, unrecoverable */ - UINT diff = stack_info.start + 4096 - stack; - ERR( "stack overflow %u bytes addr %p stack %p (%p-%p-%p)\n", - diff, rec->ExceptionAddress, stack, stack_info.start, stack_info.limit, stack_info.end ); - abort_thread(1); - } - else if (stack < stack_info.limit) - { - mutex_lock( &virtual_mutex ); /* no need for signal masking inside signal handler */ - if ((get_page_vprot( stack ) & VPROT_GUARD) && - grow_thread_stack( ROUND_ADDR( stack, page_mask ), &stack_info )) - { - rec->ExceptionCode = STATUS_STACK_OVERFLOW; - rec->NumberParameters = 0; - } - mutex_unlock( &virtual_mutex ); - } +void *virtual_setup_exception(void *stack_ptr, size_t size, + EXCEPTION_RECORD *rec) { + char *stack = stack_ptr; + struct thread_stack_info stack_info; + + if (!is_inside_thread_stack(stack, &stack_info)) { + if (is_inside_signal_stack(stack)) { + ERR("nested exception on signal stack addr %p stack %p\n", + rec->ExceptionAddress, stack); + abort_thread(1); + } + WARN("exception outside of stack limits addr %p stack %p (%p-%p-%p)\n", + rec->ExceptionAddress, stack, NtCurrentTeb()->DeallocationStack, + NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase); + return stack - size; + } + + stack -= size; + + if (stack < stack_info.start + 4096) { + /* stack overflow on last page, unrecoverable */ + UINT diff = stack_info.start + 4096 - stack; + ERR("stack overflow %u bytes addr %p stack %p (%p-%p-%p)\n", diff, + rec->ExceptionAddress, stack, stack_info.start, stack_info.limit, + stack_info.end); + abort_thread(1); + } else if (stack < stack_info.limit) { + mutex_lock( + &virtual_mutex); /* no need for signal masking inside signal handler */ + if ((get_page_vprot(stack) & VPROT_GUARD) && + grow_thread_stack(ROUND_ADDR(stack, page_mask), &stack_info)) { + rec->ExceptionCode = STATUS_STACK_OVERFLOW; + rec->NumberParameters = 0; + } + mutex_unlock(&virtual_mutex); + } #if defined(VALGRIND_MAKE_MEM_UNDEFINED) - VALGRIND_MAKE_MEM_UNDEFINED( stack, size ); + VALGRIND_MAKE_MEM_UNDEFINED(stack, size); #elif defined(VALGRIND_MAKE_WRITABLE) - VALGRIND_MAKE_WRITABLE( stack, size ); + VALGRIND_MAKE_WRITABLE(stack, size); #endif - return stack; + return stack; } - /*********************************************************************** * check_write_access * - * Check if the memory range is writable, temporarily disabling write watches if necessary. + * Check if the memory range is writable, temporarily disabling write watches if + * necessary. */ -static NTSTATUS check_write_access( void *base, size_t size, BOOL *has_write_watch ) -{ - size_t i; - char *addr = ROUND_ADDR( base, page_mask ); +static NTSTATUS check_write_access(void *base, size_t size, + BOOL *has_write_watch) { + size_t i; + char *addr = ROUND_ADDR(base, page_mask); - size = ROUND_SIZE( base, size ); - for (i = 0; i < size; i += page_size) - { - BYTE vprot = get_page_vprot( addr + i ); - if (vprot & VPROT_WRITEWATCH) *has_write_watch = TRUE; - if (!(get_unix_prot( vprot & ~VPROT_WRITEWATCH ) & PROT_WRITE)) - return STATUS_INVALID_USER_BUFFER; - } - if (*has_write_watch) - mprotect_range( addr, size, 0, VPROT_WRITEWATCH ); /* temporarily enable write access */ - return STATUS_SUCCESS; + size = ROUND_SIZE(base, size); + for (i = 0; i < size; i += page_size) { + BYTE vprot = get_page_vprot(addr + i); + if (vprot & VPROT_WRITEWATCH) + *has_write_watch = TRUE; + if (!(get_unix_prot(vprot & ~VPROT_WRITEWATCH) & PROT_WRITE)) + return STATUS_INVALID_USER_BUFFER; + } + if (*has_write_watch) + mprotect_range(addr, size, 0, + VPROT_WRITEWATCH); /* temporarily enable write access */ + return STATUS_SUCCESS; } - /*********************************************************************** * virtual_locked_server_call */ -unsigned int virtual_locked_server_call( void *req_ptr ) -{ - struct __server_request_info * const req = req_ptr; - sigset_t sigset; - void *addr = req->reply_data; - data_size_t size = req->u.req.request_header.reply_size; - BOOL has_write_watch = FALSE; - unsigned int ret = STATUS_ACCESS_VIOLATION; +unsigned int virtual_locked_server_call(void *req_ptr) { + struct __server_request_info *const req = req_ptr; + sigset_t sigset; + void *addr = req->reply_data; + data_size_t size = req->u.req.request_header.reply_size; + BOOL has_write_watch = FALSE; + unsigned int ret = STATUS_ACCESS_VIOLATION; - if (!size) return wine_server_call( req_ptr ); + if (!size) + return wine_server_call(req_ptr); - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if (!(ret = check_write_access( addr, size, &has_write_watch ))) - { - ret = server_call_unlocked( req ); - if (has_write_watch) update_write_watches( addr, size, wine_server_reply_size( req )); - } - else memset( &req->u.reply, 0, sizeof(req->u.reply) ); - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return ret; + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + if (!(ret = check_write_access(addr, size, &has_write_watch))) { + ret = server_call_unlocked(req); + if (has_write_watch) + update_write_watches(addr, size, wine_server_reply_size(req)); + } else + memset(&req->u.reply, 0, sizeof(req->u.reply)); + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return ret; } - /*********************************************************************** * virtual_locked_read */ -ssize_t virtual_locked_read( int fd, void *addr, size_t size ) -{ - sigset_t sigset; - BOOL has_write_watch = FALSE; - int err = EFAULT; - - ssize_t ret = read( fd, addr, size ); - if (ret != -1 || errno != EFAULT) return ret; +ssize_t virtual_locked_read(int fd, void *addr, size_t size) { + sigset_t sigset; + BOOL has_write_watch = FALSE; + int err = EFAULT; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if (!check_write_access( addr, size, &has_write_watch )) - { - ret = read( fd, addr, size ); - err = errno; - if (has_write_watch) update_write_watches( addr, size, max( 0, ret )); - } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - errno = err; + ssize_t ret = read(fd, addr, size); + if (ret != -1 || errno != EFAULT) return ret; -} + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + if (!check_write_access(addr, size, &has_write_watch)) { + ret = read(fd, addr, size); + err = errno; + if (has_write_watch) + update_write_watches(addr, size, max(0, ret)); + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + errno = err; + return ret; +} /*********************************************************************** * virtual_locked_pread */ -ssize_t virtual_locked_pread( int fd, void *addr, size_t size, off_t offset ) -{ - sigset_t sigset; - BOOL has_write_watch = FALSE; - int err = EFAULT; - - ssize_t ret = pread( fd, addr, size, offset ); - if (ret != -1 || errno != EFAULT) return ret; +ssize_t virtual_locked_pread(int fd, void *addr, size_t size, off_t offset) { + sigset_t sigset; + BOOL has_write_watch = FALSE; + int err = EFAULT; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if (!check_write_access( addr, size, &has_write_watch )) - { - ret = pread( fd, addr, size, offset ); - err = errno; - if (has_write_watch) update_write_watches( addr, size, max( 0, ret )); - } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - errno = err; + ssize_t ret = pread(fd, addr, size, offset); + if (ret != -1 || errno != EFAULT) return ret; -} + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + if (!check_write_access(addr, size, &has_write_watch)) { + ret = pread(fd, addr, size, offset); + err = errno; + if (has_write_watch) + update_write_watches(addr, size, max(0, ret)); + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + errno = err; + return ret; +} /*********************************************************************** * virtual_locked_recvmsg */ -ssize_t virtual_locked_recvmsg( int fd, struct msghdr *hdr, int flags ) -{ - sigset_t sigset; - size_t i; - BOOL has_write_watch = FALSE; - int err = EFAULT; +ssize_t virtual_locked_recvmsg(int fd, struct msghdr *hdr, int flags) { + sigset_t sigset; + size_t i; + BOOL has_write_watch = FALSE; + int err = EFAULT; - ssize_t ret = recvmsg( fd, hdr, flags ); - if (ret != -1 || errno != EFAULT) return ret; + ssize_t ret = recvmsg(fd, hdr, flags); + if (ret != -1 || errno != EFAULT) + return ret; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - for (i = 0; i < hdr->msg_iovlen; i++) - if (check_write_access( hdr->msg_iov[i].iov_base, hdr->msg_iov[i].iov_len, &has_write_watch )) - break; - if (i == hdr->msg_iovlen) - { - ret = recvmsg( fd, hdr, flags ); - err = errno; - } - if (has_write_watch) - while (i--) update_write_watches( hdr->msg_iov[i].iov_base, hdr->msg_iov[i].iov_len, 0 ); + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + for (i = 0; i < hdr->msg_iovlen; i++) + if (check_write_access(hdr->msg_iov[i].iov_base, hdr->msg_iov[i].iov_len, + &has_write_watch)) + break; + if (i == hdr->msg_iovlen) { + ret = recvmsg(fd, hdr, flags); + err = errno; + } + if (has_write_watch) + while (i--) + update_write_watches(hdr->msg_iov[i].iov_base, hdr->msg_iov[i].iov_len, + 0); - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - errno = err; - return ret; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + errno = err; + return ret; } - /*********************************************************************** * virtual_is_valid_code_address */ -BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size ) -{ - struct file_view *view; - BOOL ret = FALSE; - sigset_t sigset; +BOOL virtual_is_valid_code_address(const void *addr, SIZE_T size) { + struct file_view *view; + BOOL ret = FALSE; + sigset_t sigset; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if ((view = find_view( addr, size ))) - ret = !(view->protect & VPROT_SYSTEM); /* system views are not visible to the app */ - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return ret; + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + if ((view = find_view(addr, size))) + ret = !(view->protect & + VPROT_SYSTEM); /* system views are not visible to the app */ + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return ret; } - /*********************************************************************** * virtual_check_buffer_for_read * - * Check if a memory buffer can be read, triggering page faults if needed for DIB section access. + * Check if a memory buffer can be read, triggering page faults if needed for + * DIB section access. */ -BOOL virtual_check_buffer_for_read( const void *ptr, SIZE_T size ) -{ - if (!size) return TRUE; - if (!ptr) return FALSE; +BOOL virtual_check_buffer_for_read(const void *ptr, SIZE_T size) { + if (!size) + return TRUE; + if (!ptr) + return FALSE; - __TRY - { - volatile const char *p = ptr; - char dummy __attribute__((unused)); - SIZE_T count = size; - - while (count > page_size) - { - dummy = *p; - p += page_size; - count -= page_size; - } - dummy = p[0]; - dummy = p[count - 1]; - } - __EXCEPT - { - return FALSE; + __TRY { + volatile const char *p = ptr; + char dummy __attribute__((unused)); + SIZE_T count = size; + + while (count > page_size) { + dummy = *p; + p += page_size; + count -= page_size; } - __ENDTRY - return TRUE; + dummy = p[0]; + dummy = p[count - 1]; + } + __EXCEPT { return FALSE; } + __ENDTRY + return TRUE; } - /*********************************************************************** * virtual_check_buffer_for_write * - * Check if a memory buffer can be written to, triggering page faults if needed for write watches. + * Check if a memory buffer can be written to, triggering page faults if needed + * for write watches. */ -BOOL virtual_check_buffer_for_write( void *ptr, SIZE_T size ) -{ - if (!size) return TRUE; - if (!ptr) return FALSE; +BOOL virtual_check_buffer_for_write(void *ptr, SIZE_T size) { + if (!size) + return TRUE; + if (!ptr) + return FALSE; - __TRY - { - volatile char *p = ptr; - SIZE_T count = size; - - while (count > page_size) - { - *p |= 0; - p += page_size; - count -= page_size; - } - p[0] |= 0; - p[count - 1] |= 0; - } - __EXCEPT - { - return FALSE; + __TRY { + volatile char *p = ptr; + SIZE_T count = size; + + while (count > page_size) { + *p |= 0; + p += page_size; + count -= page_size; } - __ENDTRY - return TRUE; + p[0] |= 0; + p[count - 1] |= 0; + } + __EXCEPT { return FALSE; } + __ENDTRY + return TRUE; } - /*********************************************************************** * virtual_uninterrupted_read_memory * @@ -4355,35 +4380,34 @@ BOOL virtual_check_buffer_for_write( void *ptr, SIZE_T size ) * permissions are checked before accessing each page, to ensure that no * exceptions can happen. */ -SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size ) -{ - struct file_view *view; - sigset_t sigset; - SIZE_T bytes_read = 0; +SIZE_T virtual_uninterrupted_read_memory(const void *addr, void *buffer, + SIZE_T size) { + struct file_view *view; + sigset_t sigset; + SIZE_T bytes_read = 0; - if (!size) return 0; + if (!size) + return 0; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if ((view = find_view( addr, size ))) - { - if (!(view->protect & VPROT_SYSTEM)) - { - while (bytes_read < size && (get_unix_prot( get_page_vprot( addr )) & PROT_READ)) - { - SIZE_T block_size = min( size - bytes_read, page_size - ((UINT_PTR)addr & page_mask) ); - memcpy( buffer, addr, block_size ); - - addr = (const void *)((const char *)addr + block_size); - buffer = (void *)((char *)buffer + block_size); - bytes_read += block_size; - } - } + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + if ((view = find_view(addr, size))) { + if (!(view->protect & VPROT_SYSTEM)) { + while (bytes_read < size && + (get_unix_prot(get_page_vprot(addr)) & PROT_READ)) { + SIZE_T block_size = + min(size - bytes_read, page_size - ((UINT_PTR)addr & page_mask)); + memcpy(buffer, addr, block_size); + + addr = (const void *)((const char *)addr + block_size); + buffer = (void *)((char *)buffer + block_size); + bytes_read += block_size; + } } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return bytes_read; + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return bytes_read; } - /*********************************************************************** * virtual_uninterrupted_write_memory * @@ -4391,96 +4415,93 @@ SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T * permissions are checked before accessing each page, to ensure that no * exceptions can happen. */ -NTSTATUS virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size ) -{ - BOOL has_write_watch = FALSE; - sigset_t sigset; - NTSTATUS ret; +NTSTATUS virtual_uninterrupted_write_memory(void *addr, const void *buffer, + SIZE_T size) { + BOOL has_write_watch = FALSE; + sigset_t sigset; + NTSTATUS ret; - if (!size) return STATUS_SUCCESS; + if (!size) + return STATUS_SUCCESS; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if (!(ret = check_write_access( addr, size, &has_write_watch ))) - { - memcpy( addr, buffer, size ); - if (has_write_watch) update_write_watches( addr, size, size ); - } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return ret; + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + if (!(ret = check_write_access(addr, size, &has_write_watch))) { + memcpy(addr, buffer, size); + if (has_write_watch) + update_write_watches(addr, size, size); + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return ret; } - /*********************************************************************** * virtual_set_force_exec * * Whether to force exec prot on all views. */ -void virtual_set_force_exec( BOOL enable ) -{ - struct file_view *view; - sigset_t sigset; +void virtual_set_force_exec(BOOL enable) { + struct file_view *view; + sigset_t sigset; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if (!force_exec_prot != !enable) /* change all existing views */ - { - force_exec_prot = enable; + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + if (!force_exec_prot != !enable) /* change all existing views */ + { + force_exec_prot = enable; - WINE_RB_FOR_EACH_ENTRY( view, &views_tree, struct file_view, entry ) - { - /* file mappings are always accessible */ - BYTE commit = is_view_valloc( view ) ? 0 : VPROT_COMMITTED; + WINE_RB_FOR_EACH_ENTRY(view, &views_tree, struct file_view, entry) { + /* file mappings are always accessible */ + BYTE commit = is_view_valloc(view) ? 0 : VPROT_COMMITTED; - mprotect_range( view->base, view->size, commit, 0 ); - } + mprotect_range(view->base, view->size, commit, 0); } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); } - /*********************************************************************** * virtual_manage_exec_writes */ -void virtual_enable_write_exceptions( BOOL enable ) -{ - struct file_view *view; - sigset_t sigset; +void virtual_enable_write_exceptions(BOOL enable) { + struct file_view *view; + sigset_t sigset; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if (!enable_write_exceptions && enable) /* change all existing views */ - { - WINE_RB_FOR_EACH_ENTRY( view, &views_tree, struct file_view, entry ) - if (set_page_vprot_exec_write_protect( view->base, view->size )) - mprotect_range( view->base, view->size, 0, 0 ); - } - enable_write_exceptions = enable; - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + if (!enable_write_exceptions && enable) /* change all existing views */ + { + WINE_RB_FOR_EACH_ENTRY(view, &views_tree, struct file_view, entry) + if (set_page_vprot_exec_write_protect(view->base, view->size)) + mprotect_range(view->base, view->size, 0, 0); + } + enable_write_exceptions = enable; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); } - /* free reserved areas within a given range */ -static void free_reserved_memory( char *base, char *limit ) -{ - struct reserved_area *area; +static void free_reserved_memory(char *base, char *limit) { + struct reserved_area *area; - for (;;) - { - int removed = 0; - - LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) - { - char *area_base = area->base; - char *area_end = area_base + area->size; - - if (area_end <= base) continue; - if (area_base >= limit) return; - if (area_base < base) area_base = base; - if (area_end > limit) area_end = limit; - remove_reserved_area( area_base, (char *)area_end - (char *)area_base ); - removed = 1; - break; - } - if (!removed) return; + for (;;) { + int removed = 0; + + LIST_FOR_EACH_ENTRY(area, &reserved_areas, struct reserved_area, entry) { + char *area_base = area->base; + char *area_end = area_base + area->size; + + if (area_end <= base) + continue; + if (area_base >= limit) + return; + if (area_base < base) + area_base = base; + if (area_end > limit) + area_end = limit; + remove_reserved_area(area_base, (char *)area_end - (char *)area_base); + removed = 1; + break; } + if (!removed) + return; + } } #ifndef _WIN64 @@ -4490,1386 +4511,1411 @@ static void free_reserved_memory( char *base, char *limit ) * * Release some address space once we have loaded and initialized the app. */ -static void virtual_release_address_space(void) -{ -#ifndef __APPLE__ /* On macOS, we still want to free some of low memory, for OpenGL resources */ - if (user_space_limit > (void *)limit_2g) return; +static void virtual_release_address_space(void) { +#ifndef __APPLE__ /* On macOS, we still want to free some of low memory, for \ + OpenGL resources */ + if (user_space_limit > (void *)limit_2g) + return; #endif - free_reserved_memory( (char *)0x20000000, (char *)0x7f000000 ); + free_reserved_memory((char *)0x20000000, (char *)0x7f000000); } -#endif /* _WIN64 */ - +#endif /* _WIN64 */ /*********************************************************************** * virtual_set_large_address_space * * Enable use of a large address space when allowed by the application. */ -void virtual_set_large_address_space(void) -{ - if (is_win64) - { - if (is_wow64()) - user_space_wow_limit = ((main_image_info.ImageCharacteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) ? limit_4g : limit_2g) - 1; -#ifndef __APPLE__ /* don't free the zerofill section on macOS */ - else if ((main_image_info.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) && - (main_image_info.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)) - free_reserved_memory( 0, (char *)0x7ffe0000 ); +void virtual_set_large_address_space(void) { + if (is_win64) { + if (is_wow64()) + user_space_wow_limit = ((main_image_info.ImageCharacteristics & + IMAGE_FILE_LARGE_ADDRESS_AWARE) + ? limit_4g + : limit_2g) - + 1; +#ifndef __APPLE__ /* don't free the zerofill section on macOS */ + else if ((main_image_info.DllCharacteristics & + IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) && + (main_image_info.DllCharacteristics & + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)) + free_reserved_memory(0, (char *)0x7ffe0000); #endif - } - else - { - if (!(main_image_info.ImageCharacteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)) return; - free_reserved_memory( (char *)0x80000000, address_space_limit ); - } - user_space_limit = working_set_limit = address_space_limit; + } else { + if (!(main_image_info.ImageCharacteristics & + IMAGE_FILE_LARGE_ADDRESS_AWARE)) + return; + free_reserved_memory((char *)0x80000000, address_space_limit); + } + user_space_limit = working_set_limit = address_space_limit; } - /*********************************************************************** * allocate_virtual_memory * * NtAllocateVirtualMemory[Ex] implementation. */ -static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG type, ULONG protect, - ULONG_PTR limit_low, ULONG_PTR limit_high, - ULONG_PTR align, ULONG attributes ) -{ - void *base; - unsigned int vprot; - BOOL is_dos_memory = FALSE; - struct file_view *view; - sigset_t sigset; - SIZE_T size = *size_ptr; - NTSTATUS status = STATUS_SUCCESS; - - /* Round parameters to a page boundary */ - - if (is_beyond_limit( 0, size, working_set_limit )) return STATUS_WORKING_SET_LIMIT_RANGE; - - if (*ret) - { - if (type & MEM_RESERVE && !(type & MEM_REPLACE_PLACEHOLDER)) /* Round down to 64k boundary */ - base = ROUND_ADDR( *ret, granularity_mask ); - else - base = ROUND_ADDR( *ret, page_mask ); - size = (((UINT_PTR)*ret + size + page_mask) & ~page_mask) - (UINT_PTR)base; - - /* disallow low 64k, wrap-around and kernel space */ - if (((char *)base < (char *)0x10000) || - ((char *)base + size < (char *)base) || - is_beyond_limit( base, size, address_space_limit )) - { - /* address 1 is magic to mean DOS area */ - if (!base && *ret == (void *)1 && size == 0x110000) is_dos_memory = TRUE; - else return STATUS_INVALID_PARAMETER; - } - } +static NTSTATUS allocate_virtual_memory(void **ret, SIZE_T *size_ptr, + ULONG type, ULONG protect, + ULONG_PTR limit_low, + ULONG_PTR limit_high, ULONG_PTR align, + ULONG attributes) { + void *base; + unsigned int vprot; + BOOL is_dos_memory = FALSE; + struct file_view *view; + sigset_t sigset; + SIZE_T size = *size_ptr; + NTSTATUS status = STATUS_SUCCESS; + + /* Round parameters to a page boundary */ + + if (is_beyond_limit(0, size, working_set_limit)) + return STATUS_WORKING_SET_LIMIT_RANGE; + + if (*ret) { + if (type & MEM_RESERVE && + !(type & MEM_REPLACE_PLACEHOLDER)) /* Round down to 64k boundary */ + base = ROUND_ADDR(*ret, granularity_mask); else - { - base = NULL; - size = (size + page_mask) & ~page_mask; - } - - /* Compute the alloc type flags */ - - if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)) - || (type & MEM_REPLACE_PLACEHOLDER && !(type & MEM_RESERVE))) - { - WARN("called with wrong alloc type flags (%08x) !\n", (int)type); + base = ROUND_ADDR(*ret, page_mask); + size = (((UINT_PTR)*ret + size + page_mask) & ~page_mask) - (UINT_PTR)base; + + /* disallow low 64k, wrap-around and kernel space */ + if (((char *)base < (char *)0x10000) || + ((char *)base + size < (char *)base) || + is_beyond_limit(base, size, address_space_limit)) { + /* address 1 is magic to mean DOS area */ + if (!base && *ret == (void *)1 && size == 0x110000) + is_dos_memory = TRUE; + else return STATUS_INVALID_PARAMETER; } - - if (type & MEM_RESERVE_PLACEHOLDER && (protect != PAGE_NOACCESS)) return STATUS_INVALID_PARAMETER; - if (!arm64ec_view && (attributes & MEM_EXTENDED_PARAMETER_EC_CODE)) return STATUS_INVALID_PARAMETER; - - /* Reserve the memory */ - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - - if ((type & MEM_RESERVE) || !base) - { - if (!(status = get_vprot_flags( protect, &vprot, FALSE ))) - { - if (type & MEM_COMMIT) vprot |= VPROT_COMMITTED; - if (type & MEM_WRITE_WATCH) vprot |= VPROT_WRITEWATCH; - if (type & MEM_RESERVE_PLACEHOLDER) vprot |= VPROT_PLACEHOLDER | VPROT_FREE_PLACEHOLDER; - if (protect & PAGE_NOCACHE) vprot |= SEC_NOCACHE; - - if (vprot & VPROT_WRITECOPY) status = STATUS_INVALID_PAGE_PROTECTION; - else if (is_dos_memory) status = allocate_dos_memory( &view, vprot ); - else status = map_view( &view, base, size, type, vprot, limit_low, limit_high, - align ? align - 1 : granularity_mask ); - - if (status == STATUS_SUCCESS) base = view->base; - } - } - else if (type & MEM_RESET) - { - if (!(view = find_view( base, size ))) status = STATUS_NOT_MAPPED_VIEW; - else madvise( base, size, MADV_DONTNEED ); - } - else /* commit the pages */ - { - if (!(view = find_view( base, size ))) status = STATUS_NOT_MAPPED_VIEW; - else if (view->protect & SEC_FILE) status = STATUS_ALREADY_COMMITTED; - else if (view->protect & VPROT_FREE_PLACEHOLDER) status = STATUS_CONFLICTING_ADDRESSES; - else if (!(status = set_protection( view, base, size, protect )) && (view->protect & SEC_RESERVE)) - { - SERVER_START_REQ( add_mapping_committed_range ) - { - req->base = wine_server_client_ptr( view->base ); - req->offset = (char *)base - (char *)view->base; - req->size = size; - wine_server_call( req ); - } - SERVER_END_REQ; - } + } else { + base = NULL; + size = (size + page_mask) & ~page_mask; + } + + /* Compute the alloc type flags */ + + if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)) || + (type & MEM_REPLACE_PLACEHOLDER && !(type & MEM_RESERVE))) { + WARN("called with wrong alloc type flags (%08x) !\n", (int)type); + return STATUS_INVALID_PARAMETER; + } + + if (type & MEM_RESERVE_PLACEHOLDER && (protect != PAGE_NOACCESS)) + return STATUS_INVALID_PARAMETER; + if (!arm64ec_view && (attributes & MEM_EXTENDED_PARAMETER_EC_CODE)) + return STATUS_INVALID_PARAMETER; + + /* Reserve the memory */ + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + + if ((type & MEM_RESERVE) || !base) { + if (!(status = get_vprot_flags(protect, &vprot, FALSE))) { + if (type & MEM_COMMIT) + vprot |= VPROT_COMMITTED; + if (type & MEM_WRITE_WATCH) + vprot |= VPROT_WRITEWATCH; + if (type & MEM_RESERVE_PLACEHOLDER) + vprot |= VPROT_PLACEHOLDER | VPROT_FREE_PLACEHOLDER; + if (protect & PAGE_NOCACHE) + vprot |= SEC_NOCACHE; + + if (vprot & VPROT_WRITECOPY) + status = STATUS_INVALID_PAGE_PROTECTION; + else if (is_dos_memory) + status = allocate_dos_memory(&view, vprot); + else + status = map_view(&view, base, size, type, vprot, limit_low, limit_high, + align ? align - 1 : granularity_mask); + + if (status == STATUS_SUCCESS) + base = view->base; + } + } else if (type & MEM_RESET) { + if (!(view = find_view(base, size))) + status = STATUS_NOT_MAPPED_VIEW; + else + madvise(base, size, MADV_DONTNEED); + } else /* commit the pages */ + { + if (!(view = find_view(base, size))) + status = STATUS_NOT_MAPPED_VIEW; + else if (view->protect & SEC_FILE) + status = STATUS_ALREADY_COMMITTED; + else if (view->protect & VPROT_FREE_PLACEHOLDER) + status = STATUS_CONFLICTING_ADDRESSES; + else if (!(status = set_protection(view, base, size, protect)) && + (view->protect & SEC_RESERVE)) { + SERVER_START_REQ(add_mapping_committed_range) { + req->base = wine_server_client_ptr(view->base); + req->offset = (char *)base - (char *)view->base; + req->size = size; + wine_server_call(req); + } + SERVER_END_REQ; } + } - if (!status && (attributes & MEM_EXTENDED_PARAMETER_EC_CODE)) - { - commit_arm64ec_map( view ); - set_arm64ec_range( base, size ); - } + if (!status && (attributes & MEM_EXTENDED_PARAMETER_EC_CODE)) { + commit_arm64ec_map(view); + set_arm64ec_range(base, size); + } - if (!status) VIRTUAL_DEBUG_DUMP_VIEW( view ); + if (!status) + VIRTUAL_DEBUG_DUMP_VIEW(view); - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); + server_leave_uninterrupted_section(&virtual_mutex, &sigset); - if (status == STATUS_SUCCESS) - { - *ret = base; - *size_ptr = size; - } - else if (status == STATUS_NO_MEMORY) - ERR( "out of memory for allocation, base %p size %08lx\n", base, size ); + if (status == STATUS_SUCCESS) { + *ret = base; + *size_ptr = size; + } else if (status == STATUS_NO_MEMORY) + ERR("out of memory for allocation, base %p size %08lx\n", base, size); - return status; + return status; } - /*********************************************************************** * NtAllocateVirtualMemory (NTDLL.@) * ZwAllocateVirtualMemory (NTDLL.@) */ -NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR zero_bits, - SIZE_T *size_ptr, ULONG type, ULONG protect ) -{ - static const ULONG type_mask = MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH | MEM_RESET; - ULONG_PTR limit; - - TRACE("%p %p %08lx %x %08x\n", process, *ret, *size_ptr, (int)type, (int)protect ); - - if (!*size_ptr) return STATUS_INVALID_PARAMETER; - if (zero_bits > 21 && zero_bits < 32) return STATUS_INVALID_PARAMETER_3; - if (zero_bits > 32 && zero_bits < granularity_mask) return STATUS_INVALID_PARAMETER_3; +NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE process, PVOID *ret, + ULONG_PTR zero_bits, SIZE_T *size_ptr, + ULONG type, ULONG protect) { + static const ULONG type_mask = + MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH | MEM_RESET; + ULONG_PTR limit; + + TRACE("%p %p %08lx %x %08x\n", process, *ret, *size_ptr, (int)type, + (int)protect); + + if (!*size_ptr) + return STATUS_INVALID_PARAMETER; + if (zero_bits > 21 && zero_bits < 32) + return STATUS_INVALID_PARAMETER_3; + if (zero_bits > 32 && zero_bits < granularity_mask) + return STATUS_INVALID_PARAMETER_3; #ifndef _WIN64 - if (!is_old_wow64() && zero_bits >= 32) return STATUS_INVALID_PARAMETER_3; + if (!is_old_wow64() && zero_bits >= 32) + return STATUS_INVALID_PARAMETER_3; #endif - if (type & ~type_mask) return STATUS_INVALID_PARAMETER; + if (type & ~type_mask) + return STATUS_INVALID_PARAMETER; - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; - unsigned int status; - - memset( &call, 0, sizeof(call) ); - - call.virtual_alloc.type = APC_VIRTUAL_ALLOC; - call.virtual_alloc.addr = wine_server_client_ptr( *ret ); - call.virtual_alloc.size = *size_ptr; - call.virtual_alloc.zero_bits = zero_bits; - call.virtual_alloc.op_type = type; - call.virtual_alloc.prot = protect; - status = server_queue_process_apc( process, &call, &result ); - if (status != STATUS_SUCCESS) return status; - - if (result.virtual_alloc.status == STATUS_SUCCESS) - { - *ret = wine_server_get_ptr( result.virtual_alloc.addr ); - *size_ptr = result.virtual_alloc.size; + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; + unsigned int status; + + memset(&call, 0, sizeof(call)); + + call.virtual_alloc.type = APC_VIRTUAL_ALLOC; + call.virtual_alloc.addr = wine_server_client_ptr(*ret); + call.virtual_alloc.size = *size_ptr; + call.virtual_alloc.zero_bits = zero_bits; + call.virtual_alloc.op_type = type; + call.virtual_alloc.prot = protect; + status = server_queue_process_apc(process, &call, &result); + if (status != STATUS_SUCCESS) + return status; + + if (result.virtual_alloc.status == STATUS_SUCCESS) { + *ret = wine_server_get_ptr(result.virtual_alloc.addr); + *size_ptr = result.virtual_alloc.size; + } else { + WARN("cross-process allocation failed, process=%p base=%p size=%08lx " + "status=%08x", + process, *ret, *size_ptr, result.virtual_alloc.status); + } + return result.virtual_alloc.status; + } + + if (!*ret) + limit = get_zero_bits_limit(zero_bits); + else + limit = 0; + + return allocate_virtual_memory(ret, size_ptr, type, protect, 0, limit, 0, 0); +} + +static NTSTATUS get_extended_params(const MEM_EXTENDED_PARAMETER *parameters, + ULONG count, ULONG_PTR *limit_low, + ULONG_PTR *limit_high, ULONG_PTR *align, + ULONG *attributes, USHORT *machine) { + ULONG i, present = 0; + + if (count && !parameters) + return STATUS_INVALID_PARAMETER; + + for (i = 0; i < count; ++i) { + if (parameters[i].Type >= 32) + return STATUS_INVALID_PARAMETER; + if (present & (1u << parameters[i].Type)) + return STATUS_INVALID_PARAMETER; + present |= 1u << parameters[i].Type; + + switch (parameters[i].Type) { + case MemExtendedParameterAddressRequirements: { + MEM_ADDRESS_REQUIREMENTS *r = parameters[i].Pointer; + ULONG_PTR limit; + + if (is_wow64()) + limit = get_wow_user_space_limit(); + else + limit = (ULONG_PTR)user_space_limit; + + if (r->Alignment) { + if ((r->Alignment & (r->Alignment - 1)) || + r->Alignment - 1 < granularity_mask) { + WARN("Invalid alignment %lu.\n", r->Alignment); + return STATUS_INVALID_PARAMETER; } - else - { - WARN( "cross-process allocation failed, process=%p base=%p size=%08lx status=%08x", - process, *ret, *size_ptr, result.virtual_alloc.status ); + *align = r->Alignment; + } + if (r->LowestStartingAddress) { + *limit_low = (ULONG_PTR)r->LowestStartingAddress; + if (*limit_low >= limit || (*limit_low & granularity_mask)) { + WARN("Invalid limit %p.\n", r->LowestStartingAddress); + return STATUS_INVALID_PARAMETER; } - return result.virtual_alloc.status; - } - - if (!*ret) - limit = get_zero_bits_limit( zero_bits ); - else - limit = 0; - - return allocate_virtual_memory( ret, size_ptr, type, protect, 0, limit, 0, 0 ); -} - - -static NTSTATUS get_extended_params( const MEM_EXTENDED_PARAMETER *parameters, ULONG count, - ULONG_PTR *limit_low, ULONG_PTR *limit_high, ULONG_PTR *align, - ULONG *attributes, USHORT *machine ) -{ - ULONG i, present = 0; - - if (count && !parameters) return STATUS_INVALID_PARAMETER; - - for (i = 0; i < count; ++i) - { - if (parameters[i].Type >= 32) return STATUS_INVALID_PARAMETER; - if (present & (1u << parameters[i].Type)) return STATUS_INVALID_PARAMETER; - present |= 1u << parameters[i].Type; - - switch (parameters[i].Type) - { - case MemExtendedParameterAddressRequirements: - { - MEM_ADDRESS_REQUIREMENTS *r = parameters[i].Pointer; - ULONG_PTR limit; - - if (is_wow64()) limit = get_wow_user_space_limit(); - else limit = (ULONG_PTR)user_space_limit; - - if (r->Alignment) - { - if ((r->Alignment & (r->Alignment - 1)) || r->Alignment - 1 < granularity_mask) - { - WARN( "Invalid alignment %lu.\n", r->Alignment ); - return STATUS_INVALID_PARAMETER; - } - *align = r->Alignment; - } - if (r->LowestStartingAddress) - { - *limit_low = (ULONG_PTR)r->LowestStartingAddress; - if (*limit_low >= limit || (*limit_low & granularity_mask)) - { - WARN( "Invalid limit %p.\n", r->LowestStartingAddress ); - return STATUS_INVALID_PARAMETER; - } - } - if (r->HighestEndingAddress) - { - *limit_high = (ULONG_PTR)r->HighestEndingAddress; - if (*limit_high > limit || - *limit_high <= *limit_low || - ((*limit_high + 1) & (page_mask - 1))) - { - WARN( "Invalid limit %p.\n", r->HighestEndingAddress ); - return STATUS_INVALID_PARAMETER; - } - } - break; + } + if (r->HighestEndingAddress) { + *limit_high = (ULONG_PTR)r->HighestEndingAddress; + if (*limit_high > limit || *limit_high <= *limit_low || + ((*limit_high + 1) & (page_mask - 1))) { + WARN("Invalid limit %p.\n", r->HighestEndingAddress); + return STATUS_INVALID_PARAMETER; } + } + break; + } - case MemExtendedParameterAttributeFlags: - *attributes = parameters[i].ULong; - break; + case MemExtendedParameterAttributeFlags: + *attributes = parameters[i].ULong; + break; - case MemExtendedParameterImageMachine: - *machine = parameters[i].ULong; - break; + case MemExtendedParameterImageMachine: + *machine = parameters[i].ULong; + break; - case MemExtendedParameterNumaNode: - case MemExtendedParameterPartitionHandle: - case MemExtendedParameterUserPhysicalHandle: - FIXME( "Parameter type %d is not supported.\n", parameters[i].Type ); - break; + case MemExtendedParameterNumaNode: + case MemExtendedParameterPartitionHandle: + case MemExtendedParameterUserPhysicalHandle: + FIXME("Parameter type %d is not supported.\n", parameters[i].Type); + break; - default: - WARN( "Invalid parameter type %u\n", parameters[i].Type ); - return STATUS_INVALID_PARAMETER; - } + default: + WARN("Invalid parameter type %u\n", parameters[i].Type); + return STATUS_INVALID_PARAMETER; } - return STATUS_SUCCESS; + } + return STATUS_SUCCESS; } - /*********************************************************************** * NtAllocateVirtualMemoryEx (NTDLL.@) * ZwAllocateVirtualMemoryEx (NTDLL.@) */ -NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *size_ptr, ULONG type, - ULONG protect, MEM_EXTENDED_PARAMETER *parameters, - ULONG count ) -{ - static const ULONG type_mask = MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH - | MEM_RESET | MEM_RESERVE_PLACEHOLDER | MEM_REPLACE_PLACEHOLDER; - ULONG_PTR limit_low = 0; - ULONG_PTR limit_high = 0; - ULONG_PTR align = 0; - ULONG attributes = 0; - USHORT machine = 0; - unsigned int status; +NTSTATUS WINAPI NtAllocateVirtualMemoryEx(HANDLE process, PVOID *ret, + SIZE_T *size_ptr, ULONG type, + ULONG protect, + MEM_EXTENDED_PARAMETER *parameters, + ULONG count) { + static const ULONG type_mask = + MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH | MEM_RESET | + MEM_RESERVE_PLACEHOLDER | MEM_REPLACE_PLACEHOLDER; + ULONG_PTR limit_low = 0; + ULONG_PTR limit_high = 0; + ULONG_PTR align = 0; + ULONG attributes = 0; + USHORT machine = 0; + unsigned int status; + + TRACE("%p %p %08lx %x %08x %p %u\n", process, *ret, *size_ptr, (int)type, + (int)protect, parameters, (int)count); + + status = get_extended_params(parameters, count, &limit_low, &limit_high, + &align, &attributes, &machine); + if (status) + return status; - TRACE( "%p %p %08lx %x %08x %p %u\n", - process, *ret, *size_ptr, (int)type, (int)protect, parameters, (int)count ); + if (type & ~type_mask) + return STATUS_INVALID_PARAMETER; + if (*ret && (align || limit_low || limit_high)) + return STATUS_INVALID_PARAMETER; + if (!*size_ptr) + return STATUS_INVALID_PARAMETER; - status = get_extended_params( parameters, count, &limit_low, &limit_high, - &align, &attributes, &machine ); - if (status) return status; + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; - if (type & ~type_mask) return STATUS_INVALID_PARAMETER; - if (*ret && (align || limit_low || limit_high)) return STATUS_INVALID_PARAMETER; - if (!*size_ptr) return STATUS_INVALID_PARAMETER; + memset(&call, 0, sizeof(call)); - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; - - memset( &call, 0, sizeof(call) ); - - call.virtual_alloc_ex.type = APC_VIRTUAL_ALLOC_EX; - call.virtual_alloc_ex.addr = wine_server_client_ptr( *ret ); - call.virtual_alloc_ex.size = *size_ptr; - call.virtual_alloc_ex.limit_low = limit_low; - call.virtual_alloc_ex.limit_high = limit_high; - call.virtual_alloc_ex.align = align; - call.virtual_alloc_ex.op_type = type; - call.virtual_alloc_ex.prot = protect; - call.virtual_alloc_ex.attributes = attributes; - status = server_queue_process_apc( process, &call, &result ); - if (status != STATUS_SUCCESS) return status; - - if (result.virtual_alloc_ex.status == STATUS_SUCCESS) - { - *ret = wine_server_get_ptr( result.virtual_alloc_ex.addr ); - *size_ptr = result.virtual_alloc_ex.size; - } - return result.virtual_alloc_ex.status; + call.virtual_alloc_ex.type = APC_VIRTUAL_ALLOC_EX; + call.virtual_alloc_ex.addr = wine_server_client_ptr(*ret); + call.virtual_alloc_ex.size = *size_ptr; + call.virtual_alloc_ex.limit_low = limit_low; + call.virtual_alloc_ex.limit_high = limit_high; + call.virtual_alloc_ex.align = align; + call.virtual_alloc_ex.op_type = type; + call.virtual_alloc_ex.prot = protect; + call.virtual_alloc_ex.attributes = attributes; + status = server_queue_process_apc(process, &call, &result); + if (status != STATUS_SUCCESS) + return status; + + if (result.virtual_alloc_ex.status == STATUS_SUCCESS) { + *ret = wine_server_get_ptr(result.virtual_alloc_ex.addr); + *size_ptr = result.virtual_alloc_ex.size; } + return result.virtual_alloc_ex.status; + } - return allocate_virtual_memory( ret, size_ptr, type, protect, - limit_low, limit_high, align, attributes ); + return allocate_virtual_memory(ret, size_ptr, type, protect, limit_low, + limit_high, align, attributes); } - /*********************************************************************** * NtFreeVirtualMemory (NTDLL.@) * ZwFreeVirtualMemory (NTDLL.@) */ -NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *size_ptr, ULONG type ) -{ - struct file_view *view; - char *base; - sigset_t sigset; - unsigned int status = STATUS_SUCCESS; - LPVOID addr = *addr_ptr; - SIZE_T size = *size_ptr; +NTSTATUS WINAPI NtFreeVirtualMemory(HANDLE process, PVOID *addr_ptr, + SIZE_T *size_ptr, ULONG type) { + struct file_view *view; + char *base; + sigset_t sigset; + unsigned int status = STATUS_SUCCESS; + LPVOID addr = *addr_ptr; + SIZE_T size = *size_ptr; - TRACE("%p %p %08lx %x\n", process, addr, size, (int)type ); + TRACE("%p %p %08lx %x\n", process, addr, size, (int)type); - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; - - memset( &call, 0, sizeof(call) ); - - call.virtual_free.type = APC_VIRTUAL_FREE; - call.virtual_free.addr = wine_server_client_ptr( addr ); - call.virtual_free.size = size; - call.virtual_free.op_type = type; - status = server_queue_process_apc( process, &call, &result ); - if (status != STATUS_SUCCESS) return status; - - if (result.virtual_free.status == STATUS_SUCCESS) - { - *addr_ptr = wine_server_get_ptr( result.virtual_free.addr ); - *size_ptr = result.virtual_free.size; - } - return result.virtual_free.status; + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; + + memset(&call, 0, sizeof(call)); + + call.virtual_free.type = APC_VIRTUAL_FREE; + call.virtual_free.addr = wine_server_client_ptr(addr); + call.virtual_free.size = size; + call.virtual_free.op_type = type; + status = server_queue_process_apc(process, &call, &result); + if (status != STATUS_SUCCESS) + return status; + + if (result.virtual_free.status == STATUS_SUCCESS) { + *addr_ptr = wine_server_get_ptr(result.virtual_free.addr); + *size_ptr = result.virtual_free.size; } + return result.virtual_free.status; + } - /* Fix the parameters */ + /* Fix the parameters */ - if (size) size = ROUND_SIZE( addr, size ); - base = ROUND_ADDR( addr, page_mask ); + if (size) + size = ROUND_SIZE(addr, size); + base = ROUND_ADDR(addr, page_mask); - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); + server_enter_uninterrupted_section(&virtual_mutex, &sigset); - /* avoid freeing the DOS area when a broken app passes a NULL pointer */ - if (!base) - { + /* avoid freeing the DOS area when a broken app passes a NULL pointer */ + if (!base) { #ifndef _WIN64 - /* address 1 is magic to mean release reserved space */ - if (addr == (void *)1 && !size && type == MEM_RELEASE) virtual_release_address_space(); - else + /* address 1 is magic to mean release reserved space */ + if (addr == (void *)1 && !size && type == MEM_RELEASE) + virtual_release_address_space(); + else #endif - status = STATUS_INVALID_PARAMETER; - } - else if (!(view = find_view( base, 0 ))) status = STATUS_MEMORY_NOT_ALLOCATED; - else if (!is_view_valloc( view )) status = STATUS_INVALID_PARAMETER; - else if (!size && base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE; - else if ((char *)view->base + view->size - base < size && !(type & MEM_COALESCE_PLACEHOLDERS)) - status = STATUS_UNABLE_TO_FREE_VM; - else switch (type) - { + status = STATUS_INVALID_PARAMETER; + } else if (!(view = find_view(base, 0))) + status = STATUS_MEMORY_NOT_ALLOCATED; + else if (!is_view_valloc(view)) + status = STATUS_INVALID_PARAMETER; + else if (!size && base != view->base) + status = STATUS_FREE_VM_NOT_AT_BASE; + else if ((char *)view->base + view->size - base < size && + !(type & MEM_COALESCE_PLACEHOLDERS)) + status = STATUS_UNABLE_TO_FREE_VM; + else + switch (type) { case MEM_DECOMMIT: - status = decommit_pages( view, base - (char *)view->base, size ); - break; + status = decommit_pages(view, base - (char *)view->base, size); + break; case MEM_RELEASE: - if (!size) size = view->size; - status = free_pages( view, base, size ); - break; + if (!size) + size = view->size; + status = free_pages(view, base, size); + break; case MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER: - status = free_pages_preserve_placeholder( view, base, size ); - break; + status = free_pages_preserve_placeholder(view, base, size); + break; case MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS: - status = coalesce_placeholders( view, base, size ); - break; + status = coalesce_placeholders(view, base, size); + break; case MEM_COALESCE_PLACEHOLDERS: - status = STATUS_INVALID_PARAMETER_4; - break; + status = STATUS_INVALID_PARAMETER_4; + break; default: - status = STATUS_INVALID_PARAMETER; - break; + status = STATUS_INVALID_PARAMETER; + break; } - if (status == STATUS_SUCCESS) - { - *addr_ptr = base; - *size_ptr = size; - } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return status; + if (status == STATUS_SUCCESS) { + *addr_ptr = base; + *size_ptr = size; + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return status; } - /*********************************************************************** * NtProtectVirtualMemory (NTDLL.@) * ZwProtectVirtualMemory (NTDLL.@) */ -NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *size_ptr, - ULONG new_prot, ULONG *old_prot ) -{ - struct file_view *view; - sigset_t sigset; - unsigned int status = STATUS_SUCCESS; - char *base; - BYTE vprot; - SIZE_T size = *size_ptr; - LPVOID addr = *addr_ptr; - DWORD old; - - TRACE("%p %p %08lx %08x\n", process, addr, size, (int)new_prot ); - - if (!old_prot) - return STATUS_ACCESS_VIOLATION; - - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; - - memset( &call, 0, sizeof(call) ); - - call.virtual_protect.type = APC_VIRTUAL_PROTECT; - call.virtual_protect.addr = wine_server_client_ptr( addr ); - call.virtual_protect.size = size; - call.virtual_protect.prot = new_prot; - status = server_queue_process_apc( process, &call, &result ); - if (status != STATUS_SUCCESS) return status; - - if (result.virtual_protect.status == STATUS_SUCCESS) - { - *addr_ptr = wine_server_get_ptr( result.virtual_protect.addr ); - *size_ptr = result.virtual_protect.size; - *old_prot = result.virtual_protect.prot; - } - return result.virtual_protect.status; - } - - /* Fix the parameters */ - - size = ROUND_SIZE( addr, size ); - base = ROUND_ADDR( addr, page_mask ); - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - - if ((view = find_view( base, size ))) - { - /* Make sure all the pages are committed */ - if (get_committed_size( view, base, ~(size_t)0, &vprot, VPROT_COMMITTED ) >= size && (vprot & VPROT_COMMITTED)) - { - old = get_win32_prot( vprot, view->protect ); - status = set_protection( view, base, size, new_prot ); - } - else status = STATUS_NOT_COMMITTED; - } - else status = STATUS_INVALID_PARAMETER; - - if (!status) VIRTUAL_DEBUG_DUMP_VIEW( view ); - - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); +NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE process, PVOID *addr_ptr, + SIZE_T *size_ptr, ULONG new_prot, + ULONG *old_prot) { + struct file_view *view; + sigset_t sigset; + unsigned int status = STATUS_SUCCESS; + char *base; + BYTE vprot; + SIZE_T size = *size_ptr; + LPVOID addr = *addr_ptr; + DWORD old; + + TRACE("%p %p %08lx %08x\n", process, addr, size, (int)new_prot); + + if (!old_prot) + return STATUS_ACCESS_VIOLATION; + + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; + + memset(&call, 0, sizeof(call)); + + call.virtual_protect.type = APC_VIRTUAL_PROTECT; + call.virtual_protect.addr = wine_server_client_ptr(addr); + call.virtual_protect.size = size; + call.virtual_protect.prot = new_prot; + status = server_queue_process_apc(process, &call, &result); + if (status != STATUS_SUCCESS) + return status; + + if (result.virtual_protect.status == STATUS_SUCCESS) { + *addr_ptr = wine_server_get_ptr(result.virtual_protect.addr); + *size_ptr = result.virtual_protect.size; + *old_prot = result.virtual_protect.prot; + } + return result.virtual_protect.status; + } + + /* Fix the parameters */ + + size = ROUND_SIZE(addr, size); + base = ROUND_ADDR(addr, page_mask); + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + + if ((view = find_view(base, size))) { + /* Make sure all the pages are committed */ + if (get_committed_size(view, base, ~(size_t)0, &vprot, VPROT_COMMITTED) >= + size && + (vprot & VPROT_COMMITTED)) { + old = get_win32_prot(vprot, view->protect); + status = set_protection(view, base, size, new_prot); + } else + status = STATUS_NOT_COMMITTED; + } else + status = STATUS_INVALID_PARAMETER; + + if (!status) + VIRTUAL_DEBUG_DUMP_VIEW(view); + + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + + if (status == STATUS_SUCCESS) { + *addr_ptr = base; + *size_ptr = size; + *old_prot = old; + } + return status; +} + +static unsigned int fill_basic_memory_info(const void *addr, + MEMORY_BASIC_INFORMATION *info) { + char *base, *alloc_base = 0, *alloc_end = working_set_limit; + struct wine_rb_entry *ptr; + struct file_view *view; + sigset_t sigset; + + base = ROUND_ADDR(addr, page_mask); + + if (is_beyond_limit(base, 1, working_set_limit)) + return STATUS_INVALID_PARAMETER; + + /* Find the view containing the address */ + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + ptr = views_tree.root; + while (ptr) { + view = WINE_RB_ENTRY_VALUE(ptr, struct file_view, entry); + if ((char *)view->base > base) { + alloc_end = view->base; + ptr = ptr->left; + } else if ((char *)view->base + view->size <= base) { + alloc_base = (char *)view->base + view->size; + ptr = ptr->right; + } else { + alloc_base = view->base; + alloc_end = (char *)view->base + view->size; + break; + } + } + + /* Fill the info structure */ + + info->BaseAddress = base; + info->RegionSize = alloc_end - base; + + if (!ptr) { + info->State = MEM_FREE; + info->Protect = PAGE_NOACCESS; + info->AllocationBase = 0; + info->AllocationProtect = 0; + info->Type = 0; - if (status == STATUS_SUCCESS) +#ifdef __i386__ + /* on i386, pretend that space outside of a reserved area is allocated, + * so that the app doesn't believe it's fully available */ { - *addr_ptr = base; - *size_ptr = size; - *old_prot = old; - } - return status; -} - - -static unsigned int fill_basic_memory_info( const void *addr, MEMORY_BASIC_INFORMATION *info ) -{ - char *base, *alloc_base = 0, *alloc_end = working_set_limit; - struct wine_rb_entry *ptr; - struct file_view *view; - sigset_t sigset; - - base = ROUND_ADDR( addr, page_mask ); + struct reserved_area *area; + BOOL in_reserved = FALSE; - if (is_beyond_limit( base, 1, working_set_limit )) return STATUS_INVALID_PARAMETER; - - /* Find the view containing the address */ + LIST_FOR_EACH_ENTRY(area, &reserved_areas, struct reserved_area, entry) { + char *area_start = area->base; + char *area_end = (char *)area_start + area->size; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - ptr = views_tree.root; - while (ptr) - { - view = WINE_RB_ENTRY_VALUE( ptr, struct file_view, entry ); - if ((char *)view->base > base) - { - alloc_end = view->base; - ptr = ptr->left; + if (area_end <= base) { + if (alloc_base < area_end) + alloc_base = area_end; + continue; } - else if ((char *)view->base + view->size <= base) - { - alloc_base = (char *)view->base + view->size; - ptr = ptr->right; + if (area_start <= base || area_start <= (char *)address_space_start) { + if (area_end < alloc_end) + info->RegionSize = area_end - base; + in_reserved = TRUE; + break; } - else - { - alloc_base = view->base; - alloc_end = (char *)view->base + view->size; + /* report the remaining part of the 64K after the view as free */ + if ((UINT_PTR)alloc_base & granularity_mask) { + char *next = (char *)ROUND_ADDR(alloc_base, granularity_mask) + + granularity_mask + 1; + + if (base < next) { + info->RegionSize = min(next, alloc_end) - base; + in_reserved = TRUE; break; + } else + alloc_base = base; } + /* pretend it's allocated */ + if (area_start < alloc_end) + info->RegionSize = area_start - base; + break; + } + if (!in_reserved) { + info->State = MEM_RESERVE; + info->Protect = PAGE_NOACCESS; + info->AllocationBase = alloc_base; + info->AllocationProtect = PAGE_NOACCESS; + info->Type = MEM_PRIVATE; + } } - - /* Fill the info structure */ - - info->BaseAddress = base; - info->RegionSize = alloc_end - base; - - if (!ptr) - { - info->State = MEM_FREE; - info->Protect = PAGE_NOACCESS; - info->AllocationBase = 0; - info->AllocationProtect = 0; - info->Type = 0; - -#ifdef __i386__ - /* on i386, pretend that space outside of a reserved area is allocated, - * so that the app doesn't believe it's fully available */ - { - struct reserved_area *area; - BOOL in_reserved = FALSE; - - LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) - { - char *area_start = area->base; - char *area_end = (char *)area_start + area->size; - - if (area_end <= base) - { - if (alloc_base < area_end) alloc_base = area_end; - continue; - } - if (area_start <= base || area_start <= (char *)address_space_start) - { - if (area_end < alloc_end) info->RegionSize = area_end - base; - in_reserved = TRUE; - break; - } - /* report the remaining part of the 64K after the view as free */ - if ((UINT_PTR)alloc_base & granularity_mask) - { - char *next = (char *)ROUND_ADDR( alloc_base, granularity_mask ) + granularity_mask + 1; - - if (base < next) - { - info->RegionSize = min( next, alloc_end ) - base; - in_reserved = TRUE; - break; - } - else alloc_base = base; - } - /* pretend it's allocated */ - if (area_start < alloc_end) info->RegionSize = area_start - base; - break; - } - if (!in_reserved) - { - info->State = MEM_RESERVE; - info->Protect = PAGE_NOACCESS; - info->AllocationBase = alloc_base; - info->AllocationProtect = PAGE_NOACCESS; - info->Type = MEM_PRIVATE; - } - } #endif - } - else - { - BYTE vprot; + } else { + BYTE vprot; - info->AllocationBase = alloc_base; - info->RegionSize = get_committed_size( view, base, ~(size_t)0, &vprot, ~VPROT_WRITEWATCH ); - info->State = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE; - info->Protect = (vprot & VPROT_COMMITTED) ? get_win32_prot( vprot, view->protect ) : 0; - info->AllocationProtect = get_win32_prot( view->protect, view->protect ); - if (view->protect & SEC_IMAGE) info->Type = MEM_IMAGE; - else if (view->protect & (SEC_FILE | SEC_RESERVE | SEC_COMMIT)) info->Type = MEM_MAPPED; - else info->Type = MEM_PRIVATE; - } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); + info->AllocationBase = alloc_base; + info->RegionSize = + get_committed_size(view, base, ~(size_t)0, &vprot, ~VPROT_WRITEWATCH); + info->State = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE; + info->Protect = + (vprot & VPROT_COMMITTED) ? get_win32_prot(vprot, view->protect) : 0; + info->AllocationProtect = get_win32_prot(view->protect, view->protect); + if (view->protect & SEC_IMAGE) + info->Type = MEM_IMAGE; + else if (view->protect & (SEC_FILE | SEC_RESERVE | SEC_COMMIT)) + info->Type = MEM_MAPPED; + else + info->Type = MEM_PRIVATE; + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); - return STATUS_SUCCESS; + return STATUS_SUCCESS; } /* get basic information about a memory block */ -static unsigned int get_basic_memory_info( HANDLE process, LPCVOID addr, - MEMORY_BASIC_INFORMATION *info, - SIZE_T len, SIZE_T *res_len ) -{ - unsigned int status; - - if (len < sizeof(*info)) - return STATUS_INFO_LENGTH_MISMATCH; - - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; - - memset( &call, 0, sizeof(call) ); - - call.virtual_query.type = APC_VIRTUAL_QUERY; - call.virtual_query.addr = wine_server_client_ptr( addr ); - status = server_queue_process_apc( process, &call, &result ); - if (status != STATUS_SUCCESS) return status; - - if (result.virtual_query.status == STATUS_SUCCESS) - { - info->BaseAddress = wine_server_get_ptr( result.virtual_query.base ); - info->AllocationBase = wine_server_get_ptr( result.virtual_query.alloc_base ); - info->RegionSize = result.virtual_query.size; - info->Protect = result.virtual_query.prot; - info->AllocationProtect = result.virtual_query.alloc_prot; - info->State = (DWORD)result.virtual_query.state << 12; - info->Type = (DWORD)result.virtual_query.alloc_type << 16; - if (info->RegionSize != result.virtual_query.size) /* truncated */ - return STATUS_INVALID_PARAMETER; /* FIXME */ - if (res_len) *res_len = sizeof(*info); - } - return result.virtual_query.status; - } - - if ((status = fill_basic_memory_info( addr, info ))) return status; +static unsigned int get_basic_memory_info(HANDLE process, LPCVOID addr, + MEMORY_BASIC_INFORMATION *info, + SIZE_T len, SIZE_T *res_len) { + unsigned int status; + + if (len < sizeof(*info)) + return STATUS_INFO_LENGTH_MISMATCH; + + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; + + memset(&call, 0, sizeof(call)); + + call.virtual_query.type = APC_VIRTUAL_QUERY; + call.virtual_query.addr = wine_server_client_ptr(addr); + status = server_queue_process_apc(process, &call, &result); + if (status != STATUS_SUCCESS) + return status; + + if (result.virtual_query.status == STATUS_SUCCESS) { + info->BaseAddress = wine_server_get_ptr(result.virtual_query.base); + info->AllocationBase = + wine_server_get_ptr(result.virtual_query.alloc_base); + info->RegionSize = result.virtual_query.size; + info->Protect = result.virtual_query.prot; + info->AllocationProtect = result.virtual_query.alloc_prot; + info->State = (DWORD)result.virtual_query.state << 12; + info->Type = (DWORD)result.virtual_query.alloc_type << 16; + if (info->RegionSize != result.virtual_query.size) /* truncated */ + return STATUS_INVALID_PARAMETER; /* FIXME */ + if (res_len) + *res_len = sizeof(*info); + } + return result.virtual_query.status; + } + + if ((status = fill_basic_memory_info(addr, info))) + return status; - if (res_len) *res_len = sizeof(*info); - return STATUS_SUCCESS; + if (res_len) + *res_len = sizeof(*info); + return STATUS_SUCCESS; } -static unsigned int get_memory_region_info( HANDLE process, LPCVOID addr, MEMORY_REGION_INFORMATION *info, - SIZE_T len, SIZE_T *res_len ) -{ - MEMORY_BASIC_INFORMATION basic_info; - unsigned int status; +static unsigned int get_memory_region_info(HANDLE process, LPCVOID addr, + MEMORY_REGION_INFORMATION *info, + SIZE_T len, SIZE_T *res_len) { + MEMORY_BASIC_INFORMATION basic_info; + unsigned int status; - if (len < FIELD_OFFSET(MEMORY_REGION_INFORMATION, CommitSize)) - return STATUS_INFO_LENGTH_MISMATCH; + if (len < FIELD_OFFSET(MEMORY_REGION_INFORMATION, CommitSize)) + return STATUS_INFO_LENGTH_MISMATCH; - if (process != NtCurrentProcess()) - { - FIXME("Unimplemented for other processes.\n"); - return STATUS_NOT_IMPLEMENTED; - } + if (process != NtCurrentProcess()) { + FIXME("Unimplemented for other processes.\n"); + return STATUS_NOT_IMPLEMENTED; + } - if ((status = fill_basic_memory_info( addr, &basic_info ))) return status; + if ((status = fill_basic_memory_info(addr, &basic_info))) + return status; - info->AllocationBase = basic_info.AllocationBase; - info->AllocationProtect = basic_info.AllocationProtect; - info->RegionType = 0; /* FIXME */ - if (len >= FIELD_OFFSET(MEMORY_REGION_INFORMATION, CommitSize)) - info->RegionSize = basic_info.RegionSize; - if (len >= FIELD_OFFSET(MEMORY_REGION_INFORMATION, PartitionId)) - info->CommitSize = basic_info.State == MEM_COMMIT ? basic_info.RegionSize : 0; + info->AllocationBase = basic_info.AllocationBase; + info->AllocationProtect = basic_info.AllocationProtect; + info->RegionType = 0; /* FIXME */ + if (len >= FIELD_OFFSET(MEMORY_REGION_INFORMATION, CommitSize)) + info->RegionSize = basic_info.RegionSize; + if (len >= FIELD_OFFSET(MEMORY_REGION_INFORMATION, PartitionId)) + info->CommitSize = + basic_info.State == MEM_COMMIT ? basic_info.RegionSize : 0; - if (res_len) *res_len = sizeof(*info); - return STATUS_SUCCESS; + if (res_len) + *res_len = sizeof(*info); + return STATUS_SUCCESS; } -struct working_set_info_ref -{ - char *addr; - SIZE_T orig_index; +struct working_set_info_ref { + char *addr; + SIZE_T orig_index; }; #if defined(HAVE_LIBPROCSTAT) -struct fill_working_set_info_data -{ - struct procstat *pstat; - struct kinfo_proc *kip; - unsigned int vmentry_count; - struct kinfo_vmentry *vmentries; +struct fill_working_set_info_data { + struct procstat *pstat; + struct kinfo_proc *kip; + unsigned int vmentry_count; + struct kinfo_vmentry *vmentries; }; -static void init_fill_working_set_info_data( struct fill_working_set_info_data *d, char *end ) -{ - unsigned int proc_count; - - d->kip = NULL; - d->vmentry_count = 0; - d->vmentries = NULL; - - if ((d->pstat = procstat_open_sysctl())) - d->kip = procstat_getprocs( d->pstat, KERN_PROC_PID, getpid(), &proc_count ); - if (d->kip) - d->vmentries = procstat_getvmmap( d->pstat, d->kip, &d->vmentry_count ); - if (!d->vmentries) - WARN( "couldn't get process vmmap, errno %d\n", errno ); -} - -static void free_fill_working_set_info_data( struct fill_working_set_info_data *d ) -{ - if (d->vmentries) - procstat_freevmmap( d->pstat, d->vmentries ); - if (d->kip) - procstat_freeprocs( d->pstat, d->kip ); - if (d->pstat) - procstat_close( d->pstat ); -} - -static void fill_working_set_info( struct fill_working_set_info_data *d, struct file_view *view, BYTE vprot, - struct working_set_info_ref *ref, SIZE_T count, - MEMORY_WORKING_SET_EX_INFORMATION *info ) -{ - SIZE_T i; - int j; - - for (i = 0; i < count; ++i) - { - MEMORY_WORKING_SET_EX_INFORMATION *p = &info[ref[i].orig_index]; - struct kinfo_vmentry *entry = NULL; - - for (j = 0; j < d->vmentry_count; j++) - { - if (d->vmentries[j].kve_start <= (ULONG_PTR)p->VirtualAddress && (ULONG_PTR)p->VirtualAddress <= d->vmentries[j].kve_end) - { - entry = &d->vmentries[j]; - break; - } - } - - p->VirtualAttributes.Valid = !(vprot & VPROT_GUARD) && (vprot & 0x0f) && entry && entry->kve_type != KVME_TYPE_SWAP; - p->VirtualAttributes.Shared = !is_view_valloc( view ); - if (p->VirtualAttributes.Shared && p->VirtualAttributes.Valid) - p->VirtualAttributes.ShareCount = 1; /* FIXME */ - if (p->VirtualAttributes.Valid) - p->VirtualAttributes.Win32Protection = get_win32_prot( vprot, view->protect ); +static void +init_fill_working_set_info_data(struct fill_working_set_info_data *d, + char *end) { + unsigned int proc_count; + + d->kip = NULL; + d->vmentry_count = 0; + d->vmentries = NULL; + + if ((d->pstat = procstat_open_sysctl())) + d->kip = procstat_getprocs(d->pstat, KERN_PROC_PID, getpid(), &proc_count); + if (d->kip) + d->vmentries = procstat_getvmmap(d->pstat, d->kip, &d->vmentry_count); + if (!d->vmentries) + WARN("couldn't get process vmmap, errno %d\n", errno); +} + +static void +free_fill_working_set_info_data(struct fill_working_set_info_data *d) { + if (d->vmentries) + procstat_freevmmap(d->pstat, d->vmentries); + if (d->kip) + procstat_freeprocs(d->pstat, d->kip); + if (d->pstat) + procstat_close(d->pstat); +} + +static void fill_working_set_info(struct fill_working_set_info_data *d, + struct file_view *view, BYTE vprot, + struct working_set_info_ref *ref, + SIZE_T count, + MEMORY_WORKING_SET_EX_INFORMATION *info) { + SIZE_T i; + int j; + + for (i = 0; i < count; ++i) { + MEMORY_WORKING_SET_EX_INFORMATION *p = &info[ref[i].orig_index]; + struct kinfo_vmentry *entry = NULL; + + for (j = 0; j < d->vmentry_count; j++) { + if (d->vmentries[j].kve_start <= (ULONG_PTR)p->VirtualAddress && + (ULONG_PTR)p->VirtualAddress <= d->vmentries[j].kve_end) { + entry = &d->vmentries[j]; + break; + } } + + p->VirtualAttributes.Valid = !(vprot & VPROT_GUARD) && (vprot & 0x0f) && + entry && entry->kve_type != KVME_TYPE_SWAP; + p->VirtualAttributes.Shared = !is_view_valloc(view); + if (p->VirtualAttributes.Shared && p->VirtualAttributes.Valid) + p->VirtualAttributes.ShareCount = 1; /* FIXME */ + if (p->VirtualAttributes.Valid) + p->VirtualAttributes.Win32Protection = + get_win32_prot(vprot, view->protect); + } } #else static int pagemap_fd = -2; -struct fill_working_set_info_data -{ - UINT64 pm_buffer[256]; - SIZE_T buffer_start; - ssize_t buffer_len; - SIZE_T end_page; +struct fill_working_set_info_data { + UINT64 pm_buffer[256]; + SIZE_T buffer_start; + ssize_t buffer_len; + SIZE_T end_page; }; -static void init_fill_working_set_info_data( struct fill_working_set_info_data *d, char *end ) -{ - d->buffer_start = 0; - d->buffer_len = 0; - d->end_page = (UINT_PTR)end >> page_shift; - memset( d->pm_buffer, 0, sizeof(d->pm_buffer) ); - - if (pagemap_fd != -2) return; - -#ifdef O_CLOEXEC - if ((pagemap_fd = open( "/proc/self/pagemap", O_RDONLY | O_CLOEXEC, 0 )) == -1 && errno == EINVAL) -#endif - pagemap_fd = open( "/proc/self/pagemap", O_RDONLY, 0 ); - - if (pagemap_fd == -1) WARN( "unable to open /proc/self/pagemap\n" ); - else fcntl(pagemap_fd, F_SETFD, FD_CLOEXEC); /* in case O_CLOEXEC isn't supported */ -} - -static void free_fill_working_set_info_data( struct fill_working_set_info_data *d ) -{ -} - -static void fill_working_set_info( struct fill_working_set_info_data *d, struct file_view *view, BYTE vprot, - struct working_set_info_ref *ref, SIZE_T count, - MEMORY_WORKING_SET_EX_INFORMATION *info ) -{ - MEMORY_WORKING_SET_EX_INFORMATION *p; - UINT64 pagemap; - SIZE_T i, page; - ssize_t len; - - for (i = 0; i < count; ++i) - { - page = (UINT_PTR)ref[i].addr >> page_shift; - p = &info[ref[i].orig_index]; - - assert(page >= d->buffer_start); - if (page >= d->buffer_start + d->buffer_len) - { - d->buffer_start = page; - len = min( sizeof(d->pm_buffer), (d->end_page - page) * sizeof(pagemap) ); - if (pagemap_fd != -1) - { - d->buffer_len = pread( pagemap_fd, d->pm_buffer, len, page * sizeof(pagemap) ); - if (d->buffer_len != len) - { - d->buffer_len = max( d->buffer_len, 0 ); - memset( d->pm_buffer + d->buffer_len / sizeof(pagemap), 0, len - d->buffer_len ); - } - } - d->buffer_len = len / sizeof(pagemap); - } - pagemap = d->pm_buffer[page - d->buffer_start]; - - p->VirtualAttributes.Valid = !(vprot & VPROT_GUARD) && (vprot & 0x0f) && (pagemap >> 63); - p->VirtualAttributes.Shared = !is_view_valloc( view ) && ((pagemap >> 61) & 1); - if (p->VirtualAttributes.Shared && p->VirtualAttributes.Valid) - p->VirtualAttributes.ShareCount = 1; /* FIXME */ - if (p->VirtualAttributes.Valid) - p->VirtualAttributes.Win32Protection = get_win32_prot( vprot, view->protect ); - } -} -#endif - -static int compare_working_set_info_ref( const void *a, const void *b ) -{ - const struct working_set_info_ref *r1 = a, *r2 = b; - - if (r1->addr < r2->addr) return -1; - return r1->addr > r2->addr; -} - -static NTSTATUS get_working_set_ex( HANDLE process, LPCVOID addr, - MEMORY_WORKING_SET_EX_INFORMATION *info, - SIZE_T len, SIZE_T *res_len ) -{ - struct working_set_info_ref ref_buffer[256], *ref = ref_buffer, *r; - struct fill_working_set_info_data data; - char *start, *end; - SIZE_T i, count; - struct file_view *view, *prev_view; - sigset_t sigset; - BYTE vprot; - - if (process != NtCurrentProcess()) - { - FIXME( "(process=%p,addr=%p) Unimplemented information class: MemoryWorkingSetExInformation\n", process, addr ); - return STATUS_INVALID_INFO_CLASS; - } - - if (len < sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH; - - count = len / sizeof(*info); - - if (count > ARRAY_SIZE(ref_buffer)) ref = malloc( count * sizeof(*ref) ); - for (i = 0; i < count; ++i) - { - ref[i].orig_index = i; - ref[i].addr = ROUND_ADDR( info[i].VirtualAddress, page_mask ); - info[i].VirtualAttributes.Flags = 0; - } - qsort( ref, count, sizeof(*ref), compare_working_set_info_ref ); - start = ref[0].addr; - end = ref[count - 1].addr + page_size; - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - init_fill_working_set_info_data( &data, end ); - - view = find_view_range( start, end - start ); - while (view && (char *)view->base > start) - { - prev_view = RB_ENTRY_VALUE( rb_prev( &view->entry ), struct file_view, entry ); - if (!prev_view || (char *)prev_view->base + prev_view->size <= start) break; - view = prev_view; - } - - r = ref; - while (view && (char *)view->base < end) - { - if (start < (char *)view->base) start = view->base; - while (r != ref + count && r->addr < start) ++r; - while (start != (char *)view->base + view->size && r != ref + count - && r->addr < (char *)view->base + view->size) - { - start += get_committed_size( view, start, end - start, &vprot, ~VPROT_WRITEWATCH ); - i = 0; - while (r + i != ref + count && r[i].addr < start) ++i; - if (vprot & VPROT_COMMITTED) fill_working_set_info( &data, view, vprot, r, i, info ); - r += i; - } - if (r == ref + count) break; - view = RB_ENTRY_VALUE( rb_next( &view->entry ), struct file_view, entry ); - } - - free_fill_working_set_info_data( &data ); - if (ref != ref_buffer) free( ref ); - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - - if (res_len) - *res_len = len; - return STATUS_SUCCESS; -} - -static unsigned int get_memory_section_name( HANDLE process, LPCVOID addr, - MEMORY_SECTION_NAME *info, SIZE_T len, SIZE_T *ret_len ) -{ - unsigned int status; - - if (!info) return STATUS_ACCESS_VIOLATION; - - SERVER_START_REQ( get_mapping_filename ) - { - req->process = wine_server_obj_handle( process ); - req->addr = wine_server_client_ptr( addr ); - if (len > sizeof(*info) + sizeof(WCHAR)) - wine_server_set_reply( req, info + 1, len - sizeof(*info) - sizeof(WCHAR) ); - status = wine_server_call( req ); - if (!status || status == STATUS_BUFFER_OVERFLOW) - { - if (ret_len) *ret_len = sizeof(*info) + reply->len + sizeof(WCHAR); - if (len < sizeof(*info)) status = STATUS_INFO_LENGTH_MISMATCH; - if (!status) - { - info->SectionFileName.Buffer = (WCHAR *)(info + 1); - info->SectionFileName.Length = reply->len; - info->SectionFileName.MaximumLength = reply->len + sizeof(WCHAR); - info->SectionFileName.Buffer[reply->len / sizeof(WCHAR)] = 0; - } - } - } - SERVER_END_REQ; - return status; -} - -static unsigned int get_memory_image_info( HANDLE process, LPCVOID addr, MEMORY_IMAGE_INFORMATION *info, - SIZE_T len, SIZE_T *res_len ) -{ - unsigned int status; +static void +init_fill_working_set_info_data(struct fill_working_set_info_data *d, + char *end) { + d->buffer_start = 0; + d->buffer_len = 0; + d->end_page = (UINT_PTR)end >> page_shift; + memset(d->pm_buffer, 0, sizeof(d->pm_buffer)); - if (len < sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH; - memset( info, 0, sizeof(*info) ); + if (pagemap_fd != -2) + return; - SERVER_START_REQ( get_image_view_info ) - { - req->process = wine_server_obj_handle( process ); - req->addr = wine_server_client_ptr( addr ); - status = wine_server_call( req ); - if (!status && reply->base) - { - info->ImageBase = wine_server_get_ptr( reply->base ); - info->SizeOfImage = reply->size; - info->ImageSigningLevel = 12; +#ifdef O_CLOEXEC + if ((pagemap_fd = open("/proc/self/pagemap", O_RDONLY | O_CLOEXEC, 0)) == + -1 && + errno == EINVAL) +#endif + pagemap_fd = open("/proc/self/pagemap", O_RDONLY, 0); + + if (pagemap_fd == -1) + WARN("unable to open /proc/self/pagemap\n"); + else + fcntl(pagemap_fd, F_SETFD, + FD_CLOEXEC); /* in case O_CLOEXEC isn't supported */ +} + +static void +free_fill_working_set_info_data(struct fill_working_set_info_data *d) {} + +static void fill_working_set_info(struct fill_working_set_info_data *d, + struct file_view *view, BYTE vprot, + struct working_set_info_ref *ref, + SIZE_T count, + MEMORY_WORKING_SET_EX_INFORMATION *info) { + MEMORY_WORKING_SET_EX_INFORMATION *p; + UINT64 pagemap; + SIZE_T i, page; + ssize_t len; + + for (i = 0; i < count; ++i) { + page = (UINT_PTR)ref[i].addr >> page_shift; + p = &info[ref[i].orig_index]; + + assert(page >= d->buffer_start); + if (page >= d->buffer_start + d->buffer_len) { + d->buffer_start = page; + len = min(sizeof(d->pm_buffer), (d->end_page - page) * sizeof(pagemap)); + if (pagemap_fd != -1) { + d->buffer_len = + pread(pagemap_fd, d->pm_buffer, len, page * sizeof(pagemap)); + if (d->buffer_len != len) { + d->buffer_len = max(d->buffer_len, 0); + memset(d->pm_buffer + d->buffer_len / sizeof(pagemap), 0, + len - d->buffer_len); } - } - SERVER_END_REQ; + } + d->buffer_len = len / sizeof(pagemap); + } + pagemap = d->pm_buffer[page - d->buffer_start]; + + p->VirtualAttributes.Valid = + !(vprot & VPROT_GUARD) && (vprot & 0x0f) && (pagemap >> 63); + p->VirtualAttributes.Shared = + !is_view_valloc(view) && ((pagemap >> 61) & 1); + if (p->VirtualAttributes.Shared && p->VirtualAttributes.Valid) + p->VirtualAttributes.ShareCount = 1; /* FIXME */ + if (p->VirtualAttributes.Valid) + p->VirtualAttributes.Win32Protection = + get_win32_prot(vprot, view->protect); + } +} +#endif - if (status == STATUS_NOT_MAPPED_VIEW) - { - MEMORY_BASIC_INFORMATION basic_info; +static int compare_working_set_info_ref(const void *a, const void *b) { + const struct working_set_info_ref *r1 = a, *r2 = b; + + if (r1->addr < r2->addr) + return -1; + return r1->addr > r2->addr; +} + +static NTSTATUS get_working_set_ex(HANDLE process, LPCVOID addr, + MEMORY_WORKING_SET_EX_INFORMATION *info, + SIZE_T len, SIZE_T *res_len) { + struct working_set_info_ref ref_buffer[256], *ref = ref_buffer, *r; + struct fill_working_set_info_data data; + char *start, *end; + SIZE_T i, count; + struct file_view *view, *prev_view; + sigset_t sigset; + BYTE vprot; + + if (process != NtCurrentProcess()) { + FIXME("(process=%p,addr=%p) Unimplemented information class: " + "MemoryWorkingSetExInformation\n", + process, addr); + return STATUS_INVALID_INFO_CLASS; + } + + if (len < sizeof(*info)) + return STATUS_INFO_LENGTH_MISMATCH; + + count = len / sizeof(*info); + + if (count > ARRAY_SIZE(ref_buffer)) + ref = malloc(count * sizeof(*ref)); + for (i = 0; i < count; ++i) { + ref[i].orig_index = i; + ref[i].addr = ROUND_ADDR(info[i].VirtualAddress, page_mask); + info[i].VirtualAttributes.Flags = 0; + } + qsort(ref, count, sizeof(*ref), compare_working_set_info_ref); + start = ref[0].addr; + end = ref[count - 1].addr + page_size; + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + init_fill_working_set_info_data(&data, end); + + view = find_view_range(start, end - start); + while (view && (char *)view->base > start) { + prev_view = RB_ENTRY_VALUE(rb_prev(&view->entry), struct file_view, entry); + if (!prev_view || (char *)prev_view->base + prev_view->size <= start) + break; + view = prev_view; + } + + r = ref; + while (view && (char *)view->base < end) { + if (start < (char *)view->base) + start = view->base; + while (r != ref + count && r->addr < start) + ++r; + while (start != (char *)view->base + view->size && r != ref + count && + r->addr < (char *)view->base + view->size) { + start += get_committed_size(view, start, end - start, &vprot, + ~VPROT_WRITEWATCH); + i = 0; + while (r + i != ref + count && r[i].addr < start) + ++i; + if (vprot & VPROT_COMMITTED) + fill_working_set_info(&data, view, vprot, r, i, info); + r += i; + } + if (r == ref + count) + break; + view = RB_ENTRY_VALUE(rb_next(&view->entry), struct file_view, entry); + } + + free_fill_working_set_info_data(&data); + if (ref != ref_buffer) + free(ref); + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + + if (res_len) + *res_len = len; + return STATUS_SUCCESS; +} + +static unsigned int get_memory_section_name(HANDLE process, LPCVOID addr, + MEMORY_SECTION_NAME *info, + SIZE_T len, SIZE_T *ret_len) { + unsigned int status; + + if (!info) + return STATUS_ACCESS_VIOLATION; + + SERVER_START_REQ(get_mapping_filename) { + req->process = wine_server_obj_handle(process); + req->addr = wine_server_client_ptr(addr); + if (len > sizeof(*info) + sizeof(WCHAR)) + wine_server_set_reply(req, info + 1, len - sizeof(*info) - sizeof(WCHAR)); + status = wine_server_call(req); + if (!status || status == STATUS_BUFFER_OVERFLOW) { + if (ret_len) + *ret_len = sizeof(*info) + reply->len + sizeof(WCHAR); + if (len < sizeof(*info)) + status = STATUS_INFO_LENGTH_MISMATCH; + if (!status) { + info->SectionFileName.Buffer = (WCHAR *)(info + 1); + info->SectionFileName.Length = reply->len; + info->SectionFileName.MaximumLength = reply->len + sizeof(WCHAR); + info->SectionFileName.Buffer[reply->len / sizeof(WCHAR)] = 0; + } + } + } + SERVER_END_REQ; + return status; +} + +static unsigned int get_memory_image_info(HANDLE process, LPCVOID addr, + MEMORY_IMAGE_INFORMATION *info, + SIZE_T len, SIZE_T *res_len) { + unsigned int status; + + if (len < sizeof(*info)) + return STATUS_INFO_LENGTH_MISMATCH; + memset(info, 0, sizeof(*info)); + + SERVER_START_REQ(get_image_view_info) { + req->process = wine_server_obj_handle(process); + req->addr = wine_server_client_ptr(addr); + status = wine_server_call(req); + if (!status && reply->base) { + info->ImageBase = wine_server_get_ptr(reply->base); + info->SizeOfImage = reply->size; + info->ImageSigningLevel = 12; + } + } + SERVER_END_REQ; + + if (status == STATUS_NOT_MAPPED_VIEW) { + MEMORY_BASIC_INFORMATION basic_info; - status = get_basic_memory_info( process, addr, &basic_info, sizeof(basic_info), NULL ); - if (status || basic_info.State == MEM_FREE) status = STATUS_INVALID_ADDRESS; - } + status = get_basic_memory_info(process, addr, &basic_info, + sizeof(basic_info), NULL); + if (status || basic_info.State == MEM_FREE) + status = STATUS_INVALID_ADDRESS; + } - if (!status && res_len) *res_len = sizeof(*info); - return status; + if (!status && res_len) + *res_len = sizeof(*info); + return status; } - /*********************************************************************** * NtQueryVirtualMemory (NTDLL.@) * ZwQueryVirtualMemory (NTDLL.@) */ -NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr, - MEMORY_INFORMATION_CLASS info_class, - PVOID buffer, SIZE_T len, SIZE_T *res_len ) -{ - NTSTATUS status; +NTSTATUS WINAPI NtQueryVirtualMemory(HANDLE process, LPCVOID addr, + MEMORY_INFORMATION_CLASS info_class, + PVOID buffer, SIZE_T len, + SIZE_T *res_len) { + NTSTATUS status; - TRACE("(%p, %p, info_class=%d, %p, %ld, %p)\n", - process, addr, info_class, buffer, len, res_len); + TRACE("(%p, %p, info_class=%d, %p, %ld, %p)\n", process, addr, info_class, + buffer, len, res_len); - switch(info_class) - { - case MemoryBasicInformation: - return get_basic_memory_info( process, addr, buffer, len, res_len ); - - case MemoryWorkingSetExInformation: - return get_working_set_ex( process, addr, buffer, len, res_len ); - - case MemoryMappedFilenameInformation: - return get_memory_section_name( process, addr, buffer, len, res_len ); - - case MemoryRegionInformation: - return get_memory_region_info( process, addr, buffer, len, res_len ); - - case MemoryImageInformation: - return get_memory_image_info( process, addr, buffer, len, res_len ); - - case MemoryWineUnixFuncs: - case MemoryWineUnixWow64Funcs: - if (len != sizeof(unixlib_handle_t)) return STATUS_INFO_LENGTH_MISMATCH; - if (process == GetCurrentProcess()) - { - void *module = (void *)addr; - const void *funcs = NULL; - - status = get_builtin_unix_funcs( module, info_class == MemoryWineUnixWow64Funcs, &funcs ); - if (!status) *(unixlib_handle_t *)buffer = (UINT_PTR)funcs; - return status; - } - return STATUS_INVALID_HANDLE; - - default: - FIXME("(%p,%p,info_class=%d,%p,%ld,%p) Unknown information class\n", - process, addr, info_class, buffer, len, res_len); - return STATUS_INVALID_INFO_CLASS; + switch (info_class) { + case MemoryBasicInformation: + return get_basic_memory_info(process, addr, buffer, len, res_len); + + case MemoryWorkingSetExInformation: + return get_working_set_ex(process, addr, buffer, len, res_len); + + case MemoryMappedFilenameInformation: + return get_memory_section_name(process, addr, buffer, len, res_len); + + case MemoryRegionInformation: + return get_memory_region_info(process, addr, buffer, len, res_len); + + case MemoryImageInformation: + return get_memory_image_info(process, addr, buffer, len, res_len); + + case MemoryWineUnixFuncs: + case MemoryWineUnixWow64Funcs: + if (len != sizeof(unixlib_handle_t)) + return STATUS_INFO_LENGTH_MISMATCH; + if (process == GetCurrentProcess()) { + void *module = (void *)addr; + const void *funcs = NULL; + + status = get_builtin_unix_funcs( + module, info_class == MemoryWineUnixWow64Funcs, &funcs); + if (!status) + *(unixlib_handle_t *)buffer = (UINT_PTR)funcs; + return status; } -} + return STATUS_INVALID_HANDLE; + default: + FIXME("(%p,%p,info_class=%d,%p,%ld,%p) Unknown information class\n", + process, addr, info_class, buffer, len, res_len); + return STATUS_INVALID_INFO_CLASS; + } +} /*********************************************************************** * NtLockVirtualMemory (NTDLL.@) * ZwLockVirtualMemory (NTDLL.@) */ -NTSTATUS WINAPI NtLockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size, ULONG unknown ) -{ - unsigned int status = STATUS_SUCCESS; +NTSTATUS WINAPI NtLockVirtualMemory(HANDLE process, PVOID *addr, SIZE_T *size, + ULONG unknown) { + unsigned int status = STATUS_SUCCESS; - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; - memset( &call, 0, sizeof(call) ); + memset(&call, 0, sizeof(call)); - call.virtual_lock.type = APC_VIRTUAL_LOCK; - call.virtual_lock.addr = wine_server_client_ptr( *addr ); - call.virtual_lock.size = *size; - status = server_queue_process_apc( process, &call, &result ); - if (status != STATUS_SUCCESS) return status; + call.virtual_lock.type = APC_VIRTUAL_LOCK; + call.virtual_lock.addr = wine_server_client_ptr(*addr); + call.virtual_lock.size = *size; + status = server_queue_process_apc(process, &call, &result); + if (status != STATUS_SUCCESS) + return status; - if (result.virtual_lock.status == STATUS_SUCCESS) - { - *addr = wine_server_get_ptr( result.virtual_lock.addr ); - *size = result.virtual_lock.size; - } - return result.virtual_lock.status; + if (result.virtual_lock.status == STATUS_SUCCESS) { + *addr = wine_server_get_ptr(result.virtual_lock.addr); + *size = result.virtual_lock.size; } + return result.virtual_lock.status; + } - *size = ROUND_SIZE( *addr, *size ); - *addr = ROUND_ADDR( *addr, page_mask ); + *size = ROUND_SIZE(*addr, *size); + *addr = ROUND_ADDR(*addr, page_mask); - if (mlock( *addr, *size )) status = STATUS_ACCESS_DENIED; - return status; + if (mlock(*addr, *size)) + status = STATUS_ACCESS_DENIED; + return status; } - /*********************************************************************** * NtUnlockVirtualMemory (NTDLL.@) * ZwUnlockVirtualMemory (NTDLL.@) */ -NTSTATUS WINAPI NtUnlockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size, ULONG unknown ) -{ - unsigned int status = STATUS_SUCCESS; +NTSTATUS WINAPI NtUnlockVirtualMemory(HANDLE process, PVOID *addr, SIZE_T *size, + ULONG unknown) { + unsigned int status = STATUS_SUCCESS; - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; - memset( &call, 0, sizeof(call) ); + memset(&call, 0, sizeof(call)); - call.virtual_unlock.type = APC_VIRTUAL_UNLOCK; - call.virtual_unlock.addr = wine_server_client_ptr( *addr ); - call.virtual_unlock.size = *size; - status = server_queue_process_apc( process, &call, &result ); - if (status != STATUS_SUCCESS) return status; + call.virtual_unlock.type = APC_VIRTUAL_UNLOCK; + call.virtual_unlock.addr = wine_server_client_ptr(*addr); + call.virtual_unlock.size = *size; + status = server_queue_process_apc(process, &call, &result); + if (status != STATUS_SUCCESS) + return status; - if (result.virtual_unlock.status == STATUS_SUCCESS) - { - *addr = wine_server_get_ptr( result.virtual_unlock.addr ); - *size = result.virtual_unlock.size; - } - return result.virtual_unlock.status; + if (result.virtual_unlock.status == STATUS_SUCCESS) { + *addr = wine_server_get_ptr(result.virtual_unlock.addr); + *size = result.virtual_unlock.size; } + return result.virtual_unlock.status; + } - *size = ROUND_SIZE( *addr, *size ); - *addr = ROUND_ADDR( *addr, page_mask ); + *size = ROUND_SIZE(*addr, *size); + *addr = ROUND_ADDR(*addr, page_mask); - if (munlock( *addr, *size )) status = STATUS_ACCESS_DENIED; - return status; + if (munlock(*addr, *size)) + status = STATUS_ACCESS_DENIED; + return status; } - /*********************************************************************** * NtMapViewOfSection (NTDLL.@) * ZwMapViewOfSection (NTDLL.@) */ -NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_ptr, ULONG_PTR zero_bits, - SIZE_T commit_size, const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, - SECTION_INHERIT inherit, ULONG alloc_type, ULONG protect ) -{ - unsigned int res; - SIZE_T mask = granularity_mask; - LARGE_INTEGER offset; - - offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0; +NTSTATUS WINAPI NtMapViewOfSection(HANDLE handle, HANDLE process, + PVOID *addr_ptr, ULONG_PTR zero_bits, + SIZE_T commit_size, + const LARGE_INTEGER *offset_ptr, + SIZE_T *size_ptr, SECTION_INHERIT inherit, + ULONG alloc_type, ULONG protect) { + unsigned int res; + SIZE_T mask = granularity_mask; + LARGE_INTEGER offset; + + offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0; + + TRACE("handle=%p process=%p addr=%p off=%s size=0x%lx alloc_type=0x%x " + "access=0x%x\n", + handle, process, *addr_ptr, wine_dbgstr_longlong(offset.QuadPart), + *size_ptr, (int)alloc_type, (int)protect); + + /* Check parameters */ + if (zero_bits > 21 && zero_bits < 32) + return STATUS_INVALID_PARAMETER_4; + + /* If both addr_ptr and zero_bits are passed, they have match */ + if (*addr_ptr && zero_bits && zero_bits < 32 && + (((UINT_PTR)*addr_ptr) >> (32 - zero_bits))) + return STATUS_INVALID_PARAMETER_4; + if (*addr_ptr && zero_bits >= 32 && (((UINT_PTR)*addr_ptr) & ~zero_bits)) + return STATUS_INVALID_PARAMETER_4; - TRACE("handle=%p process=%p addr=%p off=%s size=0x%lx alloc_type=0x%x access=0x%x\n", - handle, process, *addr_ptr, wine_dbgstr_longlong(offset.QuadPart), *size_ptr, (int)alloc_type, (int)protect ); +#ifndef _WIN64 + if (!is_old_wow64()) { + if (zero_bits >= 32) + return STATUS_INVALID_PARAMETER_4; + if (alloc_type & AT_ROUND_TO_PAGE) { + *addr_ptr = ROUND_ADDR(*addr_ptr, page_mask); + mask = page_mask; + } + } +#endif - /* Check parameters */ - if (zero_bits > 21 && zero_bits < 32) - return STATUS_INVALID_PARAMETER_4; + if (alloc_type & MEM_REPLACE_PLACEHOLDER) + mask = page_mask; - /* If both addr_ptr and zero_bits are passed, they have match */ - if (*addr_ptr && zero_bits && zero_bits < 32 && - (((UINT_PTR)*addr_ptr) >> (32 - zero_bits))) - return STATUS_INVALID_PARAMETER_4; - if (*addr_ptr && zero_bits >= 32 && - (((UINT_PTR)*addr_ptr) & ~zero_bits)) - return STATUS_INVALID_PARAMETER_4; + if ((offset.u.LowPart & mask) || (*addr_ptr && ((UINT_PTR)*addr_ptr & mask))) + return STATUS_MAPPED_ALIGNMENT; -#ifndef _WIN64 - if (!is_old_wow64()) - { - if (zero_bits >= 32) return STATUS_INVALID_PARAMETER_4; - if (alloc_type & AT_ROUND_TO_PAGE) - { - *addr_ptr = ROUND_ADDR( *addr_ptr, page_mask ); - mask = page_mask; - } - } -#endif + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; - if (alloc_type & MEM_REPLACE_PLACEHOLDER) - mask = page_mask; + memset(&call, 0, sizeof(call)); - if ((offset.u.LowPart & mask) || (*addr_ptr && ((UINT_PTR)*addr_ptr & mask))) - return STATUS_MAPPED_ALIGNMENT; + call.map_view.type = APC_MAP_VIEW; + call.map_view.handle = wine_server_obj_handle(handle); + call.map_view.addr = wine_server_client_ptr(*addr_ptr); + call.map_view.size = *size_ptr; + call.map_view.offset = offset.QuadPart; + call.map_view.zero_bits = zero_bits; + call.map_view.alloc_type = alloc_type; + call.map_view.prot = protect; + res = server_queue_process_apc(process, &call, &result); + if (res != STATUS_SUCCESS) + return res; - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; - - memset( &call, 0, sizeof(call) ); - - call.map_view.type = APC_MAP_VIEW; - call.map_view.handle = wine_server_obj_handle( handle ); - call.map_view.addr = wine_server_client_ptr( *addr_ptr ); - call.map_view.size = *size_ptr; - call.map_view.offset = offset.QuadPart; - call.map_view.zero_bits = zero_bits; - call.map_view.alloc_type = alloc_type; - call.map_view.prot = protect; - res = server_queue_process_apc( process, &call, &result ); - if (res != STATUS_SUCCESS) return res; - - if (NT_SUCCESS(result.map_view.status)) - { - *addr_ptr = wine_server_get_ptr( result.map_view.addr ); - *size_ptr = result.map_view.size; - } - return result.map_view.status; + if (NT_SUCCESS(result.map_view.status)) { + *addr_ptr = wine_server_get_ptr(result.map_view.addr); + *size_ptr = result.map_view.size; } + return result.map_view.status; + } - return virtual_map_section( handle, addr_ptr, 0, get_zero_bits_limit( zero_bits ), commit_size, - offset_ptr, size_ptr, alloc_type, protect, 0 ); + return virtual_map_section(handle, addr_ptr, 0, + get_zero_bits_limit(zero_bits), commit_size, + offset_ptr, size_ptr, alloc_type, protect, 0); } /*********************************************************************** * NtMapViewOfSectionEx (NTDLL.@) * ZwMapViewOfSectionEx (NTDLL.@) */ -NTSTATUS WINAPI NtMapViewOfSectionEx( HANDLE handle, HANDLE process, PVOID *addr_ptr, - const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, - ULONG alloc_type, ULONG protect, - MEM_EXTENDED_PARAMETER *parameters, ULONG count ) -{ - ULONG_PTR limit_low = 0, limit_high = 0, align = 0; - ULONG attributes = 0; - USHORT machine = 0; - unsigned int status; - SIZE_T mask = granularity_mask; - LARGE_INTEGER offset; +NTSTATUS WINAPI NtMapViewOfSectionEx( + HANDLE handle, HANDLE process, PVOID *addr_ptr, + const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, ULONG alloc_type, + ULONG protect, MEM_EXTENDED_PARAMETER *parameters, ULONG count) { + ULONG_PTR limit_low = 0, limit_high = 0, align = 0; + ULONG attributes = 0; + USHORT machine = 0; + unsigned int status; + SIZE_T mask = granularity_mask; + LARGE_INTEGER offset; + + offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0; + + TRACE("handle=%p process=%p addr=%p off=%s size=0x%lx alloc_type=0x%x " + "access=0x%x\n", + handle, process, *addr_ptr, wine_dbgstr_longlong(offset.QuadPart), + *size_ptr, (int)alloc_type, (int)protect); + + status = get_extended_params(parameters, count, &limit_low, &limit_high, + &align, &attributes, &machine); + if (status) + return status; - offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0; + if (align) + return STATUS_INVALID_PARAMETER; + if (*addr_ptr && (limit_low || limit_high)) + return STATUS_INVALID_PARAMETER; - TRACE( "handle=%p process=%p addr=%p off=%s size=0x%lx alloc_type=0x%x access=0x%x\n", - handle, process, *addr_ptr, wine_dbgstr_longlong(offset.QuadPart), *size_ptr, (int)alloc_type, (int)protect ); +#ifndef _WIN64 + if (!is_old_wow64() && (alloc_type & AT_ROUND_TO_PAGE)) { + *addr_ptr = ROUND_ADDR(*addr_ptr, page_mask); + mask = page_mask; + } +#endif - status = get_extended_params( parameters, count, &limit_low, &limit_high, - &align, &attributes, &machine ); - if (status) return status; + if (alloc_type & MEM_REPLACE_PLACEHOLDER) + mask = page_mask; - if (align) return STATUS_INVALID_PARAMETER; - if (*addr_ptr && (limit_low || limit_high)) return STATUS_INVALID_PARAMETER; + if ((offset.u.LowPart & mask) || (*addr_ptr && ((UINT_PTR)*addr_ptr & mask))) + return STATUS_MAPPED_ALIGNMENT; -#ifndef _WIN64 - if (!is_old_wow64() && (alloc_type & AT_ROUND_TO_PAGE)) - { - *addr_ptr = ROUND_ADDR( *addr_ptr, page_mask ); - mask = page_mask; - } -#endif + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; - if (alloc_type & MEM_REPLACE_PLACEHOLDER) - mask = page_mask; + memset(&call, 0, sizeof(call)); - if ((offset.u.LowPart & mask) || (*addr_ptr && ((UINT_PTR)*addr_ptr & mask))) - return STATUS_MAPPED_ALIGNMENT; + call.map_view_ex.type = APC_MAP_VIEW_EX; + call.map_view_ex.handle = wine_server_obj_handle(handle); + call.map_view_ex.addr = wine_server_client_ptr(*addr_ptr); + call.map_view_ex.size = *size_ptr; + call.map_view_ex.offset = offset.QuadPart; + call.map_view_ex.limit_low = limit_low; + call.map_view_ex.limit_high = limit_high; + call.map_view_ex.alloc_type = alloc_type; + call.map_view_ex.prot = protect; + call.map_view_ex.machine = machine; + status = server_queue_process_apc(process, &call, &result); + if (status != STATUS_SUCCESS) + return status; - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; - - memset( &call, 0, sizeof(call) ); - - call.map_view_ex.type = APC_MAP_VIEW_EX; - call.map_view_ex.handle = wine_server_obj_handle( handle ); - call.map_view_ex.addr = wine_server_client_ptr( *addr_ptr ); - call.map_view_ex.size = *size_ptr; - call.map_view_ex.offset = offset.QuadPart; - call.map_view_ex.limit_low = limit_low; - call.map_view_ex.limit_high = limit_high; - call.map_view_ex.alloc_type = alloc_type; - call.map_view_ex.prot = protect; - call.map_view_ex.machine = machine; - status = server_queue_process_apc( process, &call, &result ); - if (status != STATUS_SUCCESS) return status; - - if (NT_SUCCESS(result.map_view_ex.status)) - { - *addr_ptr = wine_server_get_ptr( result.map_view_ex.addr ); - *size_ptr = result.map_view_ex.size; - } - return result.map_view_ex.status; + if (NT_SUCCESS(result.map_view_ex.status)) { + *addr_ptr = wine_server_get_ptr(result.map_view_ex.addr); + *size_ptr = result.map_view_ex.size; } + return result.map_view_ex.status; + } - return virtual_map_section( handle, addr_ptr, limit_low, limit_high, 0, - offset_ptr, size_ptr, alloc_type, protect, machine ); + return virtual_map_section(handle, addr_ptr, limit_low, limit_high, 0, + offset_ptr, size_ptr, alloc_type, protect, + machine); } - /*********************************************************************** * unmap_view_of_section * * NtUnmapViewOfSection[Ex] implementation. */ -static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr, ULONG flags ) -{ - struct file_view *view; - unsigned int status = STATUS_NOT_MAPPED_VIEW; - sigset_t sigset; - - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; - - memset( &call, 0, sizeof(call) ); +static NTSTATUS unmap_view_of_section(HANDLE process, PVOID addr, ULONG flags) { + struct file_view *view; + unsigned int status = STATUS_NOT_MAPPED_VIEW; + sigset_t sigset; - call.unmap_view.type = APC_UNMAP_VIEW; - call.unmap_view.addr = wine_server_client_ptr( addr ); - call.unmap_view.flags = flags; - status = server_queue_process_apc( process, &call, &result ); - if (status == STATUS_SUCCESS) status = result.unmap_view.status; - return status; - } + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if (!(view = find_view( addr, 0 )) || is_view_valloc( view )) goto done; + memset(&call, 0, sizeof(call)); - if (flags & MEM_PRESERVE_PLACEHOLDER && !(view->protect & VPROT_PLACEHOLDER)) - { - status = STATUS_CONFLICTING_ADDRESSES; - goto done; - } - if (view->protect & VPROT_SYSTEM) - { - struct builtin_module *builtin; - - LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry ) - { - if (builtin->module != view->base) continue; - if (builtin->refcount > 1) - { - TRACE( "not freeing in-use builtin %p\n", view->base ); - builtin->refcount--; - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return STATUS_SUCCESS; - } - } - } + call.unmap_view.type = APC_UNMAP_VIEW; + call.unmap_view.addr = wine_server_client_ptr(addr); + call.unmap_view.flags = flags; + status = server_queue_process_apc(process, &call, &result); + if (status == STATUS_SUCCESS) + status = result.unmap_view.status; + return status; + } + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + if (!(view = find_view(addr, 0)) || is_view_valloc(view)) + goto done; + + if (flags & MEM_PRESERVE_PLACEHOLDER && + !(view->protect & VPROT_PLACEHOLDER)) { + status = STATUS_CONFLICTING_ADDRESSES; + goto done; + } + if (view->protect & VPROT_SYSTEM) { + struct builtin_module *builtin; - SERVER_START_REQ( unmap_view ) - { - req->base = wine_server_client_ptr( view->base ); - status = wine_server_call( req ); - } - SERVER_END_REQ; - if (!status) - { - if (view->protect & SEC_IMAGE) release_builtin_module( view->base ); - if (flags & MEM_PRESERVE_PLACEHOLDER) free_pages_preserve_placeholder( view, view->base, view->size ); - else delete_view( view ); - } - else FIXME( "failed to unmap %p %x\n", view->base, status ); + LIST_FOR_EACH_ENTRY(builtin, &builtin_modules, struct builtin_module, + entry) { + if (builtin->module != view->base) + continue; + if (builtin->refcount > 1) { + TRACE("not freeing in-use builtin %p\n", view->base); + builtin->refcount--; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return STATUS_SUCCESS; + } + } + } + + SERVER_START_REQ(unmap_view) { + req->base = wine_server_client_ptr(view->base); + status = wine_server_call(req); + } + SERVER_END_REQ; + if (!status) { + if (view->protect & SEC_IMAGE) + release_builtin_module(view->base); + if (flags & MEM_PRESERVE_PLACEHOLDER) + free_pages_preserve_placeholder(view, view->base, view->size); + else + delete_view(view); + } else + FIXME("failed to unmap %p %x\n", view->base, status); done: - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return status; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return status; } - /*********************************************************************** * NtUnmapViewOfSection (NTDLL.@) * ZwUnmapViewOfSection (NTDLL.@) */ -NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) -{ - return unmap_view_of_section( process, addr, 0 ); +NTSTATUS WINAPI NtUnmapViewOfSection(HANDLE process, PVOID addr) { + return unmap_view_of_section(process, addr, 0); } /*********************************************************************** * NtUnmapViewOfSectionEx (NTDLL.@) * ZwUnmapViewOfSectionEx (NTDLL.@) */ -NTSTATUS WINAPI NtUnmapViewOfSectionEx( HANDLE process, PVOID addr, ULONG flags ) -{ - static const ULONG type_mask = MEM_UNMAP_WITH_TRANSIENT_BOOST | MEM_PRESERVE_PLACEHOLDER; +NTSTATUS WINAPI NtUnmapViewOfSectionEx(HANDLE process, PVOID addr, + ULONG flags) { + static const ULONG type_mask = + MEM_UNMAP_WITH_TRANSIENT_BOOST | MEM_PRESERVE_PLACEHOLDER; - if (flags & ~type_mask) - { - WARN( "Unsupported flags %#x.\n", (int)flags ); - return STATUS_INVALID_PARAMETER; - } - if (flags & MEM_UNMAP_WITH_TRANSIENT_BOOST) FIXME( "Ignoring MEM_UNMAP_WITH_TRANSIENT_BOOST.\n" ); - return unmap_view_of_section( process, addr, flags ); + if (flags & ~type_mask) { + WARN("Unsupported flags %#x.\n", (int)flags); + return STATUS_INVALID_PARAMETER; + } + if (flags & MEM_UNMAP_WITH_TRANSIENT_BOOST) + FIXME("Ignoring MEM_UNMAP_WITH_TRANSIENT_BOOST.\n"); + return unmap_view_of_section(process, addr, flags); } /****************************************************************************** @@ -5877,32 +5923,32 @@ NTSTATUS WINAPI NtUnmapViewOfSectionEx( HANDLE process, PVOID addr, ULONG flags * * Helper for NtQuerySection. */ -void virtual_fill_image_information( const struct pe_image_info *pe_info, SECTION_IMAGE_INFORMATION *info ) -{ - info->TransferAddress = wine_server_get_ptr( pe_info->base + pe_info->entry_point ); - info->ZeroBits = pe_info->zerobits; - info->MaximumStackSize = pe_info->stack_size; - info->CommittedStackSize = pe_info->stack_commit; - info->SubSystemType = pe_info->subsystem; - info->MinorSubsystemVersion = pe_info->subsystem_minor; - info->MajorSubsystemVersion = pe_info->subsystem_major; - info->MajorOperatingSystemVersion = pe_info->osversion_major; - info->MinorOperatingSystemVersion = pe_info->osversion_minor; - info->ImageCharacteristics = pe_info->image_charact; - info->DllCharacteristics = pe_info->dll_charact; - info->Machine = pe_info->machine; - info->ImageContainsCode = pe_info->contains_code; - info->ImageFlags = pe_info->image_flags; - info->LoaderFlags = pe_info->loader_flags; - info->ImageFileSize = pe_info->file_size; - info->CheckSum = pe_info->checksum; +void virtual_fill_image_information(const struct pe_image_info *pe_info, + SECTION_IMAGE_INFORMATION *info) { + info->TransferAddress = + wine_server_get_ptr(pe_info->base + pe_info->entry_point); + info->ZeroBits = pe_info->zerobits; + info->MaximumStackSize = pe_info->stack_size; + info->CommittedStackSize = pe_info->stack_commit; + info->SubSystemType = pe_info->subsystem; + info->MinorSubsystemVersion = pe_info->subsystem_minor; + info->MajorSubsystemVersion = pe_info->subsystem_major; + info->MajorOperatingSystemVersion = pe_info->osversion_major; + info->MinorOperatingSystemVersion = pe_info->osversion_minor; + info->ImageCharacteristics = pe_info->image_charact; + info->DllCharacteristics = pe_info->dll_charact; + info->Machine = pe_info->machine; + info->ImageContainsCode = pe_info->contains_code; + info->ImageFlags = pe_info->image_flags; + info->LoaderFlags = pe_info->loader_flags; + info->ImageFileSize = pe_info->file_size; + info->CheckSum = pe_info->checksum; #ifndef _WIN64 /* don't return 64-bit values to 32-bit processes */ - if (is_machine_64bit( pe_info->machine )) - { - info->TransferAddress = (void *)0x81231234; /* sic */ - info->MaximumStackSize = 0x100000; - info->CommittedStackSize = 0x10000; - } + if (is_machine_64bit(pe_info->machine)) { + info->TransferAddress = (void *)0x81231234; /* sic */ + info->MaximumStackSize = 0x100000; + info->CommittedStackSize = 0x10000; + } #endif } @@ -5910,433 +5956,417 @@ void virtual_fill_image_information( const struct pe_image_info *pe_info, SECTIO * NtQuerySection (NTDLL.@) * ZwQuerySection (NTDLL.@) */ -NTSTATUS WINAPI NtQuerySection( HANDLE handle, SECTION_INFORMATION_CLASS class, void *ptr, - SIZE_T size, SIZE_T *ret_size ) -{ - unsigned int status; - struct pe_image_info image_info; - - switch (class) - { - case SectionBasicInformation: - if (size < sizeof(SECTION_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; - break; - case SectionImageInformation: - if (size < sizeof(SECTION_IMAGE_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; - break; - default: - FIXME( "class %u not implemented\n", class ); - return STATUS_NOT_IMPLEMENTED; - } - if (!ptr) return STATUS_ACCESS_VIOLATION; - - SERVER_START_REQ( get_mapping_info ) - { - req->handle = wine_server_obj_handle( handle ); - req->access = SECTION_QUERY; - wine_server_set_reply( req, &image_info, sizeof(image_info) ); - if (!(status = wine_server_call( req ))) - { - if (class == SectionBasicInformation) - { - SECTION_BASIC_INFORMATION *info = ptr; - info->Attributes = reply->flags; - info->BaseAddress = NULL; - info->Size.QuadPart = reply->size; - if (ret_size) *ret_size = sizeof(*info); - } - else if (reply->flags & SEC_IMAGE) - { - SECTION_IMAGE_INFORMATION *info = ptr; - virtual_fill_image_information( &image_info, info ); - if (ret_size) *ret_size = sizeof(*info); - } - else status = STATUS_SECTION_NOT_IMAGE; - } - } - SERVER_END_REQ; - - return status; +NTSTATUS WINAPI NtQuerySection(HANDLE handle, SECTION_INFORMATION_CLASS class, + void *ptr, SIZE_T size, SIZE_T *ret_size) { + unsigned int status; + struct pe_image_info image_info; + + switch (class) { + case SectionBasicInformation: + if (size < sizeof(SECTION_BASIC_INFORMATION)) + return STATUS_INFO_LENGTH_MISMATCH; + break; + case SectionImageInformation: + if (size < sizeof(SECTION_IMAGE_INFORMATION)) + return STATUS_INFO_LENGTH_MISMATCH; + break; + default: + FIXME("class %u not implemented\n", class); + return STATUS_NOT_IMPLEMENTED; + } + if (!ptr) + return STATUS_ACCESS_VIOLATION; + + SERVER_START_REQ(get_mapping_info) { + req->handle = wine_server_obj_handle(handle); + req->access = SECTION_QUERY; + wine_server_set_reply(req, &image_info, sizeof(image_info)); + if (!(status = wine_server_call(req))) { + if (class == SectionBasicInformation) { + SECTION_BASIC_INFORMATION *info = ptr; + info->Attributes = reply->flags; + info->BaseAddress = NULL; + info->Size.QuadPart = reply->size; + if (ret_size) + *ret_size = sizeof(*info); + } else if (reply->flags & SEC_IMAGE) { + SECTION_IMAGE_INFORMATION *info = ptr; + virtual_fill_image_information(&image_info, info); + if (ret_size) + *ret_size = sizeof(*info); + } else + status = STATUS_SECTION_NOT_IMAGE; + } + } + SERVER_END_REQ; + + return status; } - /*********************************************************************** * NtFlushVirtualMemory (NTDLL.@) * ZwFlushVirtualMemory (NTDLL.@) */ -NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr, - SIZE_T *size_ptr, ULONG unknown ) -{ - struct file_view *view; - unsigned int status = STATUS_SUCCESS; - sigset_t sigset; - void *addr = ROUND_ADDR( *addr_ptr, page_mask ); - - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; - - memset( &call, 0, sizeof(call) ); - - call.virtual_flush.type = APC_VIRTUAL_FLUSH; - call.virtual_flush.addr = wine_server_client_ptr( addr ); - call.virtual_flush.size = *size_ptr; - status = server_queue_process_apc( process, &call, &result ); - if (status != STATUS_SUCCESS) return status; - - if (result.virtual_flush.status == STATUS_SUCCESS) - { - *addr_ptr = wine_server_get_ptr( result.virtual_flush.addr ); - *size_ptr = result.virtual_flush.size; - } - return result.virtual_flush.status; - } - - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if (!(view = find_view( addr, *size_ptr ))) status = STATUS_INVALID_PARAMETER; - else - { - if (!*size_ptr) *size_ptr = view->size; - *addr_ptr = addr; +NTSTATUS WINAPI NtFlushVirtualMemory(HANDLE process, LPCVOID *addr_ptr, + SIZE_T *size_ptr, ULONG unknown) { + struct file_view *view; + unsigned int status = STATUS_SUCCESS; + sigset_t sigset; + void *addr = ROUND_ADDR(*addr_ptr, page_mask); + + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; + + memset(&call, 0, sizeof(call)); + + call.virtual_flush.type = APC_VIRTUAL_FLUSH; + call.virtual_flush.addr = wine_server_client_ptr(addr); + call.virtual_flush.size = *size_ptr; + status = server_queue_process_apc(process, &call, &result); + if (status != STATUS_SUCCESS) + return status; + + if (result.virtual_flush.status == STATUS_SUCCESS) { + *addr_ptr = wine_server_get_ptr(result.virtual_flush.addr); + *size_ptr = result.virtual_flush.size; + } + return result.virtual_flush.status; + } + + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + if (!(view = find_view(addr, *size_ptr))) + status = STATUS_INVALID_PARAMETER; + else { + if (!*size_ptr) + *size_ptr = view->size; + *addr_ptr = addr; #ifdef MS_ASYNC - if (msync( addr, *size_ptr, MS_ASYNC )) status = STATUS_NOT_MAPPED_DATA; + if (msync(addr, *size_ptr, MS_ASYNC)) + status = STATUS_NOT_MAPPED_DATA; #endif - } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return status; + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return status; } - /*********************************************************************** * NtGetWriteWatch (NTDLL.@) * ZwGetWriteWatch (NTDLL.@) */ -NTSTATUS WINAPI NtGetWriteWatch( HANDLE process, ULONG flags, PVOID base, SIZE_T size, PVOID *addresses, - ULONG_PTR *count, ULONG *granularity ) -{ - NTSTATUS status = STATUS_SUCCESS; - sigset_t sigset; +NTSTATUS WINAPI NtGetWriteWatch(HANDLE process, ULONG flags, PVOID base, + SIZE_T size, PVOID *addresses, ULONG_PTR *count, + ULONG *granularity) { + NTSTATUS status = STATUS_SUCCESS; + sigset_t sigset; - size = ROUND_SIZE( base, size ); - base = ROUND_ADDR( base, page_mask ); + size = ROUND_SIZE(base, size); + base = ROUND_ADDR(base, page_mask); - if (!count || !granularity) return STATUS_ACCESS_VIOLATION; - if (!*count || !size) return STATUS_INVALID_PARAMETER; - if (flags & ~WRITE_WATCH_FLAG_RESET) return STATUS_INVALID_PARAMETER; + if (!count || !granularity) + return STATUS_ACCESS_VIOLATION; + if (!*count || !size) + return STATUS_INVALID_PARAMETER; + if (flags & ~WRITE_WATCH_FLAG_RESET) + return STATUS_INVALID_PARAMETER; - if (!addresses) return STATUS_ACCESS_VIOLATION; + if (!addresses) + return STATUS_ACCESS_VIOLATION; - TRACE( "%p %x %p-%p %p %lu\n", process, (int)flags, base, (char *)base + size, - addresses, *count ); + TRACE("%p %x %p-%p %p %lu\n", process, (int)flags, base, (char *)base + size, + addresses, *count); - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); + server_enter_uninterrupted_section(&virtual_mutex, &sigset); - if (is_write_watch_range( base, size )) - { - ULONG_PTR pos = 0; - char *addr = base; - char *end = addr + size; - - while (pos < *count && addr < end) - { - if (!(get_page_vprot( addr ) & VPROT_WRITEWATCH)) addresses[pos++] = addr; - addr += page_size; - } - if (flags & WRITE_WATCH_FLAG_RESET) reset_write_watches( base, addr - (char *)base ); - *count = pos; - *granularity = page_size; + if (is_write_watch_range(base, size)) { + ULONG_PTR pos = 0; + char *addr = base; + char *end = addr + size; + + while (pos < *count && addr < end) { + if (!(get_page_vprot(addr) & VPROT_WRITEWATCH)) + addresses[pos++] = addr; + addr += page_size; } - else status = STATUS_INVALID_PARAMETER; + if (flags & WRITE_WATCH_FLAG_RESET) + reset_write_watches(base, addr - (char *)base); + *count = pos; + *granularity = page_size; + } else + status = STATUS_INVALID_PARAMETER; - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return status; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return status; } - /*********************************************************************** * NtResetWriteWatch (NTDLL.@) * ZwResetWriteWatch (NTDLL.@) */ -NTSTATUS WINAPI NtResetWriteWatch( HANDLE process, PVOID base, SIZE_T size ) -{ - NTSTATUS status = STATUS_SUCCESS; - sigset_t sigset; +NTSTATUS WINAPI NtResetWriteWatch(HANDLE process, PVOID base, SIZE_T size) { + NTSTATUS status = STATUS_SUCCESS; + sigset_t sigset; - size = ROUND_SIZE( base, size ); - base = ROUND_ADDR( base, page_mask ); + size = ROUND_SIZE(base, size); + base = ROUND_ADDR(base, page_mask); - TRACE( "%p %p-%p\n", process, base, (char *)base + size ); + TRACE("%p %p-%p\n", process, base, (char *)base + size); - if (!size) return STATUS_INVALID_PARAMETER; + if (!size) + return STATUS_INVALID_PARAMETER; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); + server_enter_uninterrupted_section(&virtual_mutex, &sigset); - if (is_write_watch_range( base, size )) - reset_write_watches( base, size ); - else - status = STATUS_INVALID_PARAMETER; + if (is_write_watch_range(base, size)) + reset_write_watches(base, size); + else + status = STATUS_INVALID_PARAMETER; - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return status; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return status; } - /*********************************************************************** * NtReadVirtualMemory (NTDLL.@) * ZwReadVirtualMemory (NTDLL.@) */ -NTSTATUS WINAPI NtReadVirtualMemory( HANDLE process, const void *addr, void *buffer, - SIZE_T size, SIZE_T *bytes_read ) -{ - unsigned int status; +NTSTATUS WINAPI NtReadVirtualMemory(HANDLE process, const void *addr, + void *buffer, SIZE_T size, + SIZE_T *bytes_read) { + unsigned int status; - if (!virtual_check_buffer_for_write( buffer, size )) - { - status = STATUS_ACCESS_VIOLATION; - size = 0; + if (!virtual_check_buffer_for_write(buffer, size)) { + status = STATUS_ACCESS_VIOLATION; + size = 0; + } else if (process == GetCurrentProcess()) { + __TRY { + memmove(buffer, addr, size); + status = STATUS_SUCCESS; } - else if (process == GetCurrentProcess()) - { - __TRY - { - memmove( buffer, addr, size ); - status = STATUS_SUCCESS; - } - __EXCEPT - { - status = STATUS_PARTIAL_COPY; - size = 0; - } - __ENDTRY + __EXCEPT { + status = STATUS_PARTIAL_COPY; + size = 0; } - else - { - SERVER_START_REQ( read_process_memory ) - { - req->handle = wine_server_obj_handle( process ); - req->addr = wine_server_client_ptr( addr ); - wine_server_set_reply( req, buffer, size ); - if ((status = wine_server_call( req ))) size = 0; - } - SERVER_END_REQ; + __ENDTRY + } else { + SERVER_START_REQ(read_process_memory) { + req->handle = wine_server_obj_handle(process); + req->addr = wine_server_client_ptr(addr); + wine_server_set_reply(req, buffer, size); + if ((status = wine_server_call(req))) + size = 0; } - if (bytes_read) *bytes_read = size; - return status; + SERVER_END_REQ; + } + if (bytes_read) + *bytes_read = size; + return status; } - /*********************************************************************** * NtWriteVirtualMemory (NTDLL.@) * ZwWriteVirtualMemory (NTDLL.@) */ -NTSTATUS WINAPI NtWriteVirtualMemory( HANDLE process, void *addr, const void *buffer, - SIZE_T size, SIZE_T *bytes_written ) -{ - unsigned int status; - - if (virtual_check_buffer_for_read( buffer, size )) - { - SERVER_START_REQ( write_process_memory ) - { - req->handle = wine_server_obj_handle( process ); - req->addr = wine_server_client_ptr( addr ); - wine_server_add_data( req, buffer, size ); - if ((status = wine_server_call( req ))) size = 0; - } - SERVER_END_REQ; - } - else - { - status = STATUS_PARTIAL_COPY; +NTSTATUS WINAPI NtWriteVirtualMemory(HANDLE process, void *addr, + const void *buffer, SIZE_T size, + SIZE_T *bytes_written) { + unsigned int status; + + if (virtual_check_buffer_for_read(buffer, size)) { + SERVER_START_REQ(write_process_memory) { + req->handle = wine_server_obj_handle(process); + req->addr = wine_server_client_ptr(addr); + wine_server_add_data(req, buffer, size); + if ((status = wine_server_call(req))) size = 0; } - if (bytes_written) *bytes_written = size; - return status; + SERVER_END_REQ; + } else { + status = STATUS_PARTIAL_COPY; + size = 0; + } + if (bytes_written) + *bytes_written = size; + return status; } - /*********************************************************************** * NtAreMappedFilesTheSame (NTDLL.@) * ZwAreMappedFilesTheSame (NTDLL.@) */ -NTSTATUS WINAPI NtAreMappedFilesTheSame(PVOID addr1, PVOID addr2) -{ - struct file_view *view1, *view2; - unsigned int status; - sigset_t sigset; +NTSTATUS WINAPI NtAreMappedFilesTheSame(PVOID addr1, PVOID addr2) { + struct file_view *view1, *view2; + unsigned int status; + sigset_t sigset; - TRACE("%p %p\n", addr1, addr2); + TRACE("%p %p\n", addr1, addr2); - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); + server_enter_uninterrupted_section(&virtual_mutex, &sigset); - view1 = find_view( addr1, 0 ); - view2 = find_view( addr2, 0 ); + view1 = find_view(addr1, 0); + view2 = find_view(addr2, 0); - if (!view1 || !view2) - status = STATUS_INVALID_ADDRESS; - else if (is_view_valloc( view1 ) || is_view_valloc( view2 )) - status = STATUS_CONFLICTING_ADDRESSES; - else if (view1 == view2) - status = STATUS_SUCCESS; - else if ((view1->protect & VPROT_SYSTEM) || (view2->protect & VPROT_SYSTEM)) - status = STATUS_NOT_SAME_DEVICE; - else - { - SERVER_START_REQ( is_same_mapping ) - { - req->base1 = wine_server_client_ptr( view1->base ); - req->base2 = wine_server_client_ptr( view2->base ); - status = wine_server_call( req ); - } - SERVER_END_REQ; + if (!view1 || !view2) + status = STATUS_INVALID_ADDRESS; + else if (is_view_valloc(view1) || is_view_valloc(view2)) + status = STATUS_CONFLICTING_ADDRESSES; + else if (view1 == view2) + status = STATUS_SUCCESS; + else if ((view1->protect & VPROT_SYSTEM) || (view2->protect & VPROT_SYSTEM)) + status = STATUS_NOT_SAME_DEVICE; + else { + SERVER_START_REQ(is_same_mapping) { + req->base1 = wine_server_client_ptr(view1->base); + req->base2 = wine_server_client_ptr(view2->base); + status = wine_server_call(req); } + SERVER_END_REQ; + } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return status; + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return status; } +static NTSTATUS prefetch_memory(HANDLE process, ULONG_PTR count, + PMEMORY_RANGE_ENTRY addresses, ULONG flags) { + ULONG_PTR i; + PVOID base; + SIZE_T size; + static unsigned int once; -static NTSTATUS prefetch_memory( HANDLE process, ULONG_PTR count, - PMEMORY_RANGE_ENTRY addresses, ULONG flags ) -{ - ULONG_PTR i; - PVOID base; - SIZE_T size; - static unsigned int once; - - if (!once++) - { - FIXME( "(process=%p,flags=%u) NtSetInformationVirtualMemory(VmPrefetchInformation) partial stub\n", - process, (int)flags ); - } + if (!once++) { + FIXME("(process=%p,flags=%u) " + "NtSetInformationVirtualMemory(VmPrefetchInformation) partial stub\n", + process, (int)flags); + } - for (i = 0; i < count; i++) - { - if (!addresses[i].NumberOfBytes) return STATUS_INVALID_PARAMETER_4; - } + for (i = 0; i < count; i++) { + if (!addresses[i].NumberOfBytes) + return STATUS_INVALID_PARAMETER_4; + } - if (process != NtCurrentProcess()) return STATUS_SUCCESS; + if (process != NtCurrentProcess()) + return STATUS_SUCCESS; - for (i = 0; i < count; i++) - { - base = ROUND_ADDR( addresses[i].VirtualAddress, page_mask ); - size = ROUND_SIZE( addresses[i].VirtualAddress, addresses[i].NumberOfBytes ); - madvise( base, size, MADV_WILLNEED ); - } + for (i = 0; i < count; i++) { + base = ROUND_ADDR(addresses[i].VirtualAddress, page_mask); + size = ROUND_SIZE(addresses[i].VirtualAddress, addresses[i].NumberOfBytes); + madvise(base, size, MADV_WILLNEED); + } - return STATUS_SUCCESS; + return STATUS_SUCCESS; } -static NTSTATUS set_dirty_state_information( ULONG_PTR count, MEMORY_RANGE_ENTRY *addresses ) -{ - ULONG_PTR i; - sigset_t sigset; - NTSTATUS ret = STATUS_SUCCESS; +static NTSTATUS set_dirty_state_information(ULONG_PTR count, + MEMORY_RANGE_ENTRY *addresses) { + ULONG_PTR i; + sigset_t sigset; + NTSTATUS ret = STATUS_SUCCESS; - server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - for (i = 0; i < count; i++) - { - void *base = ROUND_ADDR( addresses[i].VirtualAddress, page_mask ); - SIZE_T size = ROUND_SIZE( addresses[i].VirtualAddress, addresses[i].NumberOfBytes ); - struct file_view *view = find_view( base, size ); - - if (view) - { - if (set_page_vprot_exec_write_protect( base, size )) - mprotect_range( base, size, 0, 0 ); - } - else - { - ret = STATUS_MEMORY_NOT_ALLOCATED; - break; - } + server_enter_uninterrupted_section(&virtual_mutex, &sigset); + for (i = 0; i < count; i++) { + void *base = ROUND_ADDR(addresses[i].VirtualAddress, page_mask); + SIZE_T size = + ROUND_SIZE(addresses[i].VirtualAddress, addresses[i].NumberOfBytes); + struct file_view *view = find_view(base, size); + + if (view) { + if (set_page_vprot_exec_write_protect(base, size)) + mprotect_range(base, size, 0, 0); + } else { + ret = STATUS_MEMORY_NOT_ALLOCATED; + break; } - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return ret; + } + server_leave_uninterrupted_section(&virtual_mutex, &sigset); + return ret; } /*********************************************************************** * NtSetInformationVirtualMemory (NTDLL.@) * ZwSetInformationVirtualMemory (NTDLL.@) */ -NTSTATUS WINAPI NtSetInformationVirtualMemory( HANDLE process, - VIRTUAL_MEMORY_INFORMATION_CLASS info_class, - ULONG_PTR count, PMEMORY_RANGE_ENTRY addresses, - PVOID ptr, ULONG size ) -{ - TRACE("(%p, info_class=%d, %lu, %p, %p, %u)\n", - process, info_class, count, addresses, ptr, (int)size); - - switch (info_class) - { - case VmPrefetchInformation: - if (!ptr) return STATUS_INVALID_PARAMETER_5; - if (size != sizeof(ULONG)) return STATUS_INVALID_PARAMETER_6; - if (!count) return STATUS_INVALID_PARAMETER_3; - return prefetch_memory( process, count, addresses, *(ULONG *)ptr ); - - case VmPageDirtyStateInformation: - if (process != GetCurrentProcess()) return STATUS_NOT_SUPPORTED; - if (!enable_write_exceptions) return STATUS_NOT_SUPPORTED; - if (!ptr) return STATUS_INVALID_PARAMETER_5; - if (size != sizeof(ULONG)) return STATUS_INVALID_PARAMETER_6; - if (*(ULONG *)ptr) return STATUS_INVALID_PARAMETER_5; - if (!count) return STATUS_INVALID_PARAMETER_3; - return set_dirty_state_information( count, addresses ); +NTSTATUS WINAPI NtSetInformationVirtualMemory( + HANDLE process, VIRTUAL_MEMORY_INFORMATION_CLASS info_class, + ULONG_PTR count, PMEMORY_RANGE_ENTRY addresses, PVOID ptr, ULONG size) { + TRACE("(%p, info_class=%d, %lu, %p, %p, %u)\n", process, info_class, count, + addresses, ptr, (int)size); - default: - FIXME("(%p,info_class=%d,%lu,%p,%p,%u) Unknown information class\n", - process, info_class, count, addresses, ptr, (int)size); - return STATUS_INVALID_PARAMETER_2; - } + switch (info_class) { + case VmPrefetchInformation: + if (!ptr) + return STATUS_INVALID_PARAMETER_5; + if (size != sizeof(ULONG)) + return STATUS_INVALID_PARAMETER_6; + if (!count) + return STATUS_INVALID_PARAMETER_3; + return prefetch_memory(process, count, addresses, *(ULONG *)ptr); + + case VmPageDirtyStateInformation: + if (process != GetCurrentProcess()) + return STATUS_NOT_SUPPORTED; + if (!enable_write_exceptions) + return STATUS_NOT_SUPPORTED; + if (!ptr) + return STATUS_INVALID_PARAMETER_5; + if (size != sizeof(ULONG)) + return STATUS_INVALID_PARAMETER_6; + if (*(ULONG *)ptr) + return STATUS_INVALID_PARAMETER_5; + if (!count) + return STATUS_INVALID_PARAMETER_3; + return set_dirty_state_information(count, addresses); + + default: + FIXME("(%p,info_class=%d,%lu,%p,%p,%u) Unknown information class\n", + process, info_class, count, addresses, ptr, (int)size); + return STATUS_INVALID_PARAMETER_2; + } } - /********************************************************************** * NtFlushInstructionCache (NTDLL.@) */ -NTSTATUS WINAPI NtFlushInstructionCache( HANDLE handle, const void *addr, SIZE_T size ) -{ +NTSTATUS WINAPI NtFlushInstructionCache(HANDLE handle, const void *addr, + SIZE_T size) { #if defined(__x86_64__) || defined(__i386__) - /* no-op */ + /* no-op */ #elif defined(HAVE___CLEAR_CACHE) - if (handle == GetCurrentProcess()) - { - __clear_cache( (char *)addr, (char *)addr + size ); - } - else - { - static int once; - if (!once++) FIXME( "%p %p %ld other process not supported\n", handle, addr, size ); - } -#else + if (handle == GetCurrentProcess()) { + __clear_cache((char *)addr, (char *)addr + size); + } else { static int once; - if (!once++) FIXME( "%p %p %ld\n", handle, addr, size ); + if (!once++) + FIXME("%p %p %ld other process not supported\n", handle, addr, size); + } +#else + static int once; + if (!once++) + FIXME("%p %p %ld\n", handle, addr, size); #endif - return STATUS_SUCCESS; + return STATUS_SUCCESS; } - /********************************************************************** * NtFlushProcessWriteBuffers (NTDLL.@) */ -NTSTATUS WINAPI NtFlushProcessWriteBuffers(void) -{ - static int once = 0; - if (!once++) FIXME( "stub\n" ); - return STATUS_SUCCESS; +NTSTATUS WINAPI NtFlushProcessWriteBuffers(void) { + static int once = 0; + if (!once++) + FIXME("stub\n"); + return STATUS_SUCCESS; } - /********************************************************************** * NtCreatePagingFile (NTDLL.@) */ -NTSTATUS WINAPI NtCreatePagingFile( UNICODE_STRING *name, LARGE_INTEGER *min_size, - LARGE_INTEGER *max_size, LARGE_INTEGER *actual_size ) -{ - FIXME( "(%s %p %p %p) stub\n", debugstr_us(name), min_size, max_size, actual_size ); - return STATUS_SUCCESS; +NTSTATUS WINAPI NtCreatePagingFile(UNICODE_STRING *name, + LARGE_INTEGER *min_size, + LARGE_INTEGER *max_size, + LARGE_INTEGER *actual_size) { + FIXME("(%s %p %p %p) stub\n", debugstr_us(name), min_size, max_size, + actual_size); + return STATUS_SUCCESS; } #ifndef _WIN64 @@ -6345,162 +6375,159 @@ NTSTATUS WINAPI NtCreatePagingFile( UNICODE_STRING *name, LARGE_INTEGER *min_siz * NtWow64AllocateVirtualMemory64 (NTDLL.@) * ZwWow64AllocateVirtualMemory64 (NTDLL.@) */ -NTSTATUS WINAPI NtWow64AllocateVirtualMemory64( HANDLE process, ULONG64 *ret, ULONG64 zero_bits, - ULONG64 *size_ptr, ULONG type, ULONG protect ) -{ - void *base; - SIZE_T size; - unsigned int status; - - TRACE("%p %s %s %x %08x\n", process, - wine_dbgstr_longlong(*ret), wine_dbgstr_longlong(*size_ptr), (int)type, (int)protect ); - - if (!*size_ptr) return STATUS_INVALID_PARAMETER_4; - if (zero_bits > 21 && zero_bits < 32) return STATUS_INVALID_PARAMETER_3; - - if (process != NtCurrentProcess()) - { - union apc_call call; - union apc_result result; - - memset( &call, 0, sizeof(call) ); - - call.virtual_alloc.type = APC_VIRTUAL_ALLOC; - call.virtual_alloc.addr = *ret; - call.virtual_alloc.size = *size_ptr; - call.virtual_alloc.zero_bits = zero_bits; - call.virtual_alloc.op_type = type; - call.virtual_alloc.prot = protect; - status = server_queue_process_apc( process, &call, &result ); - if (status != STATUS_SUCCESS) return status; - - if (result.virtual_alloc.status == STATUS_SUCCESS) - { - *ret = result.virtual_alloc.addr; - *size_ptr = result.virtual_alloc.size; - } - return result.virtual_alloc.status; - } - - base = (void *)(ULONG_PTR)*ret; - size = *size_ptr; - if ((ULONG_PTR)base != *ret) return STATUS_CONFLICTING_ADDRESSES; - if (size != *size_ptr) return STATUS_WORKING_SET_LIMIT_RANGE; - - status = NtAllocateVirtualMemory( process, &base, zero_bits, &size, type, protect ); - if (!status) - { - *ret = (ULONG_PTR)base; - *size_ptr = size; - } - return status; +NTSTATUS WINAPI NtWow64AllocateVirtualMemory64(HANDLE process, ULONG64 *ret, + ULONG64 zero_bits, + ULONG64 *size_ptr, ULONG type, + ULONG protect) { + void *base; + SIZE_T size; + unsigned int status; + + TRACE("%p %s %s %x %08x\n", process, wine_dbgstr_longlong(*ret), + wine_dbgstr_longlong(*size_ptr), (int)type, (int)protect); + + if (!*size_ptr) + return STATUS_INVALID_PARAMETER_4; + if (zero_bits > 21 && zero_bits < 32) + return STATUS_INVALID_PARAMETER_3; + + if (process != NtCurrentProcess()) { + union apc_call call; + union apc_result result; + + memset(&call, 0, sizeof(call)); + + call.virtual_alloc.type = APC_VIRTUAL_ALLOC; + call.virtual_alloc.addr = *ret; + call.virtual_alloc.size = *size_ptr; + call.virtual_alloc.zero_bits = zero_bits; + call.virtual_alloc.op_type = type; + call.virtual_alloc.prot = protect; + status = server_queue_process_apc(process, &call, &result); + if (status != STATUS_SUCCESS) + return status; + + if (result.virtual_alloc.status == STATUS_SUCCESS) { + *ret = result.virtual_alloc.addr; + *size_ptr = result.virtual_alloc.size; + } + return result.virtual_alloc.status; + } + + base = (void *)(ULONG_PTR)*ret; + size = *size_ptr; + if ((ULONG_PTR)base != *ret) + return STATUS_CONFLICTING_ADDRESSES; + if (size != *size_ptr) + return STATUS_WORKING_SET_LIMIT_RANGE; + + status = + NtAllocateVirtualMemory(process, &base, zero_bits, &size, type, protect); + if (!status) { + *ret = (ULONG_PTR)base; + *size_ptr = size; + } + return status; } - /*********************************************************************** * NtWow64ReadVirtualMemory64 (NTDLL.@) * ZwWow64ReadVirtualMemory64 (NTDLL.@) */ -NTSTATUS WINAPI NtWow64ReadVirtualMemory64( HANDLE process, ULONG64 addr, void *buffer, - ULONG64 size, ULONG64 *bytes_read ) -{ - unsigned int status; +NTSTATUS WINAPI NtWow64ReadVirtualMemory64(HANDLE process, ULONG64 addr, + void *buffer, ULONG64 size, + ULONG64 *bytes_read) { + unsigned int status; - if (size > MAXLONG) size = MAXLONG; + if (size > MAXLONG) + size = MAXLONG; - if (virtual_check_buffer_for_write( buffer, size )) - { - SERVER_START_REQ( read_process_memory ) - { - req->handle = wine_server_obj_handle( process ); - req->addr = addr; - wine_server_set_reply( req, buffer, size ); - if ((status = wine_server_call( req ))) size = 0; - } - SERVER_END_REQ; - } - else - { - status = STATUS_ACCESS_VIOLATION; + if (virtual_check_buffer_for_write(buffer, size)) { + SERVER_START_REQ(read_process_memory) { + req->handle = wine_server_obj_handle(process); + req->addr = addr; + wine_server_set_reply(req, buffer, size); + if ((status = wine_server_call(req))) size = 0; } - if (bytes_read) *bytes_read = size; - return status; + SERVER_END_REQ; + } else { + status = STATUS_ACCESS_VIOLATION; + size = 0; + } + if (bytes_read) + *bytes_read = size; + return status; } - /*********************************************************************** * NtWow64WriteVirtualMemory64 (NTDLL.@) * ZwWow64WriteVirtualMemory64 (NTDLL.@) */ -NTSTATUS WINAPI NtWow64WriteVirtualMemory64( HANDLE process, ULONG64 addr, const void *buffer, - ULONG64 size, ULONG64 *bytes_written ) -{ - unsigned int status; +NTSTATUS WINAPI NtWow64WriteVirtualMemory64(HANDLE process, ULONG64 addr, + const void *buffer, ULONG64 size, + ULONG64 *bytes_written) { + unsigned int status; - if (size > MAXLONG) size = MAXLONG; + if (size > MAXLONG) + size = MAXLONG; - if (virtual_check_buffer_for_read( buffer, size )) - { - SERVER_START_REQ( write_process_memory ) - { - req->handle = wine_server_obj_handle( process ); - req->addr = addr; - wine_server_add_data( req, buffer, size ); - if ((status = wine_server_call( req ))) size = 0; - } - SERVER_END_REQ; - } - else - { - status = STATUS_PARTIAL_COPY; + if (virtual_check_buffer_for_read(buffer, size)) { + SERVER_START_REQ(write_process_memory) { + req->handle = wine_server_obj_handle(process); + req->addr = addr; + wine_server_add_data(req, buffer, size); + if ((status = wine_server_call(req))) size = 0; } - if (bytes_written) *bytes_written = size; - return status; + SERVER_END_REQ; + } else { + status = STATUS_PARTIAL_COPY; + size = 0; + } + if (bytes_written) + *bytes_written = size; + return status; } - /*********************************************************************** * NtWow64GetNativeSystemInformation (NTDLL.@) * ZwWow64GetNativeSystemInformation (NTDLL.@) */ -NTSTATUS WINAPI NtWow64GetNativeSystemInformation( SYSTEM_INFORMATION_CLASS class, void *info, - ULONG len, ULONG *retlen ) -{ - NTSTATUS status; +NTSTATUS WINAPI NtWow64GetNativeSystemInformation( + SYSTEM_INFORMATION_CLASS class, void *info, ULONG len, ULONG *retlen) { + NTSTATUS status; - switch (class) - { - case SystemCpuInformation: - status = NtQuerySystemInformation( class, info, len, retlen ); - if (!status && is_old_wow64()) - { - SYSTEM_CPU_INFORMATION *cpu = info; - - if (cpu->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) - cpu->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64; - } - return status; - case SystemBasicInformation: - case SystemEmulationBasicInformation: - case SystemEmulationProcessorInformation: - return NtQuerySystemInformation( class, info, len, retlen ); - case SystemNativeBasicInformation: - return NtQuerySystemInformation( SystemBasicInformation, info, len, retlen ); - default: - if (is_old_wow64()) return STATUS_INVALID_INFO_CLASS; - return NtQuerySystemInformation( class, info, len, retlen ); + switch (class) { + case SystemCpuInformation: + status = NtQuerySystemInformation(class, info, len, retlen); + if (!status && is_old_wow64()) { + SYSTEM_CPU_INFORMATION *cpu = info; + + if (cpu->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) + cpu->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64; } + return status; + case SystemBasicInformation: + case SystemEmulationBasicInformation: + case SystemEmulationProcessorInformation: + return NtQuerySystemInformation(class, info, len, retlen); + case SystemNativeBasicInformation: + return NtQuerySystemInformation(SystemBasicInformation, info, len, retlen); + default: + if (is_old_wow64()) + return STATUS_INVALID_INFO_CLASS; + return NtQuerySystemInformation(class, info, len, retlen); + } } /*********************************************************************** * NtWow64IsProcessorFeaturePresent (NTDLL.@) * ZwWow64IsProcessorFeaturePresent (NTDLL.@) */ -NTSTATUS WINAPI NtWow64IsProcessorFeaturePresent( UINT feature ) -{ - return feature < PROCESSOR_FEATURE_MAX && user_shared_data->ProcessorFeatures[feature]; +NTSTATUS WINAPI NtWow64IsProcessorFeaturePresent(UINT feature) { + return feature < PROCESSOR_FEATURE_MAX && + user_shared_data->ProcessorFeatures[feature]; } -#endif /* _WIN64 */ +#endif /* _WIN64 */ From f297eb21b64d4169e2f687fb9ff46d43a0f47863 Mon Sep 17 00:00:00 2001 From: WINDROID-EMU <45230455+WINDROID-EMU@users.noreply.github.com> Date: Sat, 21 Feb 2026 22:26:00 -0300 Subject: [PATCH 3/5] Implement timeout in joystick device enumeration and creation Added a timeout mechanism to the joystick enumeration and creation functions to prevent infinite waiting. para o jogo prototype --- dlls/dinput/joystick_micewine.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/dinput/joystick_micewine.c b/dlls/dinput/joystick_micewine.c index 7935828f346f..b05c2692e00b 100644 --- a/dlls/dinput/joystick_micewine.c +++ b/dlls/dinput/joystick_micewine.c @@ -558,10 +558,11 @@ static void start_update_thread(void) HRESULT micewine_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, DWORD version, int index ) { + int timeout = 0; start_update_thread(); if (index > XUSER_MAX_COUNT) return DI_NOTATTACHED; - while (!dinput_is_ready) Sleep(250); + while (!dinput_is_ready && timeout++ < 8) Sleep(250); if (!connected_devices[index].connected) return DI_NOTATTACHED; memset(instance, 0, sizeof(DIDEVICEINSTANCEW)); @@ -597,6 +598,7 @@ HRESULT micewine_joystick_create_device(struct dinput *dinput, const GUID *guid, { static int index = 0; struct micewine_joystick *impl; + int timeout = 0; if (index >= get_controllers_count()) index = 0; @@ -604,7 +606,7 @@ HRESULT micewine_joystick_create_device(struct dinput *dinput, const GUID *guid, start_update_thread(); - while (!dinput_is_ready) Sleep(250); + while (!dinput_is_ready && timeout++ < 8) Sleep(250); TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out ); From 455054cd8aefa862f81da396b6132792a4a68a60 Mon Sep 17 00:00:00 2001 From: WINDROID-EMU <45230455+WINDROID-EMU@users.noreply.github.com> Date: Sat, 21 Feb 2026 23:57:24 -0300 Subject: [PATCH 4/5] Refactor vibration speed variables and add timeout checks Refactor controller vibration speed variables and add timeout handling for xinput readiness checks. --- dlls/xinput1_3/main.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index d7002dbff262..8acd99370979 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -303,6 +303,11 @@ static DWORD WINAPI gamepad_update_thread_proc(void *param) while (TRUE) { + uint16_t wLeftMotorSpeedC0, wRightMotorSpeedC0; + uint16_t wLeftMotorSpeedC1, wRightMotorSpeedC1; + uint16_t wLeftMotorSpeedC2, wRightMotorSpeedC2; + uint16_t wLeftMotorSpeedC3, wRightMotorSpeedC3; + memset(buffer, 0, BUFFER_SIZE); /* @@ -318,17 +323,17 @@ static DWORD WINAPI gamepad_update_thread_proc(void *param) buffer[8]: Rumble Right Motor for Controller 3 */ - uint16_t wLeftMotorSpeedC0 = controllers[0].vibration.wLeftMotorSpeed; - uint16_t wRightMotorSpeedC0 = controllers[0].vibration.wRightMotorSpeed; + wLeftMotorSpeedC0 = controllers[0].vibration.wLeftMotorSpeed; + wRightMotorSpeedC0 = controllers[0].vibration.wRightMotorSpeed; - uint16_t wLeftMotorSpeedC1 = controllers[1].vibration.wLeftMotorSpeed; - uint16_t wRightMotorSpeedC1 = controllers[1].vibration.wRightMotorSpeed; + wLeftMotorSpeedC1 = controllers[1].vibration.wLeftMotorSpeed; + wRightMotorSpeedC1 = controllers[1].vibration.wRightMotorSpeed; - uint16_t wLeftMotorSpeedC2 = controllers[2].vibration.wLeftMotorSpeed; - uint16_t wRightMotorSpeedC2 = controllers[2].vibration.wRightMotorSpeed; + wLeftMotorSpeedC2 = controllers[2].vibration.wLeftMotorSpeed; + wRightMotorSpeedC2 = controllers[2].vibration.wRightMotorSpeed; - uint16_t wLeftMotorSpeedC3 = controllers[3].vibration.wLeftMotorSpeed; - uint16_t wRightMotorSpeedC3 = controllers[3].vibration.wRightMotorSpeed; + wLeftMotorSpeedC3 = controllers[3].vibration.wLeftMotorSpeed; + wRightMotorSpeedC3 = controllers[3].vibration.wRightMotorSpeed; buffer[0] = REQUEST_GET_CONTROLLER_STATE; buffer[1] = (int) (wLeftMotorSpeedC0 / 257); @@ -373,14 +378,16 @@ static DWORD WINAPI gamepad_update_thread_proc(void *param) break; case REQUEST_GET_CONTROLLER_STATE: + { + char *controllers_ptrs[4] = { controller0, controller1, controller2, controller3 }; + int i; + memcpy(controller0, buffer, CONTROLLER_BUFFER_SIZE); memcpy(controller1, buffer + CONTROLLER_BUFFER_SIZE, CONTROLLER_BUFFER_SIZE); memcpy(controller2, buffer + CONTROLLER_BUFFER_SIZE * 2, CONTROLLER_BUFFER_SIZE); memcpy(controller3, buffer + CONTROLLER_BUFFER_SIZE * 3, CONTROLLER_BUFFER_SIZE); - char *controllers_ptrs[4] = { controller0, controller1, controller2, controller3 }; - - for (int i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) { if (controllers_ptrs[i][1]) { if (!controllers[i].connected) { controller_connect(&controllers[i]); @@ -394,6 +401,7 @@ static DWORD WINAPI gamepad_update_thread_proc(void *param) } xinput_is_ready = true; break; + } } } } @@ -469,13 +477,15 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputSetState(DWORD index, XINPUT_VIBRATION *vib * XInputGetState() in the hook, so we need a wrapper. */ static DWORD xinput_get_state(DWORD index, XINPUT_STATE *state) { + int timeout = 0; if (!state) return ERROR_BAD_ARGUMENTS; start_update_thread(); if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; - while (!xinput_is_ready) Sleep(125); + while (!xinput_is_ready && timeout++ < 16) Sleep(125); + if (!xinput_is_ready) ERR("MiceWine xinput timeout in xinput_get_state\n"); if (!controllers[index].connected) return ERROR_DEVICE_NOT_CONNECTED; *state = controllers[index].state; @@ -750,12 +760,14 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputGetBatteryInformation(DWORD index, BYTE typ DWORD WINAPI DECLSPEC_HOTPATCH XInputGetCapabilitiesEx(DWORD unk, DWORD index, DWORD flags, XINPUT_CAPABILITIES_EX *caps) { DWORD ret = ERROR_SUCCESS; + int timeout = 0; TRACE("unk %lu, index %lu, flags %#lx, capabilities %p.\n", unk, index, flags, caps); start_update_thread(); - while (!xinput_is_ready) Sleep(125); + while (!xinput_is_ready && timeout++ < 16) Sleep(125); + if (!xinput_is_ready) ERR("MiceWine xinput timeout in XInputGetCapabilitiesEx\n"); if (!controllers[index].connected) { return ERROR_DEVICE_NOT_CONNECTED; From 8e24f78fe67568b381676a7d59d386aef9998d0a Mon Sep 17 00:00:00 2001 From: WINDROID-EMU <45230455+WINDROID-EMU@users.noreply.github.com> Date: Sat, 21 Feb 2026 23:58:10 -0300 Subject: [PATCH 5/5] Add error logging for joystick timeout in MiceWine --- dlls/dinput/joystick_micewine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/dinput/joystick_micewine.c b/dlls/dinput/joystick_micewine.c index b05c2692e00b..d316451fb2ea 100644 --- a/dlls/dinput/joystick_micewine.c +++ b/dlls/dinput/joystick_micewine.c @@ -563,6 +563,7 @@ HRESULT micewine_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCE if (index > XUSER_MAX_COUNT) return DI_NOTATTACHED; while (!dinput_is_ready && timeout++ < 8) Sleep(250); + if (!dinput_is_ready) ERR("MiceWine joystick timeout in enum_device\n"); if (!connected_devices[index].connected) return DI_NOTATTACHED; memset(instance, 0, sizeof(DIDEVICEINSTANCEW)); @@ -607,6 +608,7 @@ HRESULT micewine_joystick_create_device(struct dinput *dinput, const GUID *guid, start_update_thread(); while (!dinput_is_ready && timeout++ < 8) Sleep(250); + if (!dinput_is_ready) ERR("MiceWine joystick timeout in create_device\n"); TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out );