From acf49032632ea0089a89c34880cc8789a3472f04 Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Wed, 21 Oct 2026 23:27:46 -0600 Subject: [PATCH 1/3] Add initializers and use correct syntax `= {0};` `= {};` is a compiler extension. --- loader/loader.c | 18 +++++++++--------- loader/loader_linux.c | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/loader/loader.c b/loader/loader.c index 9a0e3ca29..0ebbb83c5 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -4870,7 +4870,7 @@ VKAPI_ATTR VkResult VKAPI_CALL loader_layer_create_device(VkInstance instance, V const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, PFN_vkGetInstanceProcAddr layerGIPA, PFN_vkGetDeviceProcAddr *nextGDPA) { - VkResult res; + VkResult res = VK_SUCCESS; VkPhysicalDevice internal_device = VK_NULL_HANDLE; struct loader_device *dev = NULL; struct loader_instance *inst = NULL; @@ -5023,10 +5023,10 @@ VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, c struct loader_instance *inst, VkInstance *created_instance) { uint32_t num_activated_layers = 0; struct activated_layer_info *activated_layers = NULL; - VkLayerInstanceCreateInfo chain_info; + VkLayerInstanceCreateInfo chain_info = {0}; VkLayerInstanceLink *layer_instance_link_info = NULL; - VkInstanceCreateInfo loader_create_info; - VkResult res; + VkInstanceCreateInfo loader_create_info = {0}; + VkResult res = VK_SUCCESS; PFN_vkGetInstanceProcAddr next_gipa = loader_gpa_instance_terminator; PFN_vkGetInstanceProcAddr cur_gipa = loader_gpa_instance_terminator; @@ -5374,11 +5374,11 @@ VkResult loader_create_device_chain(VkPhysicalDevice pd, const VkDeviceCreateInf #endif uint32_t num_activated_layers = 0; struct activated_layer_info *activated_layers = NULL; - VkLayerDeviceLink *layer_device_link_info; - VkLayerDeviceCreateInfo chain_info; - VkDeviceCreateInfo loader_create_info; + VkLayerDeviceLink *layer_device_link_info = NULL; + VkLayerDeviceCreateInfo chain_info = {0}; + VkDeviceCreateInfo loader_create_info = {0}; VkDeviceGroupDeviceCreateInfo *original_device_group_create_info_struct = NULL; - VkResult res; + VkResult res = VK_SUCCESS; PFN_vkGetDeviceProcAddr fpGDPA = NULL; PFN_vkGetDeviceProcAddr nextGDPA = loader_gpa_device_terminator; @@ -7476,7 +7476,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(VkP // This case is during the call down the instance chain with pLayerName == NULL and pProperties == NULL struct loader_icd_term *icd_term = phys_dev_term->this_icd_term; struct loader_extension_list all_exts = {0}; - VkResult res; + VkResult res = VK_SUCCESS; // We need to find the count without duplicates. This requires querying the driver for the names of the extensions. res = icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &all_exts.count, NULL); diff --git a/loader/loader_linux.c b/loader/loader_linux.c index 4c6959111..2913a7a46 100644 --- a/loader/loader_linux.c +++ b/loader/loader_linux.c @@ -277,7 +277,7 @@ VkResult linux_read_sorted_physical_devices(struct loader_instance *inst, uint32 for (uint32_t icd_idx = 0; icd_idx < icd_count; ++icd_idx) { for (uint32_t phys_dev = 0; phys_dev < icd_devices[icd_idx].device_count; ++phys_dev) { struct loader_icd_term *icd_term = icd_devices[icd_idx].icd_term; - VkPhysicalDeviceProperties dev_props = {}; + VkPhysicalDeviceProperties dev_props = {0}; sorted_device_info[index].physical_device = icd_devices[icd_idx].physical_devices[phys_dev]; sorted_device_info[index].icd_term = icd_term; @@ -389,7 +389,7 @@ VkResult linux_sort_physical_device_groups(struct loader_instance *inst, uint32_ struct loader_icd_term *icd_term = sorted_group_term[group].this_icd_term; for (uint32_t gpu = 0; gpu < sorted_group_term[group].group_props.physicalDeviceCount; ++gpu) { - VkPhysicalDeviceProperties dev_props = {}; + VkPhysicalDeviceProperties dev_props = {0}; sorted_group_term[group].internal_device_info[gpu].physical_device = sorted_group_term[group].group_props.physicalDevices[gpu]; From 1a947bd020fa2ec49a48d3c8c4533c94d02a6ba4 Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Mon, 19 Oct 2026 14:10:29 -0600 Subject: [PATCH 2/3] Create vk_loader_platform.c to hold function definitions Also replaces the usage of loader_fopen in asm_offset.c with the per platform calls as it was the only function from vk_loader_platform.h used by asm_offset. This prevents needing to compile vk_loader_platform.c in the asm_offset executable. --- BUILD.gn | 1 + REUSE.toml | 1 + loader/CMakeLists.txt | 2 + loader/asm_offset.c | 16 +- loader/loader.c | 4 - loader/vk_loader_platform.c | 404 ++++++++++++++++++++++++++++++++++++ loader/vk_loader_platform.h | 387 +++------------------------------- 7 files changed, 452 insertions(+), 363 deletions(-) create mode 100644 loader/vk_loader_platform.c diff --git a/BUILD.gn b/BUILD.gn index 5a73707d4..2bc8ffac1 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -215,6 +215,7 @@ if (!is_android) { "loader/unknown_function_handling.c", "loader/vk_loader_layer.h", "loader/vk_loader_platform.h", + "loader/vk_loader_platform.c", "loader/wsi.c", "loader/wsi.h", ] diff --git a/REUSE.toml b/REUSE.toml index 45aa84b1e..2fa1226ef 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -52,6 +52,7 @@ path = [ "loader/generated/vk_layer_dispatch_table.h", "loader/generated/vk_loader_extensions.h", "loader/vk_loader_platform.h", + "loader/vk_loader_platform.c", "scripts/generators/loader_extension_generator.py", ] precedence = "closest" diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index f29ee7aae..806333de6 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -90,6 +90,8 @@ set(NORMAL_LOADER_SRCS trampoline.c unknown_function_handling.c unknown_function_handling.h + vk_loader_platform.c + vk_loader_platform.h wsi.c wsi.h ) diff --git a/loader/asm_offset.c b/loader/asm_offset.c index 4a4fe1998..18a28a118 100644 --- a/loader/asm_offset.c +++ b/loader/asm_offset.c @@ -129,7 +129,21 @@ int main(int argc, char **argv) { // clang-format on }; - FILE *file = loader_fopen("gen_defines.asm", "w"); + FILE *file = NULL; +#if defined(_WIN32) + errno_t err = fopen_s(&file, "gen_defines.asm", "w"); + if (err != 0) { + fprintf(stderr, "Error: failed to open gen_defines.asm for writing\n"); + return -1; + } +#else + file = fopen("gen_defines.asm", "w"); + if (NULL == file) { + fprintf(stderr, "Error: failed to open gen_defines.asm for writing\n"); + return -1; + } +#endif + // NOLINTBEGIN(cert-err33-c) - this is a build-time code generator run by developers, not part of the loader's // runtime attack surface; a failed write here is immediately visible as a broken build, not worth per-call checks. fprintf(file, "\n"); diff --git a/loader/loader.c b/loader/loader.c index 0ebbb83c5..e60d9f962 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -103,10 +103,6 @@ loader_platform_thread_mutex loader_preload_icd_lock; // vkCreateInstance. struct loader_icd_tramp_list preloaded_icds; -// controls whether loader_platform_close_library() closes the libraries or not - controlled by an environment -// variables - this is just the definition of the variable, usage is in vk_loader_platform.h -bool loader_disable_dynamic_library_unloading; - LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init); // Creates loader_api_version struct that contains the major and minor fields, setting patch to 0 diff --git a/loader/vk_loader_platform.c b/loader/vk_loader_platform.c new file mode 100644 index 000000000..c18933446 --- /dev/null +++ b/loader/vk_loader_platform.c @@ -0,0 +1,404 @@ +/* + * + * Copyright (c) 2015-2026 The Khronos Group Inc. + * Copyright (c) 2015-2026 Valve Corporation + * Copyright (c) 2015-2026 LunarG, Inc. + * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * Copyright (c) 2023-2023 RasterGrid Kft. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author: Ian Elliot + * Author: Jon Ashburn + * Author: Lenny Komow + * Author: Charles Giessen + * + */ +#include "vk_loader_platform.h" + +#if defined(_WIN32) +#include "stack_allocation.h" +#endif + +bool loader_disable_dynamic_library_unloading; + +#if COMMON_UNIX_PLATFORMS + +// File IO +bool loader_platform_file_exists(const char *path) { + if (access(path, F_OK)) return false; + return true; +} +// Returns true if the given string appears to be a relative or absolute +// path, as opposed to a bare filename. +bool loader_platform_is_path_absolute(const char *path) { + if (path[0] == '/') return true; + return false; +} + +// NOLINTNEXTLINE(concurrency-mt-unsafe) - no portable reentrant dirname; the returned buffer is copied by callers immediately +char *loader_platform_dirname(char *path) { return dirname(path); } + +// loader_platform_executable_path finds application path + name. +// Path cannot be longer than 1024, returns NULL if it is greater than that. +#if defined(__linux__) || defined(__GNU__) || defined(__CYGWIN__) +char *loader_platform_executable_path(char *buffer, size_t size) { + ssize_t count = readlink("/proc/self/exe", buffer, size); + if (count == -1) return NULL; + if (count == 0) return NULL; + // readlink does not append a null terminator and returns up to size bytes, so a target of size or more + // would leave no room for the terminator and buffer[count] would write past the end. + if ((size_t)count >= size) return NULL; + buffer[count] = '\0'; + return buffer; +} +#elif defined(__APPLE__) +#include +// TARGET_OS_IPHONE isn't just iOS it's also iOS/tvOS/watchOS. See TargetConditionals.h documentation. +#if TARGET_OS_IPHONE +char *loader_platform_executable_path(char *buffer, size_t size) { + (void)size; + buffer[0] = '\0'; + return buffer; +} +#endif +#if TARGET_OS_OSX +#include +char *loader_platform_executable_path(char *buffer, size_t size) { + // proc_pidpath takes a uint32_t for the buffer size + if (size > UINT32_MAX) { + return NULL; + } + pid_t pid = getpid(); + int ret = proc_pidpath(pid, buffer, (uint32_t)size); + if (ret <= 0) { + return NULL; + } + buffer[ret] = '\0'; + return buffer; +} +#endif +#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) +#include +char *loader_platform_executable_path(char *buffer, size_t size) { + int mib[] = { + CTL_KERN, +#if defined(__NetBSD__) + KERN_PROC_ARGS, + -1, + KERN_PROC_PATHNAME, +#else + KERN_PROC, + KERN_PROC_PATHNAME, + -1, +#endif + }; + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buffer, &size, NULL, 0) < 0) { + return NULL; + } + + return buffer; +} +#elif defined(__Fuchsia__) || defined(__OpenBSD__) +char *loader_platform_executable_path(char *buffer, size_t size) { + (void)buffer; + (void)size; + return NULL; +} +#elif defined(__QNX__) + +#include +#include + +char *loader_platform_executable_path(char *buffer, size_t size) { + int fd = open("/proc/self/exefile", O_RDONLY); + size_t rdsize; + + if (fd == -1) { + return NULL; + } + + rdsize = read(fd, buffer, size); + if (rdsize == size) { + return NULL; + } + buffer[rdsize] = 0x00; + close(fd); + + return buffer; +} +#endif // defined (__QNX__) + +// Compatibility with compilers that don't support __has_feature +#if !defined(__has_feature) +#define __has_feature(x) 0 +#endif + +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +#define LOADER_ADDRESS_SANITIZER_ACTIVE // TODO: Add proper build flag for ASAN support +#endif + +// When loading the library, we use RTLD_LAZY so that not all symbols have to be +// resolved at this time (which improves performance). Note that if not all symbols +// can be resolved, this could cause crashes later. Use the LD_BIND_NOW environment +// variable to force all symbols to be resolved here. +#define LOADER_DLOPEN_MODE (RTLD_LAZY | RTLD_LOCAL) + +#if defined(__Fuchsia__) +loader_platform_dl_handle loader_platform_open_driver(const char *libPath) { + return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, true); +} +loader_platform_dl_handle loader_platform_open_library(const char *libPath) { + return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, false); +} +#else +loader_platform_dl_handle loader_platform_open_library(const char *libPath) { return dlopen(libPath, LOADER_DLOPEN_MODE); } +#endif + +const char *loader_platform_open_library_error(const char *libPath) { + (void)libPath; +#if defined(__Fuchsia__) + return dlerror_fuchsia(); +#else + // NOLINTNEXTLINE(concurrency-mt-unsafe) - dlerror has no reentrant variant; the message is used immediately, not retained + return dlerror(); +#endif +} +void loader_platform_close_library(loader_platform_dl_handle library) { + if (!loader_disable_dynamic_library_unloading) { + dlclose(library); + } else { + (void)library; + } +} +void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name) { + assert(library); + assert(name); + return dlsym(library, name); +} +const char *loader_platform_get_proc_address_error(const char *name) { + (void)name; + // NOLINTNEXTLINE(concurrency-mt-unsafe) - dlerror has no reentrant variant; the message is used immediately, not retained + return dlerror(); +} + +// Thread mutex: +void loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(pMutex, &attr); +} +void loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_lock(pMutex); } +void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_unlock(pMutex); } +void loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_destroy(pMutex); } + +void *thread_safe_strtok(char *str, const char *delim, char **saveptr) { return strtok_r(str, delim, saveptr); } + +FILE *loader_fopen(const char *fileName, const char *mode) { return fopen(fileName, mode); } +char *loader_strncat(char *dest, size_t dest_sz, const char *src, size_t count) { + (void)dest_sz; + return strncat(dest, src, count); +} +char *loader_strncpy(char *dest, size_t dest_sz, const char *src, size_t count) { + (void)dest_sz; + return strncpy(dest, src, count); +} + +#elif defined(_WIN32) + +// Get the key for the plug n play driver registry +// The string returned by this function should NOT be freed +const char *LoaderPnpDriverRegistry(void) { + BOOL is_wow; + IsWow64Process(GetCurrentProcess(), &is_wow); + return is_wow ? "Vulkan" VK_VARIANT_REG_STR "DriverNameWow" : "Vulkan" VK_VARIANT_REG_STR "DriverName"; +} +const wchar_t *LoaderPnpDriverRegistryWide(void) { + BOOL is_wow; + IsWow64Process(GetCurrentProcess(), &is_wow); + return is_wow ? L"Vulkan" VK_VARIANT_REG_STR_W L"DriverNameWow" : L"Vulkan" VK_VARIANT_REG_STR_W L"DriverName"; +} + +// Get the key for the plug 'n play explicit layer registry +// The string returned by this function should NOT be freed +const char *LoaderPnpELayerRegistry(void) { + BOOL is_wow; + IsWow64Process(GetCurrentProcess(), &is_wow); + return is_wow ? "Vulkan" VK_VARIANT_REG_STR "ExplicitLayersWow" : "Vulkan" VK_VARIANT_REG_STR "ExplicitLayers"; +} +const wchar_t *LoaderPnpELayerRegistryWide(void) { + BOOL is_wow; + IsWow64Process(GetCurrentProcess(), &is_wow); + return is_wow ? L"Vulkan" VK_VARIANT_REG_STR_W L"ExplicitLayersWow" : L"Vulkan" VK_VARIANT_REG_STR_W L"ExplicitLayers"; +} + +// Get the key for the plug 'n play implicit layer registry +// The string returned by this function should NOT be freed +const char *LoaderPnpILayerRegistry(void) { + BOOL is_wow; + IsWow64Process(GetCurrentProcess(), &is_wow); + return is_wow ? "Vulkan" VK_VARIANT_REG_STR "ImplicitLayersWow" : "Vulkan" VK_VARIANT_REG_STR "ImplicitLayers"; +} +const wchar_t *LoaderPnpILayerRegistryWide(void) { + BOOL is_wow; + IsWow64Process(GetCurrentProcess(), &is_wow); + return is_wow ? L"Vulkan" VK_VARIANT_REG_STR_W L"ImplicitLayersWow" : L"Vulkan" VK_VARIANT_REG_STR_W L"ImplicitLayers"; +} + +// File IO +bool loader_platform_file_exists(const char *path) { + int path_utf16_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); + if (path_utf16_size <= 0) { + return false; + } + wchar_t *path_utf16 = (wchar_t *)loader_stack_alloc(path_utf16_size * sizeof(wchar_t)); + if (MultiByteToWideChar(CP_UTF8, 0, path, -1, path_utf16, path_utf16_size) != path_utf16_size) { + return false; + } + if (_waccess(path_utf16, 0) == -1) + return false; + else + return true; +} + +// Returns true if the given string appears to be a relative or absolute +// path, as opposed to a bare filename. +bool loader_platform_is_path_absolute(const char *path) { + if (!path || !*path) { + return false; + } + if (*path == DIRECTORY_SYMBOL || path[1] == ':') { + return true; + } + return false; +} + +// WIN32 runtime doesn't have dirname(). +char *loader_platform_dirname(char *path) { + char *current, *next; + + // TODO/TBD: Do we need to deal with the Windows's ":" character? + + for (current = path; *current != '\0'; current = next) { + next = strchr(current, DIRECTORY_SYMBOL); + if (next == NULL) { + if (current != path) *(current - 1) = '\0'; + return path; + } else { + // Point one character past the DIRECTORY_SYMBOL: + next++; + } + } + return path; +} + +char *loader_platform_executable_path(char *buffer, size_t size) { + wchar_t *buffer_utf16 = (wchar_t *)loader_stack_alloc(size * sizeof(wchar_t)); + DWORD ret = GetModuleFileNameW(NULL, buffer_utf16, (DWORD)size); + if (ret == 0) { + return NULL; + } + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + return NULL; + } + int buffer_utf8_size = WideCharToMultiByte(CP_UTF8, 0, buffer_utf16, -1, NULL, 0, NULL, NULL); + if (buffer_utf8_size <= 0 || (size_t)buffer_utf8_size > size) { + return NULL; + } + if (WideCharToMultiByte(CP_UTF8, 0, buffer_utf16, -1, buffer, buffer_utf8_size, NULL, NULL) != buffer_utf8_size) { + return NULL; + } + return buffer; +} + +// Dynamic Loading: +loader_platform_dl_handle loader_platform_open_library(const char *lib_path) { + int lib_path_utf16_size = MultiByteToWideChar(CP_UTF8, 0, lib_path, -1, NULL, 0); + if (lib_path_utf16_size <= 0) { + return NULL; + } + wchar_t *lib_path_utf16 = (wchar_t *)loader_stack_alloc(lib_path_utf16_size * sizeof(wchar_t)); + if (MultiByteToWideChar(CP_UTF8, 0, lib_path, -1, lib_path_utf16, lib_path_utf16_size) != lib_path_utf16_size) { + return NULL; + } + // Try loading the library the original way first. + loader_platform_dl_handle lib_handle = LoadLibraryW(lib_path_utf16); + if (lib_handle == NULL && GetLastError() == ERROR_MOD_NOT_FOUND) { + // If that failed, then try loading it with broader search folders. + lib_handle = LoadLibraryExW(lib_path_utf16, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); + } + return lib_handle; +} +const char *loader_platform_open_library_error(const char *libPath) { + static char errorMsg[512]; + (void)snprintf(errorMsg, 511, "Failed to open dynamic library \"%s\" with error %lu", libPath, GetLastError()); + return errorMsg; +} +void loader_platform_close_library(loader_platform_dl_handle library) { + if (!loader_disable_dynamic_library_unloading) { + FreeLibrary(library); + } else { + (void)library; + } +} +void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name) { + assert(library); + assert(name); + return (void *)GetProcAddress(library, name); +} +const char *loader_platform_get_proc_address_error(const char *name) { + static char errorMsg[120]; + (void)snprintf(errorMsg, 119, "Failed to find function \"%s\" in dynamic library", name); + return errorMsg; +} + +// Thread mutex: +void loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { InitializeCriticalSection(pMutex); } +void loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { EnterCriticalSection(pMutex); } +void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { LeaveCriticalSection(pMutex); } +void loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { DeleteCriticalSection(pMutex); } + +void *thread_safe_strtok(char *str, const char *delimiters, char **context) { return strtok_s(str, delimiters, context); } + +FILE *loader_fopen(const char *fileName, const char *mode) { + FILE *file = NULL; + errno_t err = fopen_s(&file, fileName, mode); + if (err != 0) return NULL; + return file; +} + +char *loader_strncat(char *dest, size_t dest_sz, const char *src, size_t count) { + errno_t err = strncat_s(dest, dest_sz, src, count); + if (err != 0) return NULL; + return dest; +} + +char *loader_strncpy(char *dest, size_t dest_sz, const char *src, size_t count) { + errno_t err = strncpy_s(dest, dest_sz, src, count); + if (err != 0) return NULL; + return dest; +} + +#else // defined(_WIN32) + +#warning The "vk_loader_platform.h" file must be modified for this OS. + +// NOTE: In order to support another OS, an #elif needs to be added (above the +// "#else // defined(_WIN32)") for that OS, and OS-specific versions of the +// contents of this file must be created. + +// NOTE: Other OS-specific changes are also needed for this OS. Search for +// files with "WIN32" in it, as a quick way to find files that must be changed. + +#endif // defined(_WIN32) diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h index d642961c5..eda7259c6 100644 --- a/loader/vk_loader_platform.h +++ b/loader/vk_loader_platform.h @@ -1,8 +1,8 @@ /* * - * Copyright (c) 2015-2022 The Khronos Group Inc. - * Copyright (c) 2015-2022 Valve Corporation - * Copyright (c) 2015-2022 LunarG, Inc. + * Copyright (c) 2015-2026 The Khronos Group Inc. + * Copyright (c) 2015-2026 Valve Corporation + * Copyright (c) 2015-2026 LunarG, Inc. * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * Copyright (c) 2023-2023 RasterGrid Kft. * @@ -72,7 +72,6 @@ #include #include -#include "stack_allocation.h" #endif // defined(_WIN32) #if defined(APPLE_STATIC_LOADER) && !defined(__APPLE__) @@ -283,378 +282,50 @@ static inline void loader_platform_thread_win32_once_fn(INIT_ONCE *ctl, PINIT_ON #endif -#if COMMON_UNIX_PLATFORMS - // File IO -static inline bool loader_platform_file_exists(const char *path) { - if (access(path, F_OK)) return false; - return true; -} - +bool loader_platform_file_exists(const char *path); // Returns true if the given string appears to be a relative or absolute // path, as opposed to a bare filename. -static inline bool loader_platform_is_path_absolute(const char *path) { - if (path[0] == '/') return true; - return false; -} - +bool loader_platform_is_path_absolute(const char *path); // NOLINTNEXTLINE(concurrency-mt-unsafe) - no portable reentrant dirname; the returned buffer is copied by callers immediately -static inline char *loader_platform_dirname(char *path) { return dirname(path); } - +char *loader_platform_dirname(char *path); // loader_platform_executable_path finds application path + name. // Path cannot be longer than 1024, returns NULL if it is greater than that. -#if defined(__linux__) || defined(__GNU__) || defined(__CYGWIN__) -static inline char *loader_platform_executable_path(char *buffer, size_t size) { - ssize_t count = readlink("/proc/self/exe", buffer, size); - if (count == -1) return NULL; - if (count == 0) return NULL; - // readlink does not append a null terminator and returns up to size bytes, so a target of size or more - // would leave no room for the terminator and buffer[count] would write past the end. - if ((size_t)count >= size) return NULL; - buffer[count] = '\0'; - return buffer; -} -#elif defined(__APPLE__) -#include -// TARGET_OS_IPHONE isn't just iOS it's also iOS/tvOS/watchOS. See TargetConditionals.h documentation. -#if TARGET_OS_IPHONE -static inline char *loader_platform_executable_path(char *buffer, size_t size) { - (void)size; - buffer[0] = '\0'; - return buffer; -} -#endif -#if TARGET_OS_OSX -#include -static inline char *loader_platform_executable_path(char *buffer, size_t size) { - // proc_pidpath takes a uint32_t for the buffer size - if (size > UINT32_MAX) { - return NULL; - } - pid_t pid = getpid(); - int ret = proc_pidpath(pid, buffer, (uint32_t)size); - if (ret <= 0) { - return NULL; - } - buffer[ret] = '\0'; - return buffer; -} -#endif -#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) -#include -static inline char *loader_platform_executable_path(char *buffer, size_t size) { - int mib[] = { - CTL_KERN, -#if defined(__NetBSD__) - KERN_PROC_ARGS, - -1, - KERN_PROC_PATHNAME, -#else - KERN_PROC, - KERN_PROC_PATHNAME, - -1, -#endif - }; - if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buffer, &size, NULL, 0) < 0) { - return NULL; - } - - return buffer; -} -#elif defined(__Fuchsia__) || defined(__OpenBSD__) -static inline char *loader_platform_executable_path(char *buffer, size_t size) { return NULL; } -#elif defined(__QNX__) - -#ifndef SYSCONFDIR -#define SYSCONFDIR "/etc" -#endif - -#include -#include - -static inline char *loader_platform_executable_path(char *buffer, size_t size) { - int fd = open("/proc/self/exefile", O_RDONLY); - size_t rdsize; - - if (fd == -1) { - return NULL; - } - - rdsize = read(fd, buffer, size); - if (rdsize == size) { - return NULL; - } - buffer[rdsize] = 0x00; - close(fd); - - return buffer; -} -#endif // defined (__QNX__) - -// Compatibility with compilers that don't support __has_feature -#if !defined(__has_feature) -#define __has_feature(x) 0 -#endif - -#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) -#define LOADER_ADDRESS_SANITIZER_ACTIVE // TODO: Add proper build flag for ASAN support -#endif - -// When loading the library, we use RTLD_LAZY so that not all symbols have to be -// resolved at this time (which improves performance). Note that if not all symbols -// can be resolved, this could cause crashes later. Use the LD_BIND_NOW environment -// variable to force all symbols to be resolved here. -#define LOADER_DLOPEN_MODE (RTLD_LAZY | RTLD_LOCAL) +char *loader_platform_executable_path(char *buffer, size_t size); #if defined(__Fuchsia__) -static inline loader_platform_dl_handle loader_platform_open_driver(const char *libPath) { - return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, true); -} -static inline loader_platform_dl_handle loader_platform_open_library(const char *libPath) { - return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, false); -} -#else -static inline loader_platform_dl_handle loader_platform_open_library(const char *libPath) { - return dlopen(libPath, LOADER_DLOPEN_MODE); -} +loader_platform_dl_handle loader_platform_open_driver(const char *libPath); #endif +loader_platform_dl_handle loader_platform_open_library(const char *libPath); -static inline const char *loader_platform_open_library_error(const char *libPath) { - (void)libPath; -#if defined(__Fuchsia__) - return dlerror_fuchsia(); -#else - // NOLINTNEXTLINE(concurrency-mt-unsafe) - dlerror has no reentrant variant; the message is used immediately, not retained - return dlerror(); -#endif -} -static inline void loader_platform_close_library(loader_platform_dl_handle library) { - if (!loader_disable_dynamic_library_unloading) { - dlclose(library); - } else { - (void)library; - } -} -static inline void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name) { - assert(library); - assert(name); - return dlsym(library, name); -} -static inline const char *loader_platform_get_proc_address_error(const char *name) { - (void)name; - // NOLINTNEXTLINE(concurrency-mt-unsafe) - dlerror has no reentrant variant; the message is used immediately, not retained - return dlerror(); -} +const char *loader_platform_open_library_error(const char *libPath); +void loader_platform_close_library(loader_platform_dl_handle library); +void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name); +const char *loader_platform_get_proc_address_error(const char *name); // Thread mutex: -static inline void loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(pMutex, &attr); -} -static inline void loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_lock(pMutex); } -static inline void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_unlock(pMutex); } -static inline void loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_destroy(pMutex); } - -static inline void *thread_safe_strtok(char *str, const char *delim, char **saveptr) { return strtok_r(str, delim, saveptr); } - -static inline FILE *loader_fopen(const char *fileName, const char *mode) { return fopen(fileName, mode); } -static inline char *loader_strncat(char *dest, size_t dest_sz, const char *src, size_t count) { - (void)dest_sz; - return strncat(dest, src, count); -} -static inline char *loader_strncpy(char *dest, size_t dest_sz, const char *src, size_t count) { - (void)dest_sz; - return strncpy(dest, src, count); -} +void loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex); +void loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex); +void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex); +void loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex); -#elif defined(_WIN32) +void *thread_safe_strtok(char *str, const char *delim, char **saveptr); +FILE *loader_fopen(const char *fileName, const char *mode); +char *loader_strncat(char *dest, size_t dest_sz, const char *src, size_t count); +char *loader_strncpy(char *dest, size_t dest_sz, const char *src, size_t count); +#if defined(_WIN32) // Get the key for the plug n play driver registry // The string returned by this function should NOT be freed -static inline const char *LoaderPnpDriverRegistry() { - BOOL is_wow; - IsWow64Process(GetCurrentProcess(), &is_wow); - return is_wow ? "Vulkan" VK_VARIANT_REG_STR "DriverNameWow" : "Vulkan" VK_VARIANT_REG_STR "DriverName"; -} -static inline const wchar_t *LoaderPnpDriverRegistryWide() { - BOOL is_wow; - IsWow64Process(GetCurrentProcess(), &is_wow); - return is_wow ? L"Vulkan" VK_VARIANT_REG_STR_W L"DriverNameWow" : L"Vulkan" VK_VARIANT_REG_STR_W L"DriverName"; -} - +const char *LoaderPnpDriverRegistry(void); +const wchar_t *LoaderPnpDriverRegistryWide(void); // Get the key for the plug 'n play explicit layer registry // The string returned by this function should NOT be freed -static inline const char *LoaderPnpELayerRegistry() { - BOOL is_wow; - IsWow64Process(GetCurrentProcess(), &is_wow); - return is_wow ? "Vulkan" VK_VARIANT_REG_STR "ExplicitLayersWow" : "Vulkan" VK_VARIANT_REG_STR "ExplicitLayers"; -} -static inline const wchar_t *LoaderPnpELayerRegistryWide() { - BOOL is_wow; - IsWow64Process(GetCurrentProcess(), &is_wow); - return is_wow ? L"Vulkan" VK_VARIANT_REG_STR_W L"ExplicitLayersWow" : L"Vulkan" VK_VARIANT_REG_STR_W L"ExplicitLayers"; -} - +const char *LoaderPnpELayerRegistry(void); +const wchar_t *LoaderPnpELayerRegistryWide(void); // Get the key for the plug 'n play implicit layer registry // The string returned by this function should NOT be freed -static inline const char *LoaderPnpILayerRegistry() { - BOOL is_wow; - IsWow64Process(GetCurrentProcess(), &is_wow); - return is_wow ? "Vulkan" VK_VARIANT_REG_STR "ImplicitLayersWow" : "Vulkan" VK_VARIANT_REG_STR "ImplicitLayers"; -} -static inline const wchar_t *LoaderPnpILayerRegistryWide() { - BOOL is_wow; - IsWow64Process(GetCurrentProcess(), &is_wow); - return is_wow ? L"Vulkan" VK_VARIANT_REG_STR_W L"ImplicitLayersWow" : L"Vulkan" VK_VARIANT_REG_STR_W L"ImplicitLayers"; -} - -// File IO -static inline bool loader_platform_file_exists(const char *path) { - int path_utf16_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); - if (path_utf16_size <= 0) { - return false; - } - wchar_t *path_utf16 = (wchar_t *)loader_stack_alloc(path_utf16_size * sizeof(wchar_t)); - if (MultiByteToWideChar(CP_UTF8, 0, path, -1, path_utf16, path_utf16_size) != path_utf16_size) { - return false; - } - if (_waccess(path_utf16, 0) == -1) - return false; - else - return true; -} - -// Returns true if the given string appears to be a relative or absolute -// path, as opposed to a bare filename. -static inline bool loader_platform_is_path_absolute(const char *path) { - if (!path || !*path) { - return false; - } - if (*path == DIRECTORY_SYMBOL || path[1] == ':') { - return true; - } - return false; -} - -// WIN32 runtime doesn't have dirname(). -static inline char *loader_platform_dirname(char *path) { - char *current, *next; - - // TODO/TBD: Do we need to deal with the Windows's ":" character? - - for (current = path; *current != '\0'; current = next) { - next = strchr(current, DIRECTORY_SYMBOL); - if (next == NULL) { - if (current != path) *(current - 1) = '\0'; - return path; - } else { - // Point one character past the DIRECTORY_SYMBOL: - next++; - } - } - return path; -} - -static inline char *loader_platform_executable_path(char *buffer, size_t size) { - wchar_t *buffer_utf16 = (wchar_t *)loader_stack_alloc(size * sizeof(wchar_t)); - DWORD ret = GetModuleFileNameW(NULL, buffer_utf16, (DWORD)size); - if (ret == 0) { - return NULL; - } - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - return NULL; - } - int buffer_utf8_size = WideCharToMultiByte(CP_UTF8, 0, buffer_utf16, -1, NULL, 0, NULL, NULL); - if (buffer_utf8_size <= 0 || (size_t)buffer_utf8_size > size) { - return NULL; - } - if (WideCharToMultiByte(CP_UTF8, 0, buffer_utf16, -1, buffer, buffer_utf8_size, NULL, NULL) != buffer_utf8_size) { - return NULL; - } - return buffer; -} +const char *LoaderPnpILayerRegistry(void); +const wchar_t *LoaderPnpILayerRegistryWide(void); -// Dynamic Loading: -static inline loader_platform_dl_handle loader_platform_open_library(const char *lib_path) { - int lib_path_utf16_size = MultiByteToWideChar(CP_UTF8, 0, lib_path, -1, NULL, 0); - if (lib_path_utf16_size <= 0) { - return NULL; - } - wchar_t *lib_path_utf16 = (wchar_t *)loader_stack_alloc(lib_path_utf16_size * sizeof(wchar_t)); - if (MultiByteToWideChar(CP_UTF8, 0, lib_path, -1, lib_path_utf16, lib_path_utf16_size) != lib_path_utf16_size) { - return NULL; - } - // Try loading the library the original way first. - loader_platform_dl_handle lib_handle = LoadLibraryW(lib_path_utf16); - if (lib_handle == NULL && GetLastError() == ERROR_MOD_NOT_FOUND) { - // If that failed, then try loading it with broader search folders. - lib_handle = LoadLibraryExW(lib_path_utf16, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); - } - return lib_handle; -} -static inline const char *loader_platform_open_library_error(const char *libPath) { - static char errorMsg[512]; - (void)snprintf(errorMsg, 511, "Failed to open dynamic library \"%s\" with error %lu", libPath, GetLastError()); - return errorMsg; -} -static inline void loader_platform_close_library(loader_platform_dl_handle library) { - if (!loader_disable_dynamic_library_unloading) { - FreeLibrary(library); - } else { - (void)library; - } -} -static inline void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name) { - assert(library); - assert(name); - return (void *)GetProcAddress(library, name); -} -static inline const char *loader_platform_get_proc_address_error(const char *name) { - static char errorMsg[120]; - (void)snprintf(errorMsg, 119, "Failed to find function \"%s\" in dynamic library", name); - return errorMsg; -} - -// Thread mutex: -static inline void loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { InitializeCriticalSection(pMutex); } -static inline void loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { EnterCriticalSection(pMutex); } -static inline void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { LeaveCriticalSection(pMutex); } -static inline void loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { DeleteCriticalSection(pMutex); } - -static inline void *thread_safe_strtok(char *str, const char *delimiters, char **context) { - return strtok_s(str, delimiters, context); -} - -static inline FILE *loader_fopen(const char *fileName, const char *mode) { - FILE *file = NULL; - errno_t err = fopen_s(&file, fileName, mode); - if (err != 0) return NULL; - return file; -} - -static inline char *loader_strncat(char *dest, size_t dest_sz, const char *src, size_t count) { - errno_t err = strncat_s(dest, dest_sz, src, count); - if (err != 0) return NULL; - return dest; -} - -static inline char *loader_strncpy(char *dest, size_t dest_sz, const char *src, size_t count) { - errno_t err = strncpy_s(dest, dest_sz, src, count); - if (err != 0) return NULL; - return dest; -} - -#else // defined(_WIN32) - -#warning The "vk_loader_platform.h" file must be modified for this OS. - -// NOTE: In order to support another OS, an #elif needs to be added (above the -// "#else // defined(_WIN32)") for that OS, and OS-specific versions of the -// contents of this file must be created. - -// NOTE: Other OS-specific changes are also needed for this OS. Search for -// files with "WIN32" in it, as a quick way to find files that must be changed. - -#endif // defined(_WIN32) +#endif From a298a75d117b4ed456d1bd4f1fa25ea53ea6ca4d Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Tue, 20 Oct 2026 10:38:39 -0600 Subject: [PATCH 3/3] Remove alloca from codebase Alloca is not considered good practice and its usage has caused crashes for users. Removing stack_allocation.h improving the allocating handling logic across the codebase, since many places avoided returning out-of- host-memory (OOHM) errors by using alloca instead of a real allocation. This is done by passing a bool pointer out parameter to indicate an OOHM error condition has occured. In addition to the refactoring for OOHM, helpers for converting utf-8 to ucs (aka wide chars to multi-byte chars) were added, since they too need to allocate memory to hold the converted string. --- BUILD.gn | 1 - REUSE.toml | 1 - loader/CMakeLists.txt | 6 +- loader/loader.c | 742 +++++++++++++++++++++++------------- loader/loader.h | 3 +- loader/loader_environment.c | 135 ++++--- loader/loader_environment.h | 4 +- loader/loader_json.c | 52 ++- loader/loader_linux.c | 19 +- loader/loader_windows.c | 12 +- loader/loader_windows.h | 2 +- loader/settings.c | 33 +- loader/stack_allocation.h | 47 --- loader/terminator.c | 11 +- loader/trampoline.c | 78 +++- loader/vk_loader_platform.c | 197 +++++++--- loader/vk_loader_platform.h | 22 +- loader/wsi.c | 76 ++-- 18 files changed, 923 insertions(+), 518 deletions(-) delete mode 100644 loader/stack_allocation.h diff --git a/BUILD.gn b/BUILD.gn index 2bc8ffac1..c06f51746 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -208,7 +208,6 @@ if (!is_android) { # "loader/phys_dev_ext.c", "loader/settings.c", "loader/settings.h", - "loader/stack_allocation.h", "loader/terminator.c", "loader/trampoline.c", "loader/unknown_function_handling.h", diff --git a/REUSE.toml b/REUSE.toml index 2fa1226ef..f14d0d96e 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -220,7 +220,6 @@ path = [ "loader/debug_utils.c", "loader/loader_windows.h", "loader/allocation.h", - "loader/stack_allocation.h", "loader/loader.h", "loader/debug_utils.h", "loader/loader_windows.c", diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index 806333de6..5957081bd 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -51,15 +51,11 @@ if(WIN32) configure_file(loader.rc.in ${CMAKE_CURRENT_BINARY_DIR}/loader.rc) endif() else() - # Used to make alloca() and secure_getenv() available + # Used to make secure_getenv() available target_compile_definitions(loader_specific_options INTERFACE _GNU_SOURCE) if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") target_compile_definitions(loader_specific_options INTERFACE __BSD_VISIBLE=1) endif() - check_include_file("alloca.h" HAVE_ALLOCA_H) - if(HAVE_ALLOCA_H) - target_compile_definitions(loader_specific_options INTERFACE HAVE_ALLOCA_H) - endif() set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) diff --git a/loader/loader.c b/loader/loader.c index e60d9f962..e77091554 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -55,7 +55,6 @@ #endif // _WIN32 #include "allocation.h" -#include "stack_allocation.h" #include "cJSON.h" #include "debug_utils.h" #include "loader_environment.h" @@ -526,7 +525,7 @@ VkResult normalize_path(const struct loader_instance *inst, char **passed_in_pat return res; #else - (void)inst; + VkResult res = VK_SUCCESS; char *path = *passed_in_path; size_t path_len = strlen(path) + 1; @@ -547,9 +546,10 @@ VkResult normalize_path(const struct loader_instance *inst, char **passed_in_pat // Loop while there are still ..'s in the path. Easiest implementation resolves them one by one, which requires quadratic // iteration through the string - char *directory_stack = loader_stack_alloc(path_len); + char *directory_stack = loader_instance_heap_calloc(inst, path_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (directory_stack == NULL) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } size_t top_of_stack = 0; @@ -585,7 +585,10 @@ VkResult normalize_path(const struct loader_instance *inst, char **passed_in_pat path[top_of_stack] = '\0'; path_len = top_of_stack + 1; - return VK_SUCCESS; +out: + loader_instance_heap_free(inst, directory_stack); + + return res; #endif } @@ -602,39 +605,50 @@ VkResult get_library_path_of_dl_handle(const struct loader_instance *inst, loade return VK_SUCCESS; #elif defined(WIN32) + VkResult res = VK_SUCCESS; (void)gipa; size_t module_file_name_len = MAX_PATH; // start with reasonably large buffer - wchar_t *buffer_utf16 = (wchar_t *)loader_stack_alloc(module_file_name_len * sizeof(wchar_t)); + wchar_t *buffer_utf16 = + (wchar_t *)loader_instance_heap_calloc(inst, module_file_name_len * sizeof(wchar_t), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == buffer_utf16) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } DWORD ret = GetModuleFileNameW(lib_handle, buffer_utf16, (DWORD)module_file_name_len); if (ret == 0) { - return VK_SUCCESS; + goto out; } while (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { module_file_name_len *= 2; - buffer_utf16 = (wchar_t *)loader_stack_alloc(module_file_name_len * sizeof(wchar_t)); + loader_instance_heap_free(inst, buffer_utf16); + buffer_utf16 = (wchar_t *)loader_instance_heap_calloc(inst, module_file_name_len * sizeof(wchar_t), + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == buffer_utf16) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + ret = GetModuleFileNameW(lib_handle, buffer_utf16, (DWORD)module_file_name_len); if (ret == 0) { - return VK_SUCCESS; + goto out; } } - - // Need to convert from utf16 to utf8 - int buffer_utf8_size = WideCharToMultiByte(CP_UTF8, 0, buffer_utf16, -1, NULL, 0, NULL, NULL); - if (buffer_utf8_size <= 0) { - return VK_SUCCESS; + bool oom = false; + char *buffer_utf8 = loader_convert_wchar_to_char(inst, buffer_utf16, &oom, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); + if (oom) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } - - char *buffer_utf8 = loader_instance_heap_calloc(inst, buffer_utf8_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); if (NULL == buffer_utf8) { - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - if (WideCharToMultiByte(CP_UTF8, 0, buffer_utf16, -1, buffer_utf8, buffer_utf8_size, NULL, NULL) != buffer_utf8_size) { - return VK_SUCCESS; + goto out; } // Successfully got the 'real' path to the library. *out_path = buffer_utf8; - return VK_SUCCESS; + +out: + loader_instance_heap_free(inst, buffer_utf16); + return res; #else // Do nothing, platform doesn't handle getting the path to a library @@ -969,7 +983,7 @@ VkResult loader_add_instance_extensions(const struct loader_instance *inst, struct loader_extension_list *ext_list) { uint32_t i; uint32_t count = 0; - VkExtensionProperties *ext_props; + VkExtensionProperties *ext_props = NULL; VkResult res = VK_SUCCESS; if (!fp_get_props) { @@ -998,7 +1012,7 @@ VkResult loader_add_instance_extensions(const struct loader_instance *inst, goto out; } - ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties)); + ext_props = loader_instance_heap_calloc(inst, count * sizeof(VkExtensionProperties), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == ext_props) { res = VK_ERROR_OUT_OF_HOST_MEMORY; goto out; @@ -1025,6 +1039,7 @@ VkResult loader_add_instance_extensions(const struct loader_instance *inst, } out: + loader_instance_heap_free(inst, ext_props); return res; } @@ -1041,31 +1056,33 @@ VkResult loader_add_device_extensions(const struct loader_instance *inst, if (res != VK_SUCCESS) { loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_add_device_extensions: Error getting physical device extension info count from library %s", lib_name); - return res; + goto out; } if (count > 0) { - ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties)); - if (!ext_props) { + ext_props = loader_instance_heap_calloc(inst, count * sizeof(VkExtensionProperties), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == ext_props) { loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_add_device_extensions: Failed to allocate space for device extension properties from library %s.", lib_name); - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } uint32_t allocated_count = count; res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, ext_props); if (res != VK_SUCCESS) { - return res; + goto out; } // The count returned by the second call sizes the array, but never read past what we actually allocated. for (i = 0; i < count && i < allocated_count; i++) { res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]); if (res != VK_SUCCESS) { - return res; + goto out; } } } - - return VK_SUCCESS; +out: + loader_instance_heap_free(inst, ext_props); + return res; } VkResult loader_init_generic_list(const struct loader_instance *inst, struct loader_generic_list *list_info, size_t element_size) { @@ -2148,13 +2165,18 @@ VkResult loader_scanned_icd_add(const struct loader_instance *inst, struct loade goto out; } + bool oom = false; // TODO implement smarter opening/closing of libraries. For now this // function leaves libraries open and the scanned_icd_clear closes them #if defined(__Fuchsia__) handle = loader_platform_open_driver(filename); #else - handle = loader_platform_open_library(filename); + handle = loader_platform_open_library(inst, filename, &oom); #endif + if (oom) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } if (NULL == handle) { loader_handle_load_library_error(inst, filename, lib_status); if (lib_status && *lib_status == LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY) { @@ -2528,10 +2550,17 @@ VkResult combine_manifest_directory_and_library_path(const struct loader_instanc // file in the paths. If filename already is a path then no searching in the given paths. // // @return - A string in out_fullpath of either the full path or file. -void loader_get_fullpath(const char *file, const char *in_dirs, size_t out_size, char *out_fullpath) { +VkResult loader_get_fullpath(const struct loader_instance *inst, const char *file, const char *in_dirs, size_t out_size, + char *out_fullpath) { + char *dirs_copy = NULL; + VkResult res = VK_SUCCESS; if (!loader_platform_is_path(file) && *in_dirs) { size_t dirs_copy_len = strlen(in_dirs) + 1; - char *dirs_copy = loader_stack_alloc(dirs_copy_len); + dirs_copy = loader_instance_heap_calloc(inst, dirs_copy_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == dirs_copy) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } loader_strncpy(dirs_copy, dirs_copy_len, in_dirs, dirs_copy_len); // find if file exists after prepending paths in given list @@ -2540,8 +2569,16 @@ void loader_get_fullpath(const char *file, const char *in_dirs, size_t out_size, char *next_dir = loader_get_next_path(dir); while (*dir && next_dir && out_fullpath) { int path_concat_ret = snprintf(out_fullpath, out_size, "%s%c%s", dir, DIRECTORY_SYMBOL, file); - if (path_concat_ret >= 0 && loader_platform_file_exists(out_fullpath)) { - return; + if (path_concat_ret > 0) { + bool oom = false; + bool file_exists = loader_platform_file_exists(inst, out_fullpath, &oom); + if (oom) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + if (file_exists) { + goto out; + } } dir = next_dir; next_dir = loader_get_next_path(dir); @@ -2549,6 +2586,10 @@ void loader_get_fullpath(const char *file, const char *in_dirs, size_t out_size, } (void)snprintf(out_fullpath, out_size, "%s", file); + +out: + loader_instance_heap_free(inst, dirs_copy); + return res; } // Verify that all component layers in a meta-layer are valid. @@ -2560,14 +2601,6 @@ bool verify_meta_layer_component_layers(const struct loader_instance *inst, size struct loader_layer_properties *prop = &instance_layers->list[prop_index]; loader_api_version meta_layer_version = loader_make_version(prop->info.specVersion); - if (NULL == already_checked_meta_layers) { - already_checked_meta_layers = loader_stack_alloc(sizeof(bool) * instance_layers->count); - if (already_checked_meta_layers == NULL) { - return false; - } - memset(already_checked_meta_layers, 0, sizeof(bool) * instance_layers->count); - } - // Mark this meta layer as 'already checked', indicating which layers have already been recursed. already_checked_meta_layers[prop_index] = true; @@ -2695,16 +2728,28 @@ VkResult verify_all_meta_layers(struct loader_instance *inst, const struct loade struct loader_layer_list *instance_layers, bool *override_layer_present) { VkResult res = VK_SUCCESS; *override_layer_present = false; + // No layers, no problem + if (instance_layers->count == 0) { + return VK_SUCCESS; + } + bool *already_checked_meta_layers = + loader_instance_heap_calloc(inst, sizeof(bool) * instance_layers->count, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == already_checked_meta_layers) { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) { struct loader_layer_properties *prop = &instance_layers->list[i]; // If this is a meta-layer, make sure it is valid if (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) { - if (verify_meta_layer_component_layers(inst, i, instance_layers, NULL)) { + // The size of the layer list doesn't change so we can re-use the allocation, but we do need to clear it every iteration + memset(already_checked_meta_layers, 0, sizeof(bool) * instance_layers->count); + + if (verify_meta_layer_component_layers(inst, i, instance_layers, already_checked_meta_layers)) { // If any meta layer is valid, update its extension list to include the extensions from its component layers. res = update_meta_layer_extensions_from_component_layers(inst, prop, instance_layers); if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { - return res; + goto out; } if (prop->is_override && loader_implicit_layer_is_enabled(inst, filters, prop)) { *override_layer_present = true; @@ -2718,20 +2763,26 @@ VkResult verify_all_meta_layers(struct loader_instance *inst, const struct loade } } } +out: + loader_instance_heap_free(inst, already_checked_meta_layers); + return res; } // If the current working directory matches any app_key_path of the layers, remove all other override layers. // Otherwise if no matching app_key was found, remove all but the global override layer, which has no app_key_path. -void remove_all_non_valid_override_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers) { +VkResult remove_all_non_valid_override_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers) { if (instance_layers == NULL) { - return; + return VK_SUCCESS; } - char cur_path[1024]; - char *ret = loader_platform_executable_path(cur_path, 1024); - if (NULL == ret) { - return; + bool oom = false; + char *cur_path = loader_platform_executable_path(inst, &oom); + if (oom) { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + if (NULL == cur_path) { + return VK_SUCCESS; // No way to get the current app path, so give up } // Find out if there is an override layer with same the app_key_path as the path to the current executable. // If more than one is found, remove it and use the first layer @@ -2790,6 +2841,10 @@ void remove_all_non_valid_override_layers(struct loader_instance *inst, struct l } else if (global_layer_index >= 0) { loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Using the global override layer"); } + + loader_instance_heap_free(inst, cur_path); + + return VK_SUCCESS; } /* The following are required in the "layer" object: @@ -3455,7 +3510,10 @@ VkResult add_data_files(const struct loader_instance *inst, struct loader_string #else #warning add_data_files must define relative path copy for this platform #endif - loader_get_fullpath(cur_file, name, sizeof(full_path), full_path); + vk_result = loader_get_fullpath(inst, cur_file, name, sizeof(full_path), full_path); + if (VK_ERROR_OUT_OF_HOST_MEMORY == vk_result) { + break; + } name = full_path; VkResult local_res; @@ -3493,7 +3551,10 @@ VkResult add_data_files(const struct loader_instance *inst, struct loader_string // 'name' is the bare filename, 'cur_file' is the directory being scanned; the substring "file" in // cur_file just confuses the naming heuristic below. // NOLINTNEXTLINE(readability-suspicious-call-argument) - arguments are correctly ordered, not swapped - loader_get_fullpath(name, cur_file, sizeof(full_path), full_path); + vk_result = loader_get_fullpath(inst, name, cur_file, sizeof(full_path), full_path); + if (VK_ERROR_OUT_OF_HOST_MEMORY == vk_result) { + break; + } name = full_path; VkResult local_res; @@ -3514,6 +3575,10 @@ VkResult add_data_files(const struct loader_instance *inst, struct loader_string } } } + // Double nested loop, so need to propagate break from inner loop to outer loop + if (VK_ERROR_OUT_OF_HOST_MEMORY == vk_result) { + break; + } } out: @@ -3625,7 +3690,14 @@ VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enu relative_location = VK_DRIVERS_INFO_RELATIVE_DIR; #endif #if defined(_WIN32) - package_path = windows_get_app_package_manifest_path(inst); + { + bool oom = false; + package_path = windows_get_app_package_manifest_path(inst, &oom); + if (oom) { + vk_result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + } #endif break; case LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER: @@ -3635,7 +3707,14 @@ VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enu relative_location = VK_ILAYERS_INFO_RELATIVE_DIR; #endif #if defined(_WIN32) - package_path = windows_get_app_package_manifest_path(inst); + { + bool oom = false; + package_path = windows_get_app_package_manifest_path(inst, &oom); + if (oom) { + vk_result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + } #endif break; case LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER: @@ -4153,12 +4232,12 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t goto out; } - icd_details = loader_stack_alloc(sizeof(struct ICDManifestInfo) * manifest_files.count); + icd_details = loader_instance_heap_calloc(inst, sizeof(struct ICDManifestInfo) * manifest_files.count, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == icd_details) { res = VK_ERROR_OUT_OF_HOST_MEMORY; goto out; } - memset(icd_details, 0, sizeof(struct ICDManifestInfo) * manifest_files.count); for (uint32_t i = 0; i < manifest_files.count; i++) { VkResult icd_res = VK_SUCCESS; @@ -4239,6 +4318,7 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t for (uint32_t i = 0; i < manifest_files.count; i++) { loader_instance_heap_free(inst, icd_details[i].full_library_path); } + loader_instance_heap_free(inst, icd_details); } free_string_list(inst, &manifest_files); return res; @@ -4356,7 +4436,10 @@ VkResult loader_scan_for_layers(struct loader_instance *inst, struct loader_laye } // Remove any extraneous override layers. - remove_all_non_valid_override_layers(inst, ®ular_instance_layers); + res = remove_all_non_valid_override_layers(inst, ®ular_instance_layers); + if (VK_SUCCESS != res) { + goto out; + } // Check to see if the override layer is present, and use it's override paths. for (uint32_t i = 0; i < regular_instance_layers.count; i++) { @@ -4451,8 +4534,10 @@ VkResult loader_scan_for_implicit_layers(struct loader_instance *inst, struct lo } // Remove any extraneous override layers. - remove_all_non_valid_override_layers(inst, ®ular_instance_layers); - + res = remove_all_non_valid_override_layers(inst, ®ular_instance_layers); + if (VK_SUCCESS != res) { + goto out; + } // Check to see if either the override layer is present, or another implicit meta-layer. // Each of these may require explicit layers to be enabled at this time. for (uint32_t i = 0; i < regular_instance_layers.count; i++) { @@ -4702,8 +4787,9 @@ struct loader_instance *loader_get_instance(VkInstance instance) { return ptr_instance; } -loader_platform_dl_handle loader_open_layer_file(const struct loader_instance *inst, struct loader_layer_properties *prop) { - loader_platform_dl_handle lib_handle = loader_platform_open_library(prop->lib_name); +loader_platform_dl_handle loader_open_layer_file(const struct loader_instance *inst, struct loader_layer_properties *prop, + bool *oom) { + loader_platform_dl_handle lib_handle = loader_platform_open_library(inst, prop->lib_name, oom); prop->lib_handle = lib_handle; if (lib_handle == NULL) { loader_handle_load_library_error(inst, prop->lib_name, &prop->lib_status); @@ -5039,18 +5125,23 @@ VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, c chain_info.function = VK_LAYER_LINK_INFO; loader_create_info.pNext = &chain_info; - layer_instance_link_info = loader_stack_alloc(sizeof(VkLayerInstanceLink) * inst->expanded_activated_layer_list.count); + layer_instance_link_info = loader_instance_heap_calloc( + inst, sizeof(VkLayerInstanceLink) * inst->expanded_activated_layer_list.count, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (!layer_instance_link_info) { loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_create_instance_chain: Failed to alloc Instance objects for layer"); - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } - activated_layers = loader_stack_alloc(sizeof(struct activated_layer_info) * inst->expanded_activated_layer_list.count); + activated_layers = + loader_instance_heap_calloc(inst, sizeof(struct activated_layer_info) * inst->expanded_activated_layer_list.count, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (!activated_layers) { loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_create_instance_chain: Failed to alloc activated layer storage array"); - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } // Create instance chain of enabled layers @@ -5067,10 +5158,11 @@ VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, c if (NULL == layer_prop->lib_name) { continue; } - - lib_handle = loader_open_layer_file(inst, layer_prop); - if (layer_prop->lib_status == LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + bool oom = false; + lib_handle = loader_open_layer_file(inst, layer_prop, &oom); + if (oom || layer_prop->lib_status == LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } if (!lib_handle) { continue; @@ -5172,7 +5264,7 @@ VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, c res = fixup_library_binary_path(inst, &(layer_prop->lib_name), layer_prop->lib_handle, cur_gipa); if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { - return res; + goto out; } activated_layers[num_activated_layers].name = layer_prop->info.layerName; @@ -5254,7 +5346,8 @@ VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, c break; } if (app_requested) { - return VK_ERROR_LAYER_NOT_PRESENT; + res = VK_ERROR_LAYER_NOT_PRESENT; + goto out; } } } @@ -5338,16 +5431,21 @@ VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, c if (pCreateInfo->enabledLayerCount > 0 && pCreateInfo->ppEnabledLayerNames != NULL) { res = create_string_list(inst, pCreateInfo->enabledLayerCount, &inst->enabled_layer_names); if (res != VK_SUCCESS) { - return res; + goto out; } for (uint32_t i = 0; i < pCreateInfo->enabledLayerCount; ++i) { res = copy_str_to_string_list(inst, &inst->enabled_layer_names, pCreateInfo->ppEnabledLayerNames[i], strlen(pCreateInfo->ppEnabledLayerNames[i])); - if (res != VK_SUCCESS) return res; + if (res != VK_SUCCESS) { + goto out; + } } } } +out: + loader_instance_heap_free(inst, layer_instance_link_info); + loader_instance_heap_free(inst, activated_layers); return res; } @@ -5374,6 +5472,9 @@ VkResult loader_create_device_chain(VkPhysicalDevice pd, const VkDeviceCreateInf VkLayerDeviceCreateInfo chain_info = {0}; VkDeviceCreateInfo loader_create_info = {0}; VkDeviceGroupDeviceCreateInfo *original_device_group_create_info_struct = NULL; + VkDeviceGroupDeviceCreateInfo *temp_struct = NULL; + VkPhysicalDevice *phys_dev_array = NULL; + bool modified_passed_in_pNext_chain = false; VkResult res = VK_SUCCESS; PFN_vkGetDeviceProcAddr fpGDPA = NULL; @@ -5420,15 +5521,19 @@ VkResult loader_create_device_chain(VkPhysicalDevice pd, const VkDeviceCreateInf if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) { VkDeviceGroupDeviceCreateInfo *cur_struct = (VkDeviceGroupDeviceCreateInfo *)pNext; if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) { - VkDeviceGroupDeviceCreateInfo *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfo)); - VkPhysicalDevice *phys_dev_array = NULL; + temp_struct = loader_calloc_with_instance_fallback(pAllocator, inst, sizeof(VkDeviceGroupDeviceCreateInfo), + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == temp_struct) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfo)); - phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount); + phys_dev_array = (VkPhysicalDevice *)loader_calloc_with_instance_fallback( + pAllocator, inst, sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == phys_dev_array) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } // Before calling down, replace the incoming physical device values (which are really loader trampoline @@ -5444,6 +5549,7 @@ VkResult loader_create_device_chain(VkPhysicalDevice pd, const VkDeviceCreateInf // Replace the old struct in the pNext chain with this one. pPrev->pNext = (VkBaseOutStructure *)temp_struct; + modified_passed_in_pNext_chain = true; } break; } @@ -5453,18 +5559,24 @@ VkResult loader_create_device_chain(VkPhysicalDevice pd, const VkDeviceCreateInf } } if (inst->expanded_activated_layer_list.count > 0) { - layer_device_link_info = loader_stack_alloc(sizeof(VkLayerDeviceLink) * inst->expanded_activated_layer_list.count); + layer_device_link_info = loader_calloc_with_instance_fallback( + pAllocator, inst, sizeof(VkLayerDeviceLink) * inst->expanded_activated_layer_list.count, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (!layer_device_link_info) { loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_create_device_chain: Failed to alloc Device objects for layer. Skipping Layer."); - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } - activated_layers = loader_stack_alloc(sizeof(struct activated_layer_info) * inst->expanded_activated_layer_list.count); + activated_layers = loader_calloc_with_instance_fallback( + pAllocator, inst, sizeof(struct activated_layer_info) * inst->expanded_activated_layer_list.count, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (!activated_layers) { loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_create_device_chain: Failed to alloc activated layer storage array"); - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO; @@ -5554,16 +5666,17 @@ VkResult loader_create_device_chain(VkPhysicalDevice pd, const VkDeviceCreateInf } } + // This struct needs to live in the top level scope of the function because the cleanup routine to un-link the modified pNext + // chain needs to access it. + VkLayerDeviceCreateInfo create_info_disp = {0}; + create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO; + create_info_disp.function = VK_LOADER_DATA_CALLBACK; + create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch; + VkDevice created_device = (VkDevice)dev; PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)nextGIPA(inst->instance, "vkCreateDevice"); - if (fpCreateDevice) { - VkLayerDeviceCreateInfo create_info_disp; - - create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO; - create_info_disp.function = VK_LOADER_DATA_CALLBACK; - - create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch; + if (fpCreateDevice) { // If layer debugging is enabled, let's print out the full callstack with layers in their // defined order. uint32_t layer_driver_bits = VULKAN_LOADER_LAYER_BIT | VULKAN_LOADER_DRIVER_BIT; @@ -5592,9 +5705,28 @@ VkResult loader_create_device_chain(VkPhysicalDevice pd, const VkDeviceCreateInf loader_create_info.pNext = &create_info_disp; res = fpCreateDevice(pd, &loader_create_info, pAllocator, &created_device); - // Because we changed the pNext chain to use our own VkDeviceGroupDeviceCreateInfo, we need to fixup the chain to - // point back at the original VkDeviceGroupDeviceCreateInfo. This must happen even if device creation failed, otherwise - // the caller's chain is left pointing at our stack allocated copy. + if (res != VK_SUCCESS) { + goto out; + } + dev->chain_device = created_device; + } else { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, + "loader_create_device_chain: Failed to find \'vkCreateDevice\' in layers or ICD"); + // Couldn't find CreateDevice function! + res = VK_ERROR_INITIALIZATION_FAILED; + goto out; + } + + // Initialize device dispatch table + loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA, dev->chain_device); + // Initialize the dispatch table to functions which need terminators + // These functions point directly to the driver, not the terminator functions + init_extension_device_proc_terminator_dispatch(dev); +out: + // Because we changed the pNext chain to use our own VkDeviceGroupDeviceCreateInfo, we need to fixup the chain to + // point back at the original VkDeviceGroupDeviceCreateInfo. This must happen even if device creation failed, otherwise + // the caller's chain is left pointing at our copy. + if (modified_passed_in_pNext_chain) { VkBaseOutStructure *pNext = (VkBaseOutStructure *)loader_create_info.pNext; VkBaseOutStructure *pPrev = (VkBaseOutStructure *)&loader_create_info; while (NULL != pNext) { @@ -5609,23 +5741,12 @@ VkResult loader_create_device_chain(VkPhysicalDevice pd, const VkDeviceCreateInf pPrev = pNext; pNext = pNext->pNext; } - - if (res != VK_SUCCESS) { - return res; - } - dev->chain_device = created_device; - } else { - loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, - "loader_create_device_chain: Failed to find \'vkCreateDevice\' in layers or ICD"); - // Couldn't find CreateDevice function! - return VK_ERROR_INITIALIZATION_FAILED; } - // Initialize device dispatch table - loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA, dev->chain_device); - // Initialize the dispatch table to functions which need terminators - // These functions point directly to the driver, not the terminator functions - init_extension_device_proc_terminator_dispatch(dev); + loader_free_with_instance_fallback(pAllocator, inst, temp_struct); + loader_free_with_instance_fallback(pAllocator, inst, (void *)phys_dev_array); + loader_free_with_instance_fallback(pAllocator, inst, layer_device_link_info); + loader_free_with_instance_fallback(pAllocator, inst, activated_layers); return res; } @@ -5854,12 +5975,16 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateI #if defined(LOADER_ENABLE_LINUX_SORT) extension_count += 1; #endif // LOADER_ENABLE_LINUX_SORT - filtered_extension_names = loader_stack_alloc(extension_count * sizeof(char *)); - if (!filtered_extension_names) { - loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT, 0, - "terminator_CreateInstance: Failed create extension name array for %d extensions", extension_count); - res = VK_ERROR_OUT_OF_HOST_MEMORY; - goto out; + + if (extension_count > 0) { + filtered_extension_names = (char **)loader_instance_heap_calloc(ptr_instance, extension_count * sizeof(char *), + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!filtered_extension_names) { + loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT, 0, + "terminator_CreateInstance: Failed create extension name array for %d extensions", extension_count); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } } icd_create_info.ppEnabledExtensionNames = (const char *const *)filtered_extension_names; @@ -5924,7 +6049,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateI for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) { prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[j], &icd_exts); - if (prop) { + if (prop && filtered_extension_names) { filtered_extension_names[icd_create_info.enabledExtensionCount] = (char *)pCreateInfo->ppEnabledExtensionNames[j]; icd_create_info.enabledExtensionCount++; } @@ -5937,7 +6062,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateI (VK_API_VERSION_MAJOR(icd_term->scanned_icd->api_version) == 1 && VK_API_VERSION_MINOR(icd_term->scanned_icd->api_version) == 0)) { prop = get_extension_property(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, &icd_exts); - if (prop) { + if (prop && filtered_extension_names) { filtered_extension_names[icd_create_info.enabledExtensionCount] = (char *)VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; icd_create_info.enabledExtensionCount++; @@ -5990,7 +6115,8 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateI if ((pCreateInfo->flags & VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR) == 1) { bool supports_portability_enumeration = false; for (uint32_t j = 0; j < icd_create_info.enabledExtensionCount; j++) { - if (strcmp(filtered_extension_names[j], VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) { + if (filtered_extension_names && + strcmp(filtered_extension_names[j], VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) { supports_portability_enumeration = true; break; } @@ -6150,6 +6276,8 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateI &ptr_instance->enabled_extensions); } + loader_instance_heap_free(ptr_instance, (void *)filtered_extension_names); + return res; } @@ -6229,6 +6357,10 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physical VkBaseOutStructure *caller_dgci_container = NULL; VkDeviceGroupDeviceCreateInfo *caller_dgci = NULL; + VkDeviceGroupDeviceCreateInfo *temp_struct = NULL; + VkPhysicalDevice *phys_dev_array = NULL; + char **filtered_extension_names = NULL; + if (NULL == dev) { loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0, "terminator_CreateDevice: Loader device pointer null encountered. Possibly set by active layer. (Policy " @@ -6261,14 +6393,16 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physical // NOTE: Need to filter the extensions to only those supported by the ICD. // No ICD will advertise support for layers. An ICD library could support a layer, // but it would be independent of the actual ICD, just in the same library. - char **filtered_extension_names = NULL; if (0 < pCreateInfo->enabledExtensionCount) { - filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *)); + filtered_extension_names = (char **)loader_calloc_with_instance_fallback( + pAllocator, icd_term->this_instance, pCreateInfo->enabledExtensionCount * sizeof(char *), + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == filtered_extension_names) { loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0, "terminator_CreateDevice: Failed to create extension name storage for %d extensions", pCreateInfo->enabledExtensionCount); - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } } @@ -6299,7 +6433,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physical continue; } VkExtensionProperties *prop = get_extension_property(extension_name, &icd_exts); - if (prop) { + if (prop && filtered_extension_names) { filtered_extension_names[localCreateInfo.enabledExtensionCount] = (char *)extension_name; localCreateInfo.enabledExtensionCount++; } else { @@ -6320,15 +6454,20 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physical if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) { VkDeviceGroupDeviceCreateInfo *cur_struct = (VkDeviceGroupDeviceCreateInfo *)pNext; if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) { - VkDeviceGroupDeviceCreateInfo *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfo)); - VkPhysicalDevice *phys_dev_array = NULL; + temp_struct = loader_calloc_with_instance_fallback(pAllocator, icd_term->this_instance, + sizeof(VkDeviceGroupDeviceCreateInfo), + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == temp_struct) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfo)); - phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount); + phys_dev_array = (VkPhysicalDevice *)loader_calloc_with_instance_fallback( + pAllocator, icd_term->this_instance, sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == phys_dev_array) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } // Before calling down, replace the incoming physical device values (which are really loader terminator @@ -6503,6 +6642,10 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physical caller_dgci_container->pNext = (VkBaseOutStructure *)caller_dgci; } + loader_free_with_instance_fallback(pAllocator, icd_term->this_instance, (void *)filtered_extension_names); + loader_free_with_instance_fallback(pAllocator, icd_term->this_instance, temp_struct); + loader_free_with_instance_fallback(pAllocator, icd_term->this_instance, (void *)phys_dev_array); + return res; } @@ -6516,6 +6659,9 @@ VkResult setup_loader_tramp_phys_devs(struct loader_instance *inst, uint32_t phy uint32_t new_count = inst->total_gpu_count; struct loader_physical_device_tramp **new_phys_devs = NULL; + int32_t *old_to_new_index = NULL; + int32_t *new_to_old_index = NULL; + if (0 == phys_dev_count) { return VK_SUCCESS; } @@ -6524,10 +6670,17 @@ VkResult setup_loader_tramp_phys_devs(struct loader_instance *inst, uint32_t phy } // We want an old to new index array and a new to old index array - int32_t *old_to_new_index = (int32_t *)loader_stack_alloc(sizeof(int32_t) * old_count); - int32_t *new_to_old_index = (int32_t *)loader_stack_alloc(sizeof(int32_t) * new_count); - if (NULL == old_to_new_index || NULL == new_to_old_index) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + old_to_new_index = + (int32_t *)loader_instance_heap_calloc(inst, sizeof(int32_t) * old_count, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == old_to_new_index) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + new_to_old_index = + (int32_t *)loader_instance_heap_calloc(inst, sizeof(int32_t) * new_count, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == new_to_old_index) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } // Initialize both @@ -6681,6 +6834,8 @@ VkResult setup_loader_tramp_phys_devs(struct loader_instance *inst, uint32_t phy if (VK_SUCCESS != res) { inst->total_gpu_count = 0; } + loader_instance_heap_free(inst, old_to_new_index); + loader_instance_heap_free(inst, new_to_old_index); return res; } @@ -6777,6 +6932,11 @@ VkResult setup_loader_term_phys_devs(struct loader_instance *inst) { uint32_t new_phys_devs_count = 0; struct loader_physical_device_term **new_phys_devs = NULL; + // No ICD's, no problem + if (inst->icd_terms_count == 0) { + return VK_SUCCESS; + } + #if defined(_WIN32) // Get the physical devices supported by platform sorting mechanism into a separate list res = windows_read_sorted_physical_devices(inst, &windows_sorted_devices_count, &windows_sorted_devices_array); @@ -6788,8 +6948,8 @@ VkResult setup_loader_term_phys_devs(struct loader_instance *inst) { icd_count = inst->icd_terms_count; // Allocate something to store the physical device characteristics that we read from each ICD. - icd_phys_dev_array = - (struct loader_icd_physical_devices *)loader_stack_alloc(sizeof(struct loader_icd_physical_devices) * icd_count); + icd_phys_dev_array = (struct loader_icd_physical_devices *)loader_instance_heap_calloc( + inst, sizeof(struct loader_icd_physical_devices) * icd_count, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == icd_phys_dev_array) { loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "setup_loader_term_phys_devs: Failed to allocate temporary ICD Physical device info array of size %d", @@ -6797,14 +6957,14 @@ VkResult setup_loader_term_phys_devs(struct loader_instance *inst) { res = VK_ERROR_OUT_OF_HOST_MEMORY; goto out; } - memset(icd_phys_dev_array, 0, sizeof(struct loader_icd_physical_devices) * icd_count); // For each ICD, query the number of physical devices, and then get an // internal value for those physical devices. icd_term = inst->icd_terms; uint32_t icd_idx = 0; while (NULL != icd_term) { - res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &icd_phys_dev_array[icd_idx].device_count, NULL); + struct loader_icd_physical_devices *icd_phys_dev = &icd_phys_dev_array[icd_idx]; + res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &icd_phys_dev->device_count, NULL); if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "setup_loader_term_phys_devs: Call to \'vkEnumeratePhysicalDevices\' in ICD %s failed with error code " @@ -6812,47 +6972,54 @@ VkResult setup_loader_term_phys_devs(struct loader_instance *inst) { icd_term->scanned_icd->lib_name); goto out; } else if (VK_SUCCESS == res) { - icd_phys_dev_array[icd_idx].physical_devices = - (VkPhysicalDevice *)loader_stack_alloc(icd_phys_dev_array[icd_idx].device_count * sizeof(VkPhysicalDevice)); - if (NULL == icd_phys_dev_array[icd_idx].physical_devices) { - loader_log( - inst, VULKAN_LOADER_ERROR_BIT, 0, - "setup_loader_term_phys_devs: Failed to allocate temporary ICD Physical device array for ICD %s of size %d", - icd_term->scanned_icd->lib_name, icd_phys_dev_array[icd_idx].device_count); - res = VK_ERROR_OUT_OF_HOST_MEMORY; - goto out; - } + // Prevents allocating a zero byte array + if (icd_phys_dev->device_count == 0) { + icd_phys_dev->physical_devices = 0; + } else { + icd_phys_dev->physical_devices = (VkPhysicalDevice *)loader_instance_heap_calloc( + inst, icd_phys_dev->device_count * sizeof(VkPhysicalDevice), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == icd_phys_dev->physical_devices) { + loader_log( + inst, VULKAN_LOADER_ERROR_BIT, 0, + "setup_loader_term_phys_devs: Failed to allocate temporary ICD Physical device array for ICD %s of size %d", + icd_term->scanned_icd->lib_name, icd_phys_dev->device_count); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } - uint32_t allocated_count = icd_phys_dev_array[icd_idx].device_count; - res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &(icd_phys_dev_array[icd_idx].device_count), - icd_phys_dev_array[icd_idx].physical_devices); - if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { - loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, - "setup_loader_term_phys_devs: Call to \'vkEnumeratePhysicalDevices\' in ICD %s failed with error code " - "VK_ERROR_OUT_OF_HOST_MEMORY", - icd_term->scanned_icd->lib_name); - goto out; - } - if (VK_SUCCESS != res) { - loader_log( - inst, VULKAN_LOADER_ERROR_BIT, 0, - "setup_loader_term_phys_devs: Call to \'vkEnumeratePhysicalDevices\' in ICD %s failed with error code %d", - icd_term->scanned_icd->lib_name, res); - icd_phys_dev_array[icd_idx].device_count = 0; - icd_phys_dev_array[icd_idx].physical_devices = 0; - } else if (icd_phys_dev_array[icd_idx].device_count > allocated_count) { - // The fill call sizes the array, but never read past what we actually allocated. - icd_phys_dev_array[icd_idx].device_count = allocated_count; + uint32_t allocated_count = icd_phys_dev->device_count; + res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &(icd_phys_dev->device_count), + icd_phys_dev->physical_devices); + if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { + loader_log( + inst, VULKAN_LOADER_ERROR_BIT, 0, + "setup_loader_term_phys_devs: Call to \'vkEnumeratePhysicalDevices\' in ICD %s failed with error code " + "VK_ERROR_OUT_OF_HOST_MEMORY", + icd_term->scanned_icd->lib_name); + goto out; + } + if (VK_SUCCESS != res) { + loader_log( + inst, VULKAN_LOADER_ERROR_BIT, 0, + "setup_loader_term_phys_devs: Call to \'vkEnumeratePhysicalDevices\' in ICD %s failed with error code %d", + icd_term->scanned_icd->lib_name, res); + icd_phys_dev->device_count = 0; + loader_instance_heap_free(inst, (void *)icd_phys_dev->physical_devices); + icd_phys_dev->physical_devices = NULL; + } else if (icd_phys_dev->device_count > allocated_count) { + // The fill call sizes the array, but never read past what we actually allocated. + icd_phys_dev->device_count = allocated_count; + } } } else { loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "setup_loader_term_phys_devs: Call to \'vkEnumeratePhysicalDevices\' in ICD %s failed with error code %d", icd_term->scanned_icd->lib_name, res); - icd_phys_dev_array[icd_idx].device_count = 0; - icd_phys_dev_array[icd_idx].physical_devices = 0; + icd_phys_dev->device_count = 0; + icd_phys_dev->physical_devices = 0; } - icd_phys_dev_array[icd_idx].icd_term = icd_term; - icd_term->physical_device_count = icd_phys_dev_array[icd_idx].device_count; + icd_phys_dev->icd_term = icd_term; + icd_term->physical_device_count = icd_phys_dev->device_count; icd_term = icd_term->next; ++icd_idx; } @@ -7014,6 +7181,13 @@ VkResult setup_loader_term_phys_devs(struct loader_instance *inst) { } loader_instance_heap_free(inst, windows_sorted_devices_array); } + if (NULL != icd_phys_dev_array) { + for (uint32_t i = 0; i < icd_count; i++) { + loader_instance_heap_free(inst, (void *)icd_phys_dev_array[i].physical_devices); + } + + loader_instance_heap_free(inst, icd_phys_dev_array); + } return res; } @@ -7106,9 +7280,11 @@ VkResult setup_loader_tramp_phys_dev_groups(struct loader_instance *inst, uint32 for (cur_idx = 0; cur_idx < group_count; ++cur_idx) { phys_dev_count += groups[cur_idx].physicalDeviceCount; } - VkPhysicalDevice *devices = (VkPhysicalDevice *)loader_stack_alloc(sizeof(VkPhysicalDevice) * phys_dev_count); + VkPhysicalDevice *devices = (VkPhysicalDevice *)loader_instance_heap_calloc(inst, sizeof(VkPhysicalDevice) * phys_dev_count, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == devices) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } uint32_t cur_device = 0; @@ -7121,7 +7297,7 @@ VkResult setup_loader_tramp_phys_dev_groups(struct loader_instance *inst, uint32 // Update the devices based on the loader physical device values. res = setup_loader_tramp_phys_devs(inst, phys_dev_count, devices); if (VK_SUCCESS != res) { - return res; + goto out; } // Update the devices in the group structures now @@ -7131,6 +7307,8 @@ VkResult setup_loader_tramp_phys_dev_groups(struct loader_instance *inst, uint32 groups[cur_idx].physicalDevices[dev_idx] = devices[cur_device++]; } } +out: + loader_instance_heap_free(inst, (void *)devices); return res; } @@ -7191,25 +7369,32 @@ VkResult check_physical_device_extensions_for_driver_properties_extension(struct if (res != VK_SUCCESS || extension_count == 0) { return VK_SUCCESS; } - VkExtensionProperties *extension_data = loader_stack_alloc(sizeof(VkExtensionProperties) * extension_count); + VkExtensionProperties *extension_data = + loader_instance_heap_calloc(phys_dev_term->this_icd_term->this_instance, sizeof(VkExtensionProperties) * extension_count, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == extension_data) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } uint32_t allocated_count = extension_count; res = phys_dev_term->this_icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &extension_count, extension_data); if (res != VK_SUCCESS) { - return VK_SUCCESS; + res = VK_SUCCESS; + goto out; } // The count returned by the second call sizes the array, but never read past what we actually allocated. for (uint32_t j = 0; j < extension_count && j < allocated_count; j++) { if (!strcmp(extension_data[j].extensionName, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) { *supports_driver_properties = true; - return VK_SUCCESS; + goto out; } } - return VK_SUCCESS; +out: + loader_instance_heap_free(phys_dev_term->this_icd_term->this_instance, extension_data); + + return res; } // Helper struct containing the relevant details of a VkPhysicalDevice necessary for applying the loader settings device @@ -7229,15 +7414,27 @@ typedef struct physical_device_configuration_details { // device_configurations in the settings file. VkResult loader_apply_settings_device_configurations(struct loader_instance *inst, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) { + // No physical devices to apply settings to + if (inst->phys_dev_count_term == 0) { + if (inst->settings.device_configuration_count > 0) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, + "loader_apply_settings_device_configurations: settings file contained device_configurations but no " + "VkPhysicalDevices were enumerated"); + return VK_ERROR_INITIALIZATION_FAILED; + } + return VK_SUCCESS; + } + + VkResult res = VK_SUCCESS; loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Selecting and ordering VkPhysicalDevices to match the loader settings device configurations list"); - physical_device_configuration_details *pd_details = - loader_stack_alloc(inst->phys_dev_count_term * sizeof(physical_device_configuration_details)); + physical_device_configuration_details *pd_details = loader_instance_heap_calloc( + inst, inst->phys_dev_count_term * sizeof(physical_device_configuration_details), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == pd_details) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } - memset(pd_details, 0, inst->phys_dev_count_term * sizeof(physical_device_configuration_details)); for (uint32_t i = 0; i < inst->phys_dev_count_term; i++) { struct loader_physical_device_term *phys_dev_term = inst->phys_devs_term[i]; @@ -7254,10 +7451,10 @@ VkResult loader_apply_settings_device_configurations(struct loader_instance *ins // If this physical device isn't 1.2, then we need to check if it supports VK_KHR_driver_properties if (!pd_details[i].pd_supports_driver_properties) { - VkResult res = check_physical_device_extensions_for_driver_properties_extension( - phys_dev_term, &pd_details[i].pd_supports_driver_properties); + res = check_physical_device_extensions_for_driver_properties_extension(phys_dev_term, + &pd_details[i].pd_supports_driver_properties); if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { - return res; + goto out; } } @@ -7296,7 +7493,8 @@ VkResult loader_apply_settings_device_configurations(struct loader_instance *ins // Catch when there are more device_configurations than space available in the output if (written_output_index >= *pPhysicalDeviceCount) { *pPhysicalDeviceCount = written_output_index; // write out how many were written - return VK_INCOMPLETE; + res = VK_INCOMPLETE; + goto out; } if (pd_details[j].pd_supports_driver_properties) { loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, @@ -7362,11 +7560,16 @@ VkResult loader_apply_settings_device_configurations(struct loader_instance *ins loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, "loader_apply_settings_device_configurations: None of the settings file device configurations had " "deviceUUID's that corresponded to enumerated VkPhysicalDevices. Returning VK_ERROR_INITIALIZATION_FAILED"); - return VK_ERROR_INITIALIZATION_FAILED; + res = VK_ERROR_INITIALIZATION_FAILED; + goto out; } *pPhysicalDeviceCount = written_output_index; // update with how many were written - return VK_SUCCESS; + +out: + loader_instance_heap_free(inst, pd_details); + + return res; } VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, @@ -7763,10 +7966,16 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups( uint32_t cur_icd_group_count = 0; VkPhysicalDeviceGroupProperties **new_phys_dev_groups = NULL; struct loader_physical_device_group_term *local_phys_dev_groups = NULL; + size_t existing_phys_dev_array_alloc_size = 0; + VkPhysicalDevice *phys_dev_array = NULL; PFN_vkEnumeratePhysicalDeviceGroups fpEnumeratePhysicalDeviceGroups = NULL; struct loader_icd_physical_devices *sorted_phys_dev_array = NULL; uint32_t sorted_count = 0; + size_t tmp_group_props_alloc_size = 0; + VkPhysicalDeviceGroupProperties *tmp_group_props = NULL; + VkPhysicalDevice *visible_phys_devs = NULL; + // For each ICD, query the number of physical device groups, and then get an // internal value for those physical devices. icd_term = inst->icd_terms; @@ -7828,14 +8037,12 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups( goto out; } - // Create a temporary array (on the stack) to keep track of the - // returned VkPhysicalDevice values. - // total_count may legitimately be 0 (no physical device groups); every subsequent use of local_phys_dev_groups - // is bounded by total_count, so a 0-byte alloca is never touched. - // NOLINTNEXTLINE(clang-analyzer-optin.portability.UnixAPI) - local_phys_dev_groups = loader_stack_alloc(sizeof(struct loader_physical_device_group_term) * total_count); - // Initialize the memory to something valid - memset(local_phys_dev_groups, 0, sizeof(struct loader_physical_device_group_term) * total_count); + local_phys_dev_groups = loader_instance_heap_calloc(inst, sizeof(struct loader_physical_device_group_term) * total_count, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == local_phys_dev_groups) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } #if defined(_WIN32) // Get the physical devices supported by platform sorting mechanism into a separate list @@ -7866,33 +8073,38 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups( count_this_time = total_count - cur_icd_group_count; } - VkPhysicalDevice *phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * count_this_time); - if (NULL == phys_dev_array) { - loader_log( - inst, VULKAN_LOADER_ERROR_BIT, 0, - "terminator_EnumeratePhysicalDeviceGroups: Failed to allocate local physical device array of size %d", - count_this_time); - res = VK_ERROR_OUT_OF_HOST_MEMORY; - goto out; - } + if (count_this_time > 0) { + void *new_phys_dev_array = loader_instance_heap_realloc( + inst, (void *)phys_dev_array, existing_phys_dev_array_alloc_size, + sizeof(VkPhysicalDevice) * count_this_time, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == new_phys_dev_array) { + loader_log( + inst, VULKAN_LOADER_ERROR_BIT, 0, + "terminator_EnumeratePhysicalDeviceGroups: Failed to allocate local physical device array of size %d", + count_this_time); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + existing_phys_dev_array_alloc_size = sizeof(VkPhysicalDevice) * count_this_time; + phys_dev_array = (VkPhysicalDevice *)new_phys_dev_array; - res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &count_this_time, phys_dev_array); - if (res != VK_SUCCESS) { - loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, - "terminator_EnumeratePhysicalDeviceGroups: Failed during dispatch call of " - "\'EnumeratePhysicalDevices\' to ICD %s to get plain phys dev count.", - icd_term->scanned_icd->lib_name); - goto out; - } + res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &count_this_time, phys_dev_array); + if (res != VK_SUCCESS) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, + "terminator_EnumeratePhysicalDeviceGroups: Failed during dispatch call of " + "\'EnumeratePhysicalDevices\' to ICD %s to get plain phys dev count.", + icd_term->scanned_icd->lib_name); + goto out; + } - // Add each GPU as it's own group - for (uint32_t indiv_gpu = 0; indiv_gpu < count_this_time; indiv_gpu++) { - uint32_t cur_index = indiv_gpu + cur_icd_group_count; - local_phys_dev_groups[cur_index].this_icd_term = icd_term; - local_phys_dev_groups[cur_index].group_props.physicalDeviceCount = 1; - local_phys_dev_groups[cur_index].group_props.physicalDevices[0] = phys_dev_array[indiv_gpu]; + // Add each GPU as it's own group + for (uint32_t indiv_gpu = 0; indiv_gpu < count_this_time; indiv_gpu++) { + uint32_t cur_index = indiv_gpu + cur_icd_group_count; + local_phys_dev_groups[cur_index].this_icd_term = icd_term; + local_phys_dev_groups[cur_index].group_props.physicalDeviceCount = 1; + local_phys_dev_groups[cur_index].group_props.physicalDevices[0] = phys_dev_array[indiv_gpu]; + } } - } else { res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time, NULL); if (res != VK_SUCCESS) { @@ -7929,44 +8141,54 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups( local_phys_dev_groups[cur_index].this_icd_term = icd_term; } } else { - // There's not enough space in the callee's allocated pPhysicalDeviceGroupProperties structs, - // so we have to allocate temporary versions to collect all the data. However, we need to make - // sure that at least the ones we do query utilize any pNext data in the callee's version. - VkPhysicalDeviceGroupProperties *tmp_group_props = - loader_stack_alloc(count_this_time * sizeof(VkPhysicalDeviceGroupProperties)); - for (uint32_t group = 0; group < count_this_time; group++) { - tmp_group_props[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES; - uint32_t cur_index = group + cur_icd_group_count; - if (*pPhysicalDeviceGroupCount > cur_index) { - tmp_group_props[group].pNext = pPhysicalDeviceGroupProperties[cur_index].pNext; - } else { - tmp_group_props[group].pNext = NULL; + if (count_this_time > 0) { + // There's not enough space in the callee's allocated pPhysicalDeviceGroupProperties structs, + // so we have to allocate temporary versions to collect all the data. However, we need to make + // sure that at least the ones we do query utilize any pNext data in the callee's version. + void *new_tmp_group_props = loader_instance_heap_realloc( + inst, tmp_group_props, tmp_group_props_alloc_size, + count_this_time * sizeof(VkPhysicalDeviceGroupProperties), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == new_tmp_group_props) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + tmp_group_props = (VkPhysicalDeviceGroupProperties *)new_tmp_group_props; + tmp_group_props_alloc_size = count_this_time * sizeof(VkPhysicalDeviceGroupProperties); + + for (uint32_t group = 0; group < count_this_time; group++) { + tmp_group_props[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES; + uint32_t cur_index = group + cur_icd_group_count; + if (*pPhysicalDeviceGroupCount > cur_index) { + tmp_group_props[group].pNext = pPhysicalDeviceGroupProperties[cur_index].pNext; + } else { + tmp_group_props[group].pNext = NULL; + } + tmp_group_props[group].subsetAllocation = false; } - tmp_group_props[group].subsetAllocation = false; - } - res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time, tmp_group_props); - if (res != VK_SUCCESS) { - loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, - "terminator_EnumeratePhysicalDeviceGroups: Failed during dispatch call of " - "\'EnumeratePhysicalDeviceGroups\' to ICD %s to get group information for temp data.", - icd_term->scanned_icd->lib_name); - goto out; - } - // Same guard as the other two paths above: the ICD can report a larger completed count here than it did - // during the counting pass. tmp_group_props and local_phys_dev_groups were both sized to the earlier - // (clamped) count_this_time, so trusting a larger value here would overflow both stack allocations. - if (count_this_time > total_count - cur_icd_group_count) { - count_this_time = total_count - cur_icd_group_count; - } - for (uint32_t group = 0; group < count_this_time; ++group) { - uint32_t cur_index = group + cur_icd_group_count; - local_phys_dev_groups[cur_index].group_props = tmp_group_props[group]; - // physicalDevices is a fixed VK_MAX_DEVICE_GROUP_SIZE array; don't trust a larger count from the ICD. - if (local_phys_dev_groups[cur_index].group_props.physicalDeviceCount > VK_MAX_DEVICE_GROUP_SIZE) { - local_phys_dev_groups[cur_index].group_props.physicalDeviceCount = VK_MAX_DEVICE_GROUP_SIZE; + res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time, tmp_group_props); + if (res != VK_SUCCESS) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, + "terminator_EnumeratePhysicalDeviceGroups: Failed during dispatch call of " + "\'EnumeratePhysicalDeviceGroups\' to ICD %s to get group information for temp data.", + icd_term->scanned_icd->lib_name); + goto out; + } + // Same guard as the other two paths above: the ICD can report a larger completed count here than it did + // during the counting pass. tmp_group_props and local_phys_dev_groups were both sized to the earlier + // (clamped) count_this_time, so trusting a larger value here would overflow both stack allocations. + if (count_this_time > total_count - cur_icd_group_count) { + count_this_time = total_count - cur_icd_group_count; + } + for (uint32_t group = 0; group < count_this_time; ++group) { + uint32_t cur_index = group + cur_icd_group_count; + local_phys_dev_groups[cur_index].group_props = tmp_group_props[group]; + // physicalDevices is a fixed VK_MAX_DEVICE_GROUP_SIZE array; don't trust a larger count from the ICD. + if (local_phys_dev_groups[cur_index].group_props.physicalDeviceCount > VK_MAX_DEVICE_GROUP_SIZE) { + local_phys_dev_groups[cur_index].group_props.physicalDeviceCount = VK_MAX_DEVICE_GROUP_SIZE; + } + local_phys_dev_groups[cur_index].this_icd_term = icd_term; } - local_phys_dev_groups[cur_index].this_icd_term = icd_term; } } if (VK_SUCCESS != res) { @@ -8027,9 +8249,11 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups( // Apply the settings file's device_configurations to the groups. If a group // contains an excluded VkPhysicalDevice, drop the whole group. - if (inst->settings.settings_active && inst->settings.device_configurations_active && NULL != inst->phys_devs_term) { + if (inst->settings.settings_active && inst->settings.device_configurations_active && NULL != inst->phys_devs_term && + inst->phys_dev_count_term > 0) { uint32_t visible_count = inst->phys_dev_count_term; - VkPhysicalDevice *visible_phys_devs = loader_stack_alloc(visible_count * sizeof(VkPhysicalDevice)); + visible_phys_devs = (VkPhysicalDevice *)loader_instance_heap_calloc(inst, visible_count * sizeof(VkPhysicalDevice), + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == visible_phys_devs) { res = VK_ERROR_OUT_OF_HOST_MEMORY; goto out; @@ -8219,6 +8443,12 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups( } else { *pPhysicalDeviceGroupCount = total_count; } + + loader_instance_heap_free(inst, local_phys_dev_groups); + loader_instance_heap_free(inst, (void *)phys_dev_array); + loader_instance_heap_free(inst, tmp_group_props); + loader_instance_heap_free(inst, (void *)visible_phys_devs); + return res; } diff --git a/loader/loader.h b/loader/loader.h index cebadfe81..ef529e3ef 100644 --- a/loader/loader.h +++ b/loader/loader.h @@ -190,7 +190,8 @@ VkResult loader_get_icd_loader_instance_extensions(const struct loader_instance struct loader_extension_list *inst_exts); struct loader_icd_term *loader_get_icd_and_device(const void *device, struct loader_device **found_dev); struct loader_instance *loader_get_instance(VkInstance instance); -loader_platform_dl_handle loader_open_layer_file(const struct loader_instance *inst, struct loader_layer_properties *prop); +loader_platform_dl_handle loader_open_layer_file(const struct loader_instance *inst, struct loader_layer_properties *prop, + bool *oom); struct loader_device *loader_create_logical_device(const struct loader_instance *inst, const VkAllocationCallbacks *pAllocator); void loader_add_logical_device(struct loader_icd_term *icd_term, struct loader_device *found_dev); void loader_remove_logical_device(struct loader_icd_term *icd_term, struct loader_device *found_dev, diff --git a/loader/loader_environment.c b/loader/loader_environment.c index d552e63e8..7c63053ae 100644 --- a/loader/loader_environment.c +++ b/loader/loader_environment.c @@ -31,7 +31,6 @@ #include "allocation.h" #include "loader.h" #include "log.h" -#include "stack_allocation.h" #include @@ -112,39 +111,45 @@ bool is_high_integrity() { } char *loader_getenv(const char *name, const struct loader_instance *inst) { - int name_utf16_size = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); - if (name_utf16_size <= 0) { - return NULL; + wchar_t *name_utf16 = NULL; + wchar_t *val = NULL; + char *val_utf8 = NULL; + + bool oom = false; + name_utf16 = loader_convert_char_to_wchar(inst, name, &oom, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (oom) { + goto out; } - wchar_t *name_utf16 = (wchar_t *)loader_stack_alloc(name_utf16_size * sizeof(wchar_t)); - if (MultiByteToWideChar(CP_UTF8, 0, name, -1, name_utf16, name_utf16_size) != name_utf16_size) { - return NULL; + if (NULL == name_utf16) { + goto out; } DWORD val_size = GetEnvironmentVariableW(name_utf16, NULL, 0); // val_size DOES include the null terminator, so for any set variable // will always be at least 1. If it's 0, the variable wasn't set. if (val_size == 0) { - return NULL; + goto out; } - wchar_t *val = (wchar_t *)loader_stack_alloc(val_size * sizeof(wchar_t)); + val = (wchar_t *)loader_instance_heap_calloc(inst, val_size * sizeof(wchar_t), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == val) { + goto out; + } if (GetEnvironmentVariableW(name_utf16, val, val_size) != val_size - 1) { - return NULL; + goto out; } - int val_utf8_size = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, NULL, NULL); - if (val_utf8_size <= 0) { - return NULL; - } - char *val_utf8 = (char *)loader_instance_heap_calloc(inst, val_utf8_size * sizeof(char), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); - if (val_utf8 == NULL) { - return NULL; + val_utf8 = loader_convert_wchar_to_char(inst, val, &oom, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (oom) { + goto out; } - if (WideCharToMultiByte(CP_UTF8, 0, val, -1, val_utf8, val_utf8_size, NULL, NULL) != val_utf8_size) { - loader_instance_heap_free(inst, val_utf8); - return NULL; + if (NULL == val_utf8) { + goto out; } +out: + loader_instance_heap_free(inst, val); + loader_instance_heap_free(inst, name_utf16); + return val_utf8; } @@ -463,49 +468,53 @@ VkResult loader_add_environment_layers(struct loader_instance *inst, const char VkResult res = VK_SUCCESS; const enum layer_type_flags type_flags = VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER; + char *layer_env_name_alloc = NULL; + // If the layer environment variable is present (i.e. VK_INSTANCE_LAYERS), we will always add it to the layer list. if (enabled_layers_env != NULL) { size_t layer_env_len = strlen(enabled_layers_env) + 1; - char *name = loader_stack_alloc(layer_env_len); - if (name != NULL) { - loader_strncpy(name, layer_env_len, enabled_layers_env, layer_env_len); - - loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers \"%s\"", - ENABLED_LAYERS_ENV, name); - - // First look for the old-fashion layers forced on with VK_INSTANCE_LAYERS - while (name && *name) { - char *next = loader_get_next_path(name); - - if (strlen(name) > 0) { - bool found = false; - for (uint32_t i = 0; i < inst->instance_layer_list.count; i++) { - struct loader_layer_properties *source_prop = &inst->instance_layer_list.list[i]; - - if (0 == strcmp(name, source_prop->info.layerName)) { - found = true; - // Only add it if it doesn't already appear in the layer list - if (!loader_find_layer_name_in_list(source_prop->info.layerName, - &inst->expanded_activated_layer_list)) { - if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) { - source_prop->enabled_by_what = ENABLED_BY_WHAT_VK_INSTANCE_LAYERS; - res = loader_add_layer_properties_to_list(inst, source_prop); - if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; - } else { - res = loader_add_meta_layer(inst, filters, source_prop, NULL); - if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; - } - break; + layer_env_name_alloc = loader_instance_heap_calloc(inst, layer_env_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == layer_env_name_alloc) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + char *name = layer_env_name_alloc; + loader_strncpy(name, layer_env_len, enabled_layers_env, layer_env_len); + + loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers \"%s\"", + ENABLED_LAYERS_ENV, name); + + // First look for the old-fashion layers forced on with VK_INSTANCE_LAYERS + while (name && *name) { + char *next = loader_get_next_path(name); + + if (strlen(name) > 0) { + bool found = false; + for (uint32_t i = 0; i < inst->instance_layer_list.count; i++) { + struct loader_layer_properties *source_prop = &inst->instance_layer_list.list[i]; + + if (0 == strcmp(name, source_prop->info.layerName)) { + found = true; + // Only add it if it doesn't already appear in the layer list + if (!loader_find_layer_name_in_list(source_prop->info.layerName, &inst->expanded_activated_layer_list)) { + if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) { + source_prop->enabled_by_what = ENABLED_BY_WHAT_VK_INSTANCE_LAYERS; + res = loader_add_layer_properties_to_list(inst, source_prop); + if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; + } else { + res = loader_add_meta_layer(inst, filters, source_prop, NULL); + if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; } + break; } } - if (!found) { - loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, - "Layer \"%s\" was not found but was requested by env var VK_INSTANCE_LAYERS!", name); - } } - name = next; + if (!found) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, + "Layer \"%s\" was not found but was requested by env var VK_INSTANCE_LAYERS!", name); + } } + name = next; } } @@ -557,17 +566,19 @@ VkResult loader_add_environment_layers(struct loader_instance *inst, const char } out: + loader_instance_heap_free(inst, layer_env_name_alloc); return res; } -void parse_id_filter_environment_var(const struct loader_instance *inst, const char *env_var_name, - struct loader_envvar_id_filter *filter_struct) { +VkResult parse_id_filter_environment_var(const struct loader_instance *inst, const char *env_var_name, + struct loader_envvar_id_filter *filter_struct) { + VkResult res = VK_SUCCESS; memset(filter_struct, 0, sizeof(struct loader_envvar_id_filter)); char *parsing_string = NULL; char *env_var_value = loader_secure_getenv(env_var_name, inst); if (NULL == env_var_value) { - return; + goto out; } const size_t env_var_len = strlen(env_var_value); if (env_var_len == 0) { @@ -575,7 +586,11 @@ void parse_id_filter_environment_var(const struct loader_instance *inst, const c } // Allocate a separate string since scan_for_next_comma modifies the original string uint32_t num_commas = 0; - parsing_string = loader_stack_alloc(env_var_len + 1); + parsing_string = loader_instance_heap_calloc(inst, env_var_len + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == parsing_string) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } for (uint32_t iii = 0; iii < env_var_len; ++iii) { if (env_var_value[iii] == ',') { num_commas++; @@ -609,6 +624,8 @@ void parse_id_filter_environment_var(const struct loader_instance *inst, const c out: loader_free_getenv(env_var_value, inst); + loader_instance_heap_free(inst, parsing_string); + return res; } bool check_id_matches_filter_environment_var(const uint32_t id, const struct loader_envvar_id_filter *filter_struct) { diff --git a/loader/loader_environment.h b/loader/loader_environment.h index d266dfff9..9e8f5ded1 100644 --- a/loader/loader_environment.h +++ b/loader/loader_environment.h @@ -52,7 +52,7 @@ bool check_name_matches_filter_environment_var(const char *name, const struct lo VkResult loader_add_environment_layers(struct loader_instance *inst, const char *enabled_layers_env, const struct loader_envvar_all_filters *filters); -void parse_id_filter_environment_var(const struct loader_instance *inst, const char *env_var_name, - struct loader_envvar_id_filter *filter_struct); +VkResult parse_id_filter_environment_var(const struct loader_instance *inst, const char *env_var_name, + struct loader_envvar_id_filter *filter_struct); bool check_id_matches_filter_environment_var(const uint32_t id, const struct loader_envvar_id_filter *filter_struct); void free_id_filters(const struct loader_instance *inst, struct loader_envvar_id_filter *filter_struct); diff --git a/loader/loader_json.c b/loader/loader_json.c index b9ccfedd9..67180804e 100644 --- a/loader/loader_json.c +++ b/loader/loader_json.c @@ -50,26 +50,40 @@ static VkResult loader_read_entire_file(const struct loader_instance *inst, cons DWORD len = 0, read_len = 0; VkResult res = VK_SUCCESS; BOOL read_ok = false; + wchar_t *filename_utf16 = NULL; + wchar_t *prefixed_utf16 = NULL; - int filename_utf16_size = MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); - if (filename_utf16_size > 0) { - wchar_t *filename_utf16 = (wchar_t *)loader_stack_alloc(filename_utf16_size * sizeof(wchar_t)); - if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filename_utf16, filename_utf16_size) == filename_utf16_size) { - file_handle = - CreateFileW(filename_utf16, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - // A path at or beyond MAX_PATH won't open unless we opt into long paths with the "\\?\" prefix, so retry with it. - if (INVALID_HANDLE_VALUE == file_handle && filename_utf16_size >= MAX_PATH) { - int prefixed_utf16_size = filename_utf16_size + 4; // room for the leading "\\?\" - wchar_t *prefixed_utf16 = (wchar_t *)loader_stack_alloc(prefixed_utf16_size * sizeof(wchar_t)); - prefixed_utf16[0] = L'\\'; - prefixed_utf16[1] = L'\\'; - prefixed_utf16[2] = L'?'; - prefixed_utf16[3] = L'\\'; - memcpy(prefixed_utf16 + 4, filename_utf16, filename_utf16_size * sizeof(wchar_t)); - file_handle = - CreateFileW(prefixed_utf16, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - } + bool oom = false; + filename_utf16 = loader_convert_char_to_wchar(inst, filename, &oom, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (oom) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to allocate memory to read JSON file %s", filename); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + if (NULL == filename_utf16) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to convert JSON file %s to a wchar_t string", + filename); + res = VK_ERROR_INITIALIZATION_FAILED; + goto out; + } + size_t filename_utf16_size = wcslen(filename_utf16) + 1; + + file_handle = CreateFileW(filename_utf16, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + // A path at or beyond MAX_PATH won't open unless we opt into long paths with the "\\?\" prefix, so retry with it. + if (INVALID_HANDLE_VALUE == file_handle && filename_utf16_size >= MAX_PATH) { + size_t prefixed_utf16_size = filename_utf16_size + 4; // room for the leading "\\?\" + prefixed_utf16 = + (wchar_t *)loader_instance_heap_calloc(inst, prefixed_utf16_size * sizeof(wchar_t), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == prefixed_utf16) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } + prefixed_utf16[0] = L'\\'; + prefixed_utf16[1] = L'\\'; + prefixed_utf16[2] = L'?'; + prefixed_utf16[3] = L'\\'; + memcpy(prefixed_utf16 + 4, filename_utf16, filename_utf16_size * sizeof(wchar_t)); + file_handle = CreateFileW(prefixed_utf16, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } if (INVALID_HANDLE_VALUE == file_handle) { loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to open JSON file %s", filename); @@ -101,6 +115,8 @@ static VkResult loader_read_entire_file(const struct loader_instance *inst, cons if (INVALID_HANDLE_VALUE != file_handle) { CloseHandle(file_handle); } + loader_instance_heap_free(inst, prefixed_utf16); + loader_instance_heap_free(inst, filename_utf16); return res; } #elif COMMON_UNIX_PLATFORMS diff --git a/loader/loader_linux.c b/loader/loader_linux.c index 2913a7a46..8b3e3cf3b 100644 --- a/loader/loader_linux.c +++ b/loader/loader_linux.c @@ -33,7 +33,6 @@ #include "loader_environment.h" #include "loader.h" #include "log.h" -#include "stack_allocation.h" // Determine a priority based on device type with the higher value being higher priority. uint32_t determine_priority_type_value(VkPhysicalDeviceType type) { @@ -298,13 +297,14 @@ VkResult linux_read_sorted_physical_devices(struct loader_instance *inst, uint32 NULL); if (ext_count > 0) { if (NULL == ext_props || ext_props_alloc_count < ext_count) { - ext_props = loader_instance_heap_realloc(inst, ext_props, ext_props_alloc_count, - sizeof(VkExtensionProperties) * ext_count, - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); - if (NULL == ext_props) { + VkExtensionProperties *new_ext_props = loader_instance_heap_realloc( + inst, ext_props, ext_props_alloc_count, sizeof(VkExtensionProperties) * ext_count, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == new_ext_props) { res = VK_ERROR_OUT_OF_HOST_MEMORY; goto out; } + ext_props = new_ext_props; ext_props_alloc_count = ext_count; } uint32_t allocated_count = ext_count; @@ -412,13 +412,14 @@ VkResult linux_sort_physical_device_groups(struct loader_instance *inst, uint32_ sorted_group_term[group].internal_device_info[gpu].physical_device, NULL, &ext_count, NULL); if (ext_count > 0) { if (NULL == ext_props || ext_props_alloc_count < ext_count) { - ext_props = loader_instance_heap_realloc(inst, ext_props, ext_props_alloc_count, - sizeof(VkExtensionProperties) * ext_count, - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); - if (NULL == ext_props) { + VkExtensionProperties *new_ext_props = loader_instance_heap_realloc( + inst, ext_props, ext_props_alloc_count, sizeof(VkExtensionProperties) * ext_count, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == new_ext_props) { res = VK_ERROR_OUT_OF_HOST_MEMORY; goto out; } + ext_props = new_ext_props; ext_props_alloc_count = ext_count; } uint32_t allocated_count = ext_count; diff --git a/loader/loader_windows.c b/loader/loader_windows.c index 392c3ef59..2929d9c6e 100644 --- a/loader/loader_windows.c +++ b/loader/loader_windows.c @@ -1020,7 +1020,8 @@ VkResult windows_sort_physical_device_groups(struct loader_instance *inst, const return VK_SUCCESS; } -char *windows_get_app_package_manifest_path(const struct loader_instance *inst) { +char *windows_get_app_package_manifest_path(const struct loader_instance *inst, bool *oom) { + *oom = false; // These functions are only available on Windows 8 and above, load them dynamically for compatibility with Windows 7 typedef LONG(WINAPI * PFN_GetPackagesByPackageFamily)(PCWSTR, UINT32 *, PWSTR *, UINT32 *, WCHAR *); PFN_GetPackagesByPackageFamily fpGetPackagesByPackageFamily = @@ -1050,6 +1051,7 @@ char *windows_get_app_package_manifest_path(const struct loader_instance *inst) WCHAR *buffer = loader_instance_heap_calloc(inst, sizeof(WCHAR) * bufferLength, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); PWSTR *packages = loader_instance_heap_calloc(inst, sizeof(PWSTR) * numPackages, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (!buffer || !packages) { + *oom = true; loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "windows_get_app_package_manifest_path: Failed to allocate memory for package names"); goto cleanup; @@ -1080,6 +1082,7 @@ char *windows_get_app_package_manifest_path(const struct loader_instance *inst) ret = loader_instance_heap_calloc(inst, narrowPathLength, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (!ret) { + *oom = true; loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "windows_get_app_package_manifest_path: Failed to allocate path"); goto cleanup; } @@ -1121,7 +1124,12 @@ VkResult get_settings_path_if_exists_in_registry_key(const struct loader_instanc if (strcmp(VK_LOADER_SETTINGS_FILENAME, &(name[start_of_path_filename])) == 0) { // Make sure the path exists first - if (!loader_platform_file_exists(name)) { + bool oom = false; + bool file_exists = loader_platform_file_exists(inst, name, &oom); + if (oom) { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + if (!file_exists) { loader_log( inst, VULKAN_LOADER_DEBUG_BIT, 0, "Registry contained entry to vk_loader_settings.json but the corresponding file does not exist, ignoring"); diff --git a/loader/loader_windows.h b/loader/loader_windows.h index 1aed87aef..475802d1c 100644 --- a/loader/loader_windows.h +++ b/loader/loader_windows.h @@ -113,7 +113,7 @@ VkLoaderFeatureFlags windows_initialize_dxgi(void); // Retrieve a path to an installed app package that contains Vulkan manifests. // When done using the returned string, the caller should free the pointer. -char *windows_get_app_package_manifest_path(const struct loader_instance *inst); +char *windows_get_app_package_manifest_path(const struct loader_instance *inst, bool *oom); // Gets the path to the loader settings file, if it exists. If it doesn't exists, writes NULL to out_path. // The path is located through the registry as an entry in HKEY_CURRENT_USER/SOFTWARE/Khronos/Vulkan/LoaderSettings diff --git a/loader/settings.c b/loader/settings.c index 3d2e5b3af..7769c4ceb 100644 --- a/loader/settings.c +++ b/loader/settings.c @@ -32,7 +32,6 @@ #include "loader_windows.h" #endif #include "log.h" -#include "stack_allocation.h" #include "vk_loader_platform.h" loader_platform_thread_mutex global_loader_settings_lock; @@ -469,7 +468,14 @@ TEST_FUNCTION_EXPORT VkResult check_if_settings_path_exists(const struct loader_ loader_strncpy(*settings_file_path, path_len, base + start, segment_len); loader_strncat(*settings_file_path, path_len, suffix, suffix_len); - if (loader_platform_file_exists(*settings_file_path)) { + bool oom = false; + bool file_exists = loader_platform_file_exists(inst, *settings_file_path, &oom); + if (oom) { + loader_instance_heap_free(inst, *settings_file_path); + *settings_file_path = NULL; + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + if (file_exists) { return VK_SUCCESS; } loader_instance_heap_free(inst, *settings_file_path); @@ -689,6 +695,7 @@ VkResult get_loader_settings(const struct loader_instance* inst, loader_settings cJSON* json = NULL; char* file_format_version_string = NULL; char* settings_file_path = NULL; + char* current_process_path = NULL; #if defined(WIN32) res = windows_get_loader_settings_file_path(inst, &settings_file_path); if (res != VK_SUCCESS) { @@ -749,9 +756,13 @@ VkResult get_loader_settings(const struct loader_instance* inst, loader_settings // Corresponds to the settings object which has a matching app key cJSON* settings_to_use = NULL; - char current_process_path[1024]; - bool valid_exe_path = NULL != loader_platform_executable_path(current_process_path, 1024); - + bool oom = false; + current_process_path = loader_platform_executable_path(inst, &oom); + if (oom) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + bool valid_exe_path = NULL != current_process_path; cJSON* settings_object_iter = NULL; cJSON_ArrayForEach(settings_object_iter, &settings_iter_parent) { if (settings_object_iter->type != cJSON_Object) { @@ -882,6 +893,8 @@ VkResult get_loader_settings(const struct loader_instance* inst, loader_settings loader_instance_heap_free(inst, settings_file_path); loader_instance_heap_free(inst, file_format_version_string); + + loader_instance_heap_free(inst, current_process_path); return res; } @@ -1177,8 +1190,12 @@ VkResult enable_correct_layers_from_settings(struct loader_instance* inst, const char* vk_instance_layers_env_copy = NULL; if (vk_instance_layers_env != NULL) { vk_instance_layers_env_len = strlen(vk_instance_layers_env) + 1; - vk_instance_layers_env_copy = loader_stack_alloc(vk_instance_layers_env_len); - memset(vk_instance_layers_env_copy, 0, vk_instance_layers_env_len); + vk_instance_layers_env_copy = + loader_instance_heap_calloc(inst, vk_instance_layers_env_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == vk_instance_layers_env_copy) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers: %s", ENABLED_LAYERS_ENV, vk_instance_layers_env); @@ -1273,6 +1290,8 @@ VkResult enable_correct_layers_from_settings(struct loader_instance* inst, const } } out: + loader_instance_heap_free(inst, vk_instance_layers_env_copy); + if (vk_instance_layers_env != NULL) { loader_free_getenv(vk_instance_layers_env, inst); } diff --git a/loader/stack_allocation.h b/loader/stack_allocation.h deleted file mode 100644 index baf33667c..000000000 --- a/loader/stack_allocation.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Copyright (c) 2014-2022 The Khronos Group Inc. - * Copyright (c) 2014-2022 Valve Corporation - * Copyright (c) 2014-2022 LunarG, Inc. - * Copyright (C) 2015 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Author: Jon Ashburn - * Author: Courtney Goeltzenleuchter - * Author: Chia-I Wu - * Author: Chia-I Wu - * Author: Mark Lobodzinski - * Author: Lenny Komow - * Author: Charles Giessen - */ - -#pragma once - -#include "vk_loader_platform.h" - -#if defined(_WIN32) -#include -#elif defined(HAVE_ALLOCA_H) -#include -#else -#include -#endif - -#if COMMON_UNIX_PLATFORMS -#define loader_stack_alloc(size) alloca(size) -#elif defined(_WIN32) -#define loader_stack_alloc(size) _alloca(size) -#else -#warning "alloca not available on this platform!" -#endif // defined(_WIN32) diff --git a/loader/terminator.c b/loader/terminator.c index 9524bb6e9..c1170dac0 100644 --- a/loader/terminator.c +++ b/loader/terminator.c @@ -34,7 +34,7 @@ #include "loader_common.h" #include "loader.h" #include "log.h" -#include "stack_allocation.h" +#include "allocation.h" // Terminators for 1.0 functions @@ -362,7 +362,8 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties2(Vk } else { // Allocate a temporary array for the output of the old function uint32_t allocated_count = *pQueueFamilyPropertyCount; - VkQueueFamilyProperties *properties = loader_stack_alloc(allocated_count * sizeof(VkQueueFamilyProperties)); + VkQueueFamilyProperties *properties = loader_instance_heap_calloc( + inst, allocated_count * sizeof(VkQueueFamilyProperties), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (properties == NULL) { *pQueueFamilyPropertyCount = 0; loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0, @@ -385,6 +386,7 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties2(Vk i); } } + loader_instance_heap_free(inst, properties); } } } @@ -468,7 +470,8 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperti } else { // Allocate a temporary array for the output of the old function uint32_t allocated_count = *pPropertyCount; - VkSparseImageFormatProperties *properties = loader_stack_alloc(allocated_count * sizeof(VkSparseImageFormatProperties)); + VkSparseImageFormatProperties *properties = loader_instance_heap_calloc( + inst, allocated_count * sizeof(VkSparseImageFormatProperties), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (properties == NULL) { *pPropertyCount = 0; loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0, @@ -492,6 +495,8 @@ VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperti i); } } + + loader_instance_heap_free(inst, properties); } } } diff --git a/loader/trampoline.c b/loader/trampoline.c index 8c1d6be62..7f942934c 100644 --- a/loader/trampoline.c +++ b/loader/trampoline.c @@ -36,10 +36,8 @@ #include "loader_environment.h" #include "log.h" #include "settings.h" -#include "stack_allocation.h" #include "vk_loader_extensions.h" #include "vk_loader_platform.h" -#include "wsi.h" // Trampoline entrypoints are in this file for core Vulkan commands @@ -201,8 +199,12 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionPropert if (NULL == layers.list[i].pre_instance_functions.enumerate_instance_extension_properties) { continue; } - - loader_open_layer_file(NULL, &layers.list[i]); + bool oom = false; + loader_open_layer_file(NULL, &layers.list[i], &oom); + if (oom) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } if (layers.list[i].lib_handle == NULL) { continue; } @@ -237,6 +239,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionPropert res = chain_head->pfnNextLayer(chain_head->pNextLink, pLayerName, pPropertyCount, pProperties); } +out: // Free up the layers loader_delete_layer_list_and_properties(NULL, &layers); @@ -292,7 +295,12 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( continue; } - loader_open_layer_file(NULL, &layers.list[i]); + bool oom = false; + loader_open_layer_file(NULL, &layers.list[i], &oom); + if (oom) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } if (layers.list[i].lib_handle == NULL) { continue; } @@ -327,6 +335,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( res = chain_head->pfnNextLayer(chain_head->pNextLink, pPropertyCount, pProperties); } +out: // Free up the layers loader_delete_layer_list_and_properties(NULL, &layers); @@ -389,7 +398,12 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion(uint32_t continue; } - loader_open_layer_file(NULL, &layers.list[i]); + bool oom = false; + loader_open_layer_file(NULL, &layers.list[i], &oom); + if (oom) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } if (layers.list[i].lib_handle == NULL) { continue; } @@ -423,6 +437,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion(uint32_t res = chain_head->pfnNextLayer(chain_head->pNextLink, pApiVersion); } +out: // Free up the layers loader_delete_layer_list_and_properties(NULL, &layers); @@ -872,6 +887,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstan VkPhysicalDevice *pPhysicalDevices) { VkResult res = VK_SUCCESS; struct loader_instance *inst; + VkPhysicalDevice *physical_devices = NULL; struct loader_envvar_id_filter device_id_filter = {0, NULL}; struct loader_envvar_id_filter vendor_id_filter = {0, NULL}; @@ -894,9 +910,12 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstan goto out; } - parse_id_filter_environment_var(inst, VK_DEVICE_ID_FILTER_ENV_VAR, &device_id_filter); - parse_id_filter_environment_var(inst, VK_VENDOR_ID_FILTER_ENV_VAR, &vendor_id_filter); - parse_id_filter_environment_var(inst, VK_DRIVER_ID_FILTER_ENV_VAR, &driver_id_filter); + res = parse_id_filter_environment_var(inst, VK_DEVICE_ID_FILTER_ENV_VAR, &device_id_filter); + if (VK_ERROR_OUT_OF_HOST_MEMORY == res) goto out; + res = parse_id_filter_environment_var(inst, VK_VENDOR_ID_FILTER_ENV_VAR, &vendor_id_filter); + if (VK_ERROR_OUT_OF_HOST_MEMORY == res) goto out; + res = parse_id_filter_environment_var(inst, VK_DRIVER_ID_FILTER_ENV_VAR, &driver_id_filter); + if (VK_ERROR_OUT_OF_HOST_MEMORY == res) goto out; // Call down the chain to get the physical device info if ((0 == device_id_filter.count) && (0 == vendor_id_filter.count) && (0 == driver_id_filter.count)) { @@ -904,11 +923,18 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstan } else { uint32_t physical_device_count = 0; res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(inst->instance, &physical_device_count, NULL); - if (res != VK_SUCCESS) { + if (res != VK_SUCCESS || physical_device_count == 0) { + *pPhysicalDeviceCount = 0; + goto out; + } + + physical_devices = (VkPhysicalDevice *)loader_instance_heap_calloc(inst, physical_device_count * sizeof(VkPhysicalDevice), + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == physical_devices) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; goto out; } - VkPhysicalDevice *physical_devices = loader_stack_alloc(physical_device_count * sizeof(VkPhysicalDevice)); res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(inst->instance, &physical_device_count, physical_devices); if (res != VK_SUCCESS) { goto out; @@ -931,6 +957,8 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstan } out: + loader_instance_heap_free(inst, (void *)physical_devices); + free_id_filters(inst, &device_id_filter); free_id_filters(inst, &vendor_id_filter); free_id_filters(inst, &driver_id_filter); @@ -2642,6 +2670,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups( VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) { VkResult res = VK_SUCCESS; struct loader_instance *inst = NULL; + VkPhysicalDeviceGroupProperties *physical_device_group_properties = NULL; struct loader_envvar_id_filter device_id_filter = {0, NULL}; struct loader_envvar_id_filter vendor_id_filter = {0, NULL}; @@ -2664,9 +2693,12 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups( goto out; } - parse_id_filter_environment_var(inst, VK_DEVICE_ID_FILTER_ENV_VAR, &device_id_filter); - parse_id_filter_environment_var(inst, VK_VENDOR_ID_FILTER_ENV_VAR, &vendor_id_filter); - parse_id_filter_environment_var(inst, VK_DRIVER_ID_FILTER_ENV_VAR, &driver_id_filter); + res = parse_id_filter_environment_var(inst, VK_DEVICE_ID_FILTER_ENV_VAR, &device_id_filter); + if (VK_ERROR_OUT_OF_HOST_MEMORY == res) goto out; + res = parse_id_filter_environment_var(inst, VK_VENDOR_ID_FILTER_ENV_VAR, &vendor_id_filter); + if (VK_ERROR_OUT_OF_HOST_MEMORY == res) goto out; + res = parse_id_filter_environment_var(inst, VK_DRIVER_ID_FILTER_ENV_VAR, &driver_id_filter); + if (VK_ERROR_OUT_OF_HOST_MEMORY == res) goto out; // Call down the chain to get the physical device group info. if ((0 == device_id_filter.count) && (0 == vendor_id_filter.count) && (0 == driver_id_filter.count)) { @@ -2675,13 +2707,21 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups( } else { uint32_t physical_device_group_count = 0; res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroups(inst->instance, &physical_device_group_count, NULL); - if (res != VK_SUCCESS) { + if (res != VK_SUCCESS || physical_device_group_count == 0) { + *pPhysicalDeviceGroupCount = 0; goto out; } - VkPhysicalDeviceGroupProperties *physical_device_group_properties = - loader_stack_alloc(physical_device_group_count * sizeof(VkPhysicalDeviceGroupProperties)); - memset(physical_device_group_properties, 0, physical_device_group_count * sizeof(VkPhysicalDeviceGroupProperties)); + physical_device_group_properties = loader_instance_heap_calloc( + inst, physical_device_group_count * sizeof(VkPhysicalDeviceGroupProperties), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == physical_device_group_properties) { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + + for (uint32_t i = 0; i < physical_device_group_count; i++) { + physical_device_group_properties[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES; + } res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroups(inst->instance, &physical_device_group_count, physical_device_group_properties); @@ -2703,6 +2743,8 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups( } out: + loader_instance_heap_free(inst, physical_device_group_properties); + free_id_filters(inst, &device_id_filter); free_id_filters(inst, &vendor_id_filter); free_id_filters(inst, &driver_id_filter); diff --git a/loader/vk_loader_platform.c b/loader/vk_loader_platform.c index c18933446..5ae5ff66f 100644 --- a/loader/vk_loader_platform.c +++ b/loader/vk_loader_platform.c @@ -26,18 +26,18 @@ */ #include "vk_loader_platform.h" -#if defined(_WIN32) -#include "stack_allocation.h" -#endif +#include "allocation.h" bool loader_disable_dynamic_library_unloading; #if COMMON_UNIX_PLATFORMS // File IO -bool loader_platform_file_exists(const char *path) { - if (access(path, F_OK)) return false; - return true; +// NOLINTNEXTLINE(readability-non-const-parameter) - oom is only used on Windows but clang-tidy doesn't see that +bool loader_platform_file_exists(const struct loader_instance *inst, const char *path, bool *oom) { + (void)inst; + (void)oom; + return access(path, F_OK) == 0; } // Returns true if the given string appears to be a relative or absolute // path, as opposed to a bare filename. @@ -50,15 +50,23 @@ bool loader_platform_is_path_absolute(const char *path) { char *loader_platform_dirname(char *path) { return dirname(path); } // loader_platform_executable_path finds application path + name. -// Path cannot be longer than 1024, returns NULL if it is greater than that. #if defined(__linux__) || defined(__GNU__) || defined(__CYGWIN__) -char *loader_platform_executable_path(char *buffer, size_t size) { +char *loader_platform_executable_path(const struct loader_instance *inst, bool *oom) { + size_t size = 1024; + char *buffer = loader_instance_heap_calloc(inst, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == buffer) { + *oom = true; + return NULL; + } ssize_t count = readlink("/proc/self/exe", buffer, size); - if (count == -1) return NULL; - if (count == 0) return NULL; // readlink does not append a null terminator and returns up to size bytes, so a target of size or more // would leave no room for the terminator and buffer[count] would write past the end. - if ((size_t)count >= size) return NULL; + if (count <= 0 || (size_t)count >= size) { + loader_instance_heap_free(inst, buffer); + return NULL; + } + // We make sure count is within bounds of the array, but clang-tidy doesn't see it + // NOLINTNEXTLINE(clang-analyzer-security.ArrayBound) buffer[count] = '\0'; return buffer; } @@ -66,22 +74,31 @@ char *loader_platform_executable_path(char *buffer, size_t size) { #include // TARGET_OS_IPHONE isn't just iOS it's also iOS/tvOS/watchOS. See TargetConditionals.h documentation. #if TARGET_OS_IPHONE -char *loader_platform_executable_path(char *buffer, size_t size) { - (void)size; +char *loader_platform_executable_path(const struct loader_instance *inst, bool *oom) { + size_t size = 1; + char *buffer = loader_instance_heap_calloc(inst, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == buffer) { + // Return a single character string that only contains the null terminator to preserve existing behavior + *oom = true; + return NULL; + } buffer[0] = '\0'; return buffer; } #endif #if TARGET_OS_OSX #include -char *loader_platform_executable_path(char *buffer, size_t size) { - // proc_pidpath takes a uint32_t for the buffer size - if (size > UINT32_MAX) { +char *loader_platform_executable_path(const struct loader_instance *inst, bool *oom) { + size_t size = PROC_PIDPATHINFO_MAXSIZE; + char *buffer = loader_instance_heap_calloc(inst, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == buffer) { + *oom = true; return NULL; } pid_t pid = getpid(); int ret = proc_pidpath(pid, buffer, (uint32_t)size); if (ret <= 0) { + loader_instance_heap_free(inst, buffer); return NULL; } buffer[ret] = '\0'; @@ -90,7 +107,13 @@ char *loader_platform_executable_path(char *buffer, size_t size) { #endif #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) #include -char *loader_platform_executable_path(char *buffer, size_t size) { +char *loader_platform_executable_path(const struct loader_instance *inst, bool *oom) { + size_t size = 1024; + char *buffer = loader_instance_heap_calloc(inst, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == buffer) { + *oom = true; + return NULL; + } int mib[] = { CTL_KERN, #if defined(__NetBSD__) @@ -104,15 +127,16 @@ char *loader_platform_executable_path(char *buffer, size_t size) { #endif }; if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buffer, &size, NULL, 0) < 0) { + loader_instance_heap_free(inst, buffer); return NULL; } return buffer; } #elif defined(__Fuchsia__) || defined(__OpenBSD__) -char *loader_platform_executable_path(char *buffer, size_t size) { - (void)buffer; - (void)size; +char *loader_platform_executable_path(const struct loader_instance *inst, bool *oom) { + (void)inst; + (void)oom; return NULL; } #elif defined(__QNX__) @@ -120,16 +144,24 @@ char *loader_platform_executable_path(char *buffer, size_t size) { #include #include -char *loader_platform_executable_path(char *buffer, size_t size) { - int fd = open("/proc/self/exefile", O_RDONLY); - size_t rdsize; +char *loader_platform_executable_path(const struct loader_instance *inst, bool *oom) { + size_t size = 1024; + char *buffer = loader_instance_heap_calloc(inst, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == buffer) { + *oom = true; + return NULL; + } + int fd = open("/proc/self/exefile", O_RDONLY); if (fd == -1) { + loader_instance_heap_free(inst, buffer); return NULL; } - rdsize = read(fd, buffer, size); - if (rdsize == size) { + ssize_t rdsize = read(fd, buffer, size); + if (rdsize < 0 || (size_t)rdsize == size) { + loader_instance_heap_free(inst, buffer); + close(fd); return NULL; } buffer[rdsize] = 0x00; @@ -158,11 +190,18 @@ char *loader_platform_executable_path(char *buffer, size_t size) { loader_platform_dl_handle loader_platform_open_driver(const char *libPath) { return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, true); } -loader_platform_dl_handle loader_platform_open_library(const char *libPath) { +loader_platform_dl_handle loader_platform_open_library(const struct loader_instance *inst, const char *libPath, bool *oom) { + (void)inst; + (void)oom; return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, false); } #else -loader_platform_dl_handle loader_platform_open_library(const char *libPath) { return dlopen(libPath, LOADER_DLOPEN_MODE); } +// NOLINTNEXTLINE(readability-non-const-parameter) - oom is only used on Windows but clang-tidy doesn't see that +loader_platform_dl_handle loader_platform_open_library(const struct loader_instance *inst, const char *libPath, bool *oom) { + (void)inst; + (void)oom; + return dlopen(libPath, LOADER_DLOPEN_MODE); +} #endif const char *loader_platform_open_library_error(const char *libPath) { @@ -217,6 +256,48 @@ char *loader_strncpy(char *dest, size_t dest_sz, const char *src, size_t count) #elif defined(_WIN32) +char *loader_convert_wchar_to_char(const struct loader_instance *inst, const wchar_t *str_utf16, bool *oom, uint32_t scope) { + *oom = false; + int str_utf8_size = WideCharToMultiByte(CP_UTF8, 0, str_utf16, -1, NULL, 0, NULL, NULL); + if (str_utf8_size <= 0) { + return NULL; + } + + char *str_utf8 = (char *)loader_instance_heap_calloc(inst, str_utf8_size, (VkSystemAllocationScope)scope); + if (NULL == str_utf8) { + *oom = true; + return NULL; + } + + if (WideCharToMultiByte(CP_UTF8, 0, str_utf16, -1, str_utf8, str_utf8_size, NULL, NULL) != str_utf8_size) { + loader_instance_heap_free(inst, str_utf8); + return NULL; + } + assert((size_t)str_utf8_size == strlen(str_utf8) + 1); + + return str_utf8; +} + +wchar_t *loader_convert_char_to_wchar(const struct loader_instance *inst, const char *str_utf8, bool *oom, uint32_t scope) { + *oom = false; + int str_utf16_size = MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, NULL, 0); + if (str_utf16_size <= 0) { + return NULL; + } + wchar_t *str_utf16 = + (wchar_t *)loader_instance_heap_calloc(inst, str_utf16_size * sizeof(wchar_t), (VkSystemAllocationScope)scope); + if (NULL == str_utf16) { + *oom = true; + return NULL; + } + if (MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_utf16, str_utf16_size) != str_utf16_size) { + loader_instance_heap_free(inst, str_utf16); + return NULL; + } + assert((size_t)str_utf16_size == wcslen(str_utf16) + 1); + return str_utf16; +} + // Get the key for the plug n play driver registry // The string returned by this function should NOT be freed const char *LoaderPnpDriverRegistry(void) { @@ -257,19 +338,14 @@ const wchar_t *LoaderPnpILayerRegistryWide(void) { } // File IO -bool loader_platform_file_exists(const char *path) { - int path_utf16_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); - if (path_utf16_size <= 0) { - return false; - } - wchar_t *path_utf16 = (wchar_t *)loader_stack_alloc(path_utf16_size * sizeof(wchar_t)); - if (MultiByteToWideChar(CP_UTF8, 0, path, -1, path_utf16, path_utf16_size) != path_utf16_size) { +bool loader_platform_file_exists(const struct loader_instance *inst, const char *path, bool *oom) { + wchar_t *path_utf16 = loader_convert_char_to_wchar(inst, path, oom, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (*oom || NULL == path_utf16) { return false; } - if (_waccess(path_utf16, 0) == -1) - return false; - else - return true; + bool ret = _waccess(path_utf16, 0) != -1; // -1 means the file doesn't exist + loader_instance_heap_free(inst, path_utf16); + return ret; } // Returns true if the given string appears to be a relative or absolute @@ -303,41 +379,48 @@ char *loader_platform_dirname(char *path) { return path; } -char *loader_platform_executable_path(char *buffer, size_t size) { - wchar_t *buffer_utf16 = (wchar_t *)loader_stack_alloc(size * sizeof(wchar_t)); - DWORD ret = GetModuleFileNameW(NULL, buffer_utf16, (DWORD)size); +char *loader_platform_executable_path(const struct loader_instance *inst, bool *oom) { + char *buffer = NULL; + size_t size = 1024; + wchar_t *str_utf16 = (wchar_t *)loader_instance_heap_calloc(inst, size * sizeof(wchar_t), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == str_utf16) { + *oom = true; + goto out; + } + DWORD ret = GetModuleFileNameW(NULL, str_utf16, (DWORD)size); if (ret == 0) { - return NULL; + goto out; } if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - return NULL; + goto out; } - int buffer_utf8_size = WideCharToMultiByte(CP_UTF8, 0, buffer_utf16, -1, NULL, 0, NULL, NULL); - if (buffer_utf8_size <= 0 || (size_t)buffer_utf8_size > size) { - return NULL; - } - if (WideCharToMultiByte(CP_UTF8, 0, buffer_utf16, -1, buffer, buffer_utf8_size, NULL, NULL) != buffer_utf8_size) { - return NULL; + buffer = loader_convert_wchar_to_char(inst, str_utf16, oom, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (*oom || NULL == buffer) { + goto out; } +out: + loader_instance_heap_free(inst, str_utf16); return buffer; } // Dynamic Loading: -loader_platform_dl_handle loader_platform_open_library(const char *lib_path) { - int lib_path_utf16_size = MultiByteToWideChar(CP_UTF8, 0, lib_path, -1, NULL, 0); - if (lib_path_utf16_size <= 0) { - return NULL; - } - wchar_t *lib_path_utf16 = (wchar_t *)loader_stack_alloc(lib_path_utf16_size * sizeof(wchar_t)); - if (MultiByteToWideChar(CP_UTF8, 0, lib_path, -1, lib_path_utf16, lib_path_utf16_size) != lib_path_utf16_size) { +loader_platform_dl_handle loader_platform_open_library(const struct loader_instance *inst, const char *lib_path, bool *oom) { + loader_platform_dl_handle lib_handle = NULL; + wchar_t *lib_path_utf16 = loader_convert_char_to_wchar(inst, lib_path, oom, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (*oom || NULL == lib_path_utf16) { return NULL; } + // Try loading the library the original way first. - loader_platform_dl_handle lib_handle = LoadLibraryW(lib_path_utf16); + lib_handle = LoadLibraryW(lib_path_utf16); if (lib_handle == NULL && GetLastError() == ERROR_MOD_NOT_FOUND) { // If that failed, then try loading it with broader search folders. lib_handle = LoadLibraryExW(lib_path_utf16, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); } + // Save the error so we don't lose it when we free the temporary string + DWORD last_error = GetLastError(); + loader_instance_heap_free(inst, lib_path_utf16); + SetLastError(last_error); return lib_handle; } const char *loader_platform_open_library_error(const char *libPath) { diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h index eda7259c6..324e956a2 100644 --- a/loader/vk_loader_platform.h +++ b/loader/vk_loader_platform.h @@ -282,21 +282,24 @@ static inline void loader_platform_thread_win32_once_fn(INIT_ONCE *ctl, PINIT_ON #endif +struct loader_instance; + // File IO -bool loader_platform_file_exists(const char *path); +bool loader_platform_file_exists(const struct loader_instance *inst, const char *path, bool *oom); // Returns true if the given string appears to be a relative or absolute // path, as opposed to a bare filename. bool loader_platform_is_path_absolute(const char *path); // NOLINTNEXTLINE(concurrency-mt-unsafe) - no portable reentrant dirname; the returned buffer is copied by callers immediately char *loader_platform_dirname(char *path); // loader_platform_executable_path finds application path + name. -// Path cannot be longer than 1024, returns NULL if it is greater than that. -char *loader_platform_executable_path(char *buffer, size_t size); +// Allocates memory to store the path and returns it - caller is responsible for freeing +// Sets oom to true if allocation failed. If it didn't fail allocating but didn't succeed getting the exe path, it returns NULL +char *loader_platform_executable_path(const struct loader_instance *inst, bool *oom); #if defined(__Fuchsia__) loader_platform_dl_handle loader_platform_open_driver(const char *libPath); #endif -loader_platform_dl_handle loader_platform_open_library(const char *libPath); +loader_platform_dl_handle loader_platform_open_library(const struct loader_instance *inst, const char *libPath, bool *oom); const char *loader_platform_open_library_error(const char *libPath); void loader_platform_close_library(loader_platform_dl_handle library); @@ -315,6 +318,17 @@ char *loader_strncat(char *dest, size_t dest_sz, const char *src, size_t count); char *loader_strncpy(char *dest, size_t dest_sz, const char *src, size_t count); #if defined(_WIN32) + +// Converts a wchar_t string to multi byte character string (utf-8) +// oom is set to true if allocation failed +// scope must be a valid VkSystemAllocationScope enum value - uint32_t is used to avoid needing to include vulkan.h +char *loader_convert_wchar_to_char(const struct loader_instance *inst, const wchar_t *str_utf16, bool *oom, uint32_t scope); + +// Converts a multi byte character string (utf-8) string to wchar_t string +// oom is set to true if allocation failed +// scope must be a valid VkSystemAllocationScope enum value - uint32_t is used to avoid needing to include vulkan.h +wchar_t *loader_convert_char_to_wchar(const struct loader_instance *inst, const char *str_utf8, bool *oom, uint32_t scope); + // Get the key for the plug n play driver registry // The string returned by this function should NOT be freed const char *LoaderPnpDriverRegistry(void); diff --git a/loader/wsi.c b/loader/wsi.c index 930bcfdfa..5fcc50b01 100644 --- a/loader/wsi.c +++ b/loader/wsi.c @@ -31,7 +31,6 @@ #include "allocation.h" #include "loader.h" #include "log.h" -#include "stack_allocation.h" #include "vk_loader_platform.h" #include "wsi.h" @@ -2258,20 +2257,26 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateSharedSwapchainsKHR(VkDevice dev "VK_KHR_display_swapchain extension enabled?"); return VK_SUCCESS; } - - VkSwapchainCreateInfoKHR *pCreateCopy = loader_stack_alloc(sizeof(VkSwapchainCreateInfoKHR) * swapchainCount); + VkResult res = VK_SUCCESS; + VkSwapchainCreateInfoKHR *pCreateCopy = loader_calloc_with_instance_fallback( + pAllocator, icd_term->this_instance, sizeof(VkSwapchainCreateInfoKHR) * swapchainCount, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (NULL == pCreateCopy) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } memcpy(pCreateCopy, pCreateInfos, sizeof(VkSwapchainCreateInfoKHR) * swapchainCount); for (uint32_t sc = 0; sc < swapchainCount; sc++) { - VkResult res = wsi_unwrap_icd_surface(icd_term, &pCreateCopy[sc].surface); + res = wsi_unwrap_icd_surface(icd_term, &pCreateCopy[sc].surface); if (res != VK_SUCCESS) { - return res; + goto out; } } - return dev->loader_dispatch.extension_terminator_dispatch.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateCopy, - pAllocator, pSwapchains); + res = dev->loader_dispatch.extension_terminator_dispatch.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateCopy, + pAllocator, pSwapchains); + +out: + loader_free_with_instance_fallback(pAllocator, icd_term->this_instance, pCreateCopy); + return res; } LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL @@ -2415,21 +2420,25 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceDisplayProperties2KHR if (pProperties == NULL || *pPropertyCount == 0) { return icd_term->dispatch.GetPhysicalDeviceDisplayPropertiesKHR(phys_dev_term->phys_dev, pPropertyCount, NULL); } - + VkResult res = VK_SUCCESS; // If we do have to write to pProperties, then we need to write to a temporary array of VkDisplayPropertiesKHR and copy it uint32_t allocated_count = *pPropertyCount; - VkDisplayPropertiesKHR *properties = loader_stack_alloc(allocated_count * sizeof(VkDisplayPropertiesKHR)); + VkDisplayPropertiesKHR *properties = loader_instance_heap_calloc( + icd_term->this_instance, allocated_count * sizeof(VkDisplayPropertiesKHR), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (properties == NULL) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } - VkResult res = icd_term->dispatch.GetPhysicalDeviceDisplayPropertiesKHR(phys_dev_term->phys_dev, pPropertyCount, properties); + res = icd_term->dispatch.GetPhysicalDeviceDisplayPropertiesKHR(phys_dev_term->phys_dev, pPropertyCount, properties); if (res < 0) { - return res; + goto out; } // The driver reports the written count back in pPropertyCount; never copy past the array we sized. for (uint32_t i = 0; i < *pPropertyCount && i < allocated_count; ++i) { memcpy(&pProperties[i].displayProperties, &properties[i], sizeof(VkDisplayPropertiesKHR)); } +out: + loader_instance_heap_free(icd_term->this_instance, properties); return res; } @@ -2472,22 +2481,26 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceDisplayPlanePropertie if (pProperties == NULL || *pPropertyCount == 0) { return icd_term->dispatch.GetPhysicalDeviceDisplayPlanePropertiesKHR(phys_dev_term->phys_dev, pPropertyCount, NULL); } - + VkResult res = VK_SUCCESS; // If we do have to write to pProperties, then we need to write to a temporary array of VkDisplayPlanePropertiesKHR and copy it uint32_t allocated_count = *pPropertyCount; - VkDisplayPlanePropertiesKHR *properties = loader_stack_alloc(allocated_count * sizeof(VkDisplayPlanePropertiesKHR)); + VkDisplayPlanePropertiesKHR *properties = loader_instance_heap_calloc( + icd_term->this_instance, allocated_count * sizeof(VkDisplayPlanePropertiesKHR), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (properties == NULL) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } - VkResult res = - icd_term->dispatch.GetPhysicalDeviceDisplayPlanePropertiesKHR(phys_dev_term->phys_dev, pPropertyCount, properties); + res = icd_term->dispatch.GetPhysicalDeviceDisplayPlanePropertiesKHR(phys_dev_term->phys_dev, pPropertyCount, properties); if (res < 0) { - return res; + goto out; } // The driver reports the written count back in pPropertyCount; never copy past the array we sized. for (uint32_t i = 0; i < *pPropertyCount && i < allocated_count; ++i) { memcpy(&pProperties[i].displayPlaneProperties, &properties[i], sizeof(VkDisplayPlanePropertiesKHR)); } + +out: + loader_instance_heap_free(icd_term->this_instance, properties); return res; } @@ -2533,19 +2546,24 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetDisplayModeProperties2KHR(VkPhysica } // If we do have to write to pProperties, then we need to write to a temporary array of VkDisplayModePropertiesKHR and copy it + VkResult res = VK_SUCCESS; uint32_t allocated_count = *pPropertyCount; - VkDisplayModePropertiesKHR *properties = loader_stack_alloc(allocated_count * sizeof(VkDisplayModePropertiesKHR)); + VkDisplayModePropertiesKHR *properties = loader_instance_heap_calloc( + icd_term->this_instance, allocated_count * sizeof(VkDisplayModePropertiesKHR), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (properties == NULL) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } - VkResult res = icd_term->dispatch.GetDisplayModePropertiesKHR(phys_dev_term->phys_dev, display, pPropertyCount, properties); + res = icd_term->dispatch.GetDisplayModePropertiesKHR(phys_dev_term->phys_dev, display, pPropertyCount, properties); if (res < 0) { - return res; + goto out; } // The driver reports the written count back in pPropertyCount; never copy past the array we sized. for (uint32_t i = 0; i < *pPropertyCount && i < allocated_count; ++i) { memcpy(&pProperties[i].displayModeProperties, &properties[i], sizeof(VkDisplayModePropertiesKHR)); } +out: + loader_instance_heap_free(icd_term->this_instance, properties); return res; } @@ -2867,14 +2885,16 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceFormats2KHR(Vk return icd_term->dispatch.GetPhysicalDeviceSurfaceFormatsKHR(phys_dev_term->phys_dev, surface, pSurfaceFormatCount, NULL); } // Allocate a temporary array for the output of the old function + VkResult res = VK_SUCCESS; uint32_t allocated_count = *pSurfaceFormatCount; - VkSurfaceFormatKHR *formats = loader_stack_alloc(allocated_count * sizeof(VkSurfaceFormatKHR)); + VkSurfaceFormatKHR *formats = loader_instance_heap_calloc(icd_term->this_instance, allocated_count * sizeof(VkSurfaceFormatKHR), + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (formats == NULL) { - return VK_ERROR_OUT_OF_HOST_MEMORY; + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; } - VkResult res = - icd_term->dispatch.GetPhysicalDeviceSurfaceFormatsKHR(phys_dev_term->phys_dev, surface, pSurfaceFormatCount, formats); + res = icd_term->dispatch.GetPhysicalDeviceSurfaceFormatsKHR(phys_dev_term->phys_dev, surface, pSurfaceFormatCount, formats); // The driver reports the written count back in pSurfaceFormatCount; never copy past the array we sized. for (uint32_t i = 0; i < *pSurfaceFormatCount && i < allocated_count; ++i) { pSurfaceFormats[i].surfaceFormat = formats[i]; @@ -2885,6 +2905,8 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceFormats2KHR(Vk i); } } +out: + loader_instance_heap_free(icd_term->this_instance, formats); return res; }