1 /*
2  * Copyright (c) 2021-2023 The Khronos Group Inc.
3  * Copyright (c) 2021-2023 Valve Corporation
4  * Copyright (c) 2021-2023 LunarG, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and/or associated documentation files (the "Materials"), to
8  * deal in the Materials without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Materials, and to permit persons to whom the Materials are
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice(s) and this permission notice shall be included in
14  * all copies or substantial portions of the Materials.
15  *
16  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  *
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23  * USE OR OTHER DEALINGS IN THE MATERIALS.
24  *
25  * Author: Charles Giessen <charles@lunarg.com>
26  */
27 
28 #include "test_environment.h"
29 
30 #include <mutex>
31 
32 struct MemoryTrackerSettings {
33     bool should_fail_on_allocation = false;
34     size_t fail_after_allocations = 0;  // fail after this number of allocations in total
35     bool should_fail_after_set_number_of_calls = false;
36     size_t fail_after_calls = 0;  // fail after this number of calls to alloc or realloc
37 };
38 
39 class MemoryTracker {
40     std::mutex main_mutex;
41     MemoryTrackerSettings settings{};
42     VkAllocationCallbacks callbacks{};
43     // Implementation internals
44     struct AllocationDetails {
45         std::unique_ptr<char[]> allocation;
46         size_t requested_size_bytes;
47         size_t actual_size_bytes;
48         size_t alignment;
49         VkSystemAllocationScope alloc_scope;
50     };
51     const static size_t UNKNOWN_ALLOCATION = std::numeric_limits<size_t>::max();
52     size_t allocation_count = 0;
53     size_t call_count = 0;
54     std::unordered_map<void*, AllocationDetails> allocations;
55 
allocate(size_t size, size_t alignment, VkSystemAllocationScope alloc_scope)56     void* allocate(size_t size, size_t alignment, VkSystemAllocationScope alloc_scope) {
57         if ((settings.should_fail_on_allocation && allocation_count == settings.fail_after_allocations) ||
58             (settings.should_fail_after_set_number_of_calls && call_count == settings.fail_after_calls)) {
59             return nullptr;
60         }
61         call_count++;
62         allocation_count++;
63         AllocationDetails detail{nullptr, size, size + (alignment - 1), alignment, alloc_scope};
64         detail.allocation = std::unique_ptr<char[]>(new char[detail.actual_size_bytes]);
65         if (!detail.allocation) {
66             abort();
67         };
68         uint64_t addr = (uint64_t)detail.allocation.get();
69         addr += (alignment - 1);
70         addr &= ~(alignment - 1);
71         void* aligned_alloc = (void*)addr;
72         allocations.insert(std::make_pair(aligned_alloc, std::move(detail)));
73         return aligned_alloc;
74     }
reallocate(void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope alloc_scope)75     void* reallocate(void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope alloc_scope) {
76         if (pOriginal == nullptr) {
77             return allocate(size, alignment, alloc_scope);
78         }
79         auto elem = allocations.find(pOriginal);
80         if (elem == allocations.end()) return nullptr;
81         size_t original_size = elem->second.requested_size_bytes;
82 
83         // We only care about the case where realloc is used to increase the size
84         if (size >= original_size && settings.should_fail_after_set_number_of_calls && call_count == settings.fail_after_calls)
85             return nullptr;
86         call_count++;
87         if (size == 0) {
88             allocations.erase(elem);
89             allocation_count--;
90             return nullptr;
91         } else if (size < original_size) {
92             return pOriginal;
93         } else {
94             void* new_alloc = allocate(size, alignment, alloc_scope);
95             if (new_alloc == nullptr) return nullptr;
96             allocation_count--;  // allocate() increments this, we we don't want that
97             call_count--;        // allocate() also increments this, we don't want that
98             memcpy(new_alloc, pOriginal, original_size);
99             allocations.erase(elem);
100             return new_alloc;
101         }
102     }
free(void* pMemory)103     void free(void* pMemory) {
104         if (pMemory == nullptr) return;
105         auto elem = allocations.find(pMemory);
106         if (elem == allocations.end()) return;
107         allocations.erase(elem);
108         assert(allocation_count != 0 && "Cant free when there are no valid allocations");
109         allocation_count--;
110     }
111 
112     // Implementation of public functions
113     void* impl_allocation(size_t size, size_t alignment, VkSystemAllocationScope allocationScope) noexcept {
114         std::lock_guard<std::mutex> lg(main_mutex);
115         void* addr = allocate(size, alignment, allocationScope);
116         return addr;
117     }
118     void* impl_reallocation(void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope) noexcept {
119         std::lock_guard<std::mutex> lg(main_mutex);
120         void* addr = reallocate(pOriginal, size, alignment, allocationScope);
121         return addr;
122     }
123     void impl_free(void* pMemory) noexcept {
124         std::lock_guard<std::mutex> lg(main_mutex);
125         free(pMemory);
126     }
127     void impl_internal_allocation_notification([[maybe_unused]] size_t size,
128                                                [[maybe_unused]] VkInternalAllocationType allocationType,
129                                                [[maybe_unused]] VkSystemAllocationScope allocationScope) noexcept {
130         std::lock_guard<std::mutex> lg(main_mutex);
131         // TODO?
132     }
133     void impl_internal_free([[maybe_unused]] size_t size, [[maybe_unused]] VkInternalAllocationType allocationType,
134                             [[maybe_unused]] VkSystemAllocationScope allocationScope) noexcept {
135         std::lock_guard<std::mutex> lg(main_mutex);
136         // TODO?
137     }
138 
139    public:
settings(settings)140     MemoryTracker(MemoryTrackerSettings settings) noexcept : settings(settings) {
141         allocations.reserve(3000);
142 
143         callbacks.pUserData = this;
144         callbacks.pfnAllocation = public_allocation;
145         callbacks.pfnReallocation = public_reallocation;
146         callbacks.pfnFree = public_free;
147         callbacks.pfnInternalAllocation = public_internal_allocation_notification;
148         callbacks.pfnInternalFree = public_internal_free;
149     }
150     MemoryTracker() noexcept : MemoryTracker(MemoryTrackerSettings{}) {}
151 
152     VkAllocationCallbacks* get() noexcept { return &callbacks; }
153 
154     bool empty() noexcept { return allocation_count == 0; }
155 
156     // Static callbacks
157     static VKAPI_ATTR void* VKAPI_CALL public_allocation(void* pUserData, size_t size, size_t alignment,
158                                                          VkSystemAllocationScope allocationScope) noexcept {
159         return reinterpret_cast<MemoryTracker*>(pUserData)->impl_allocation(size, alignment, allocationScope);
160     }
161     static VKAPI_ATTR void* VKAPI_CALL public_reallocation(void* pUserData, void* pOriginal, size_t size, size_t alignment,
162                                                            VkSystemAllocationScope allocationScope) noexcept {
163         return reinterpret_cast<MemoryTracker*>(pUserData)->impl_reallocation(pOriginal, size, alignment, allocationScope);
164     }
165     static VKAPI_ATTR void VKAPI_CALL public_free(void* pUserData, void* pMemory) noexcept {
166         reinterpret_cast<MemoryTracker*>(pUserData)->impl_free(pMemory);
167     }
168     static VKAPI_ATTR void VKAPI_CALL public_internal_allocation_notification(void* pUserData, size_t size,
169                                                                               VkInternalAllocationType allocationType,
170                                                                               VkSystemAllocationScope allocationScope) noexcept {
171         reinterpret_cast<MemoryTracker*>(pUserData)->impl_internal_allocation_notification(size, allocationType, allocationScope);
172     }
173     static VKAPI_ATTR void VKAPI_CALL public_internal_free(void* pUserData, size_t size, VkInternalAllocationType allocationType,
174                                                            VkSystemAllocationScope allocationScope) noexcept {
175         reinterpret_cast<MemoryTracker*>(pUserData)->impl_internal_free(size, allocationType, allocationScope);
176     }
177 };
178 
179 // Test making sure the allocation functions are called to allocate and cleanup everything during
180 // a CreateInstance/DestroyInstance call pair.
TEST(Allocation, Instance)181 TEST(Allocation, Instance) {
182     FrameworkEnvironment env{};
183     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
184 
185     MemoryTracker tracker;
186     {
187         InstWrapper inst{env.vulkan_functions, tracker.get()};
188         ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
189     }
190     ASSERT_TRUE(tracker.empty());
191 }
192 
193 // Test making sure the allocation functions are called to allocate and cleanup everything during
194 // a CreateInstance/DestroyInstance call pair with a call to GetInstanceProcAddr.
TEST(Allocation, GetInstanceProcAddr)195 TEST(Allocation, GetInstanceProcAddr) {
196     FrameworkEnvironment env{};
197     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
198 
199     MemoryTracker tracker;
200     {
201         InstWrapper inst{env.vulkan_functions, tracker.get()};
202         ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
203 
204         auto* pfnCreateDevice = inst->vkGetInstanceProcAddr(inst, "vkCreateDevice");
205         auto* pfnDestroyDevice = inst->vkGetInstanceProcAddr(inst, "vkDestroyDevice");
206         ASSERT_TRUE(pfnCreateDevice != nullptr && pfnDestroyDevice != nullptr);
207     }
208     ASSERT_TRUE(tracker.empty());
209 }
210 
211 // Test making sure the allocation functions are called to allocate and cleanup everything during
212 // a vkEnumeratePhysicalDevices call pair.
TEST(Allocation, EnumeratePhysicalDevices)213 TEST(Allocation, EnumeratePhysicalDevices) {
214     FrameworkEnvironment env{};
215     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device("physical_device_0");
216 
217     MemoryTracker tracker;
218     {
219         InstWrapper inst{env.vulkan_functions, tracker.get()};
220         ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
221         uint32_t physical_count = 1;
222         uint32_t returned_physical_count = 0;
223         ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
224         ASSERT_EQ(physical_count, returned_physical_count);
225 
226         VkPhysicalDevice physical_device;
227         ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, &physical_device));
228         ASSERT_EQ(physical_count, returned_physical_count);
229     }
230     ASSERT_TRUE(tracker.empty());
231 }
232 
233 // Test making sure the allocation functions are called to allocate and cleanup everything from
234 // vkCreateInstance, to vkCreateDevicce, and then through their destructors.  With special
235 // allocators used on both the instance and device.
TEST(Allocation, InstanceAndDevice)236 TEST(Allocation, InstanceAndDevice) {
237     FrameworkEnvironment env{};
238     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2))
239         .add_physical_device(PhysicalDevice{"physical_device_0"}
240                                  .add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false})
241                                  .finish());
242 
243     MemoryTracker tracker;
244     {
245         InstWrapper inst{env.vulkan_functions, tracker.get()};
246         ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
247 
248         uint32_t physical_count = 1;
249         uint32_t returned_physical_count = 0;
250         ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
251         ASSERT_EQ(physical_count, returned_physical_count);
252 
253         VkPhysicalDevice physical_device;
254         ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, &physical_device));
255         ASSERT_EQ(physical_count, returned_physical_count);
256 
257         uint32_t family_count = 1;
258         uint32_t returned_family_count = 0;
259         env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &returned_family_count, nullptr);
260         ASSERT_EQ(returned_family_count, family_count);
261 
262         VkQueueFamilyProperties family;
263         env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &returned_family_count, &family);
264         ASSERT_EQ(returned_family_count, family_count);
265         ASSERT_EQ(family.queueFlags, static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT));
266         ASSERT_EQ(family.queueCount, family_count);
267         ASSERT_EQ(family.timestampValidBits, 0U);
268 
269         DeviceCreateInfo dev_create_info;
270         dev_create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
271 
272         VkDevice device;
273         ASSERT_EQ(inst->vkCreateDevice(physical_device, dev_create_info.get(), tracker.get(), &device), VK_SUCCESS);
274 
275         VkQueue queue;
276         inst->vkGetDeviceQueue(device, 0, 0, &queue);
277 
278         inst->vkDestroyDevice(device, tracker.get());
279     }
280     ASSERT_TRUE(tracker.empty());
281 }
282 // Test making sure the allocation functions are called to allocate and cleanup everything from
283 // vkCreateInstance, to vkCreateDevicce, and then through their destructors.  With special
284 // allocators used on only the instance and not the device.
TEST(Allocation, InstanceButNotDevice)285 TEST(Allocation, InstanceButNotDevice) {
286     FrameworkEnvironment env{};
287     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2))
288         .add_physical_device(PhysicalDevice{"physical_device_0"}
289                                  .add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false})
290                                  .finish());
291 
292     MemoryTracker tracker;
293     {
294         InstWrapper inst{env.vulkan_functions, tracker.get()};
295         ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
296 
297         uint32_t physical_count = 1;
298         uint32_t returned_physical_count = 0;
299         ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
300         ASSERT_EQ(physical_count, returned_physical_count);
301 
302         VkPhysicalDevice physical_device;
303         ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, &physical_device));
304         ASSERT_EQ(physical_count, returned_physical_count);
305 
306         uint32_t family_count = 1;
307         uint32_t returned_family_count = 0;
308         env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &returned_family_count, nullptr);
309         ASSERT_EQ(returned_family_count, family_count);
310 
311         VkQueueFamilyProperties family;
312         env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &returned_family_count, &family);
313         ASSERT_EQ(returned_family_count, family_count);
314         ASSERT_EQ(family.queueFlags, static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT));
315         ASSERT_EQ(family.queueCount, family_count);
316         ASSERT_EQ(family.timestampValidBits, 0U);
317 
318         DeviceCreateInfo dev_create_info;
319         dev_create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
320 
321         VkDevice device;
322         ASSERT_EQ(inst->vkCreateDevice(physical_device, dev_create_info.get(), nullptr, &device), VK_SUCCESS);
323         VkQueue queue;
324         inst->vkGetDeviceQueue(device, 0, 0, &queue);
325 
326         inst->vkDestroyDevice(device, nullptr);
327     }
328     ASSERT_TRUE(tracker.empty());
329 }
330 
331 // Test making sure the allocation functions are called to allocate and cleanup everything from
332 // vkCreateInstance, to vkCreateDevicce, and then through their destructors.  With special
333 // allocators used on only the device and not the instance.
TEST(Allocation, DeviceButNotInstance)334 TEST(Allocation, DeviceButNotInstance) {
335     FrameworkEnvironment env{};
336     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2))
337         .add_physical_device(PhysicalDevice{"physical_device_0"}
338                                  .add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false})
339                                  .finish());
340 
341     const char* layer_name = "VK_LAYER_implicit";
342     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
343                                                          .set_name(layer_name)
344                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
345                                                          .set_disable_environment("DISABLE_ENV")),
346                            "test_layer.json");
347     env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
348 
349     MemoryTracker tracker;
350     {
351         InstWrapper inst{env.vulkan_functions};
352         ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
353 
354         uint32_t physical_count = 1;
355         uint32_t returned_physical_count = 0;
356         ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
357         ASSERT_EQ(physical_count, returned_physical_count);
358 
359         VkPhysicalDevice physical_device;
360         ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, &physical_device));
361         ASSERT_EQ(physical_count, returned_physical_count);
362 
363         uint32_t family_count = 1;
364         uint32_t returned_family_count = 0;
365         env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &returned_family_count, nullptr);
366         ASSERT_EQ(returned_family_count, family_count);
367 
368         VkQueueFamilyProperties family;
369         env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &returned_family_count, &family);
370         ASSERT_EQ(returned_family_count, family_count);
371         ASSERT_EQ(family.queueFlags, static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT));
372         ASSERT_EQ(family.queueCount, family_count);
373         ASSERT_EQ(family.timestampValidBits, 0U);
374 
375         DeviceCreateInfo dev_create_info;
376         dev_create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
377 
378         VkDevice device;
379         ASSERT_EQ(inst->vkCreateDevice(physical_device, dev_create_info.get(), tracker.get(), &device), VK_SUCCESS);
380 
381         VkQueue queue;
382         inst->vkGetDeviceQueue(device, 0, 0, &queue);
383 
384         inst->vkDestroyDevice(device, tracker.get());
385     }
386     ASSERT_TRUE(tracker.empty());
387 }
388 
389 // Test failure during vkCreateInstance to make sure we don't leak memory if
390 // one of the out-of-memory conditions trigger.
TEST(Allocation, CreateInstanceIntentionalAllocFail)391 TEST(Allocation, CreateInstanceIntentionalAllocFail) {
392     FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("error,warn")};
393     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
394 
395     const char* layer_name = "VK_LAYER_implicit";
396     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
397                                                          .set_name(layer_name)
398                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
399                                                          .set_disable_environment("DISABLE_ENV")),
400                            "test_layer.json");
401     env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
402 
403     size_t fail_index = 0;
404     VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
405     while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
406         MemoryTracker tracker({false, 0, true, fail_index});
407 
408         VkInstance instance;
409         InstanceCreateInfo inst_create_info{};
410         result = env.vulkan_functions.vkCreateInstance(inst_create_info.get(), tracker.get(), &instance);
411         if (result == VK_SUCCESS) {
412             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
413         }
414         ASSERT_TRUE(tracker.empty());
415         fail_index++;
416     }
417 }
418 
419 // Test failure during vkCreateInstance to make sure we don't leak memory if
420 // one of the out-of-memory conditions trigger and there are invalid jsons in the same folder
TEST(Allocation, CreateInstanceIntentionalAllocFailInvalidManifests)421 TEST(Allocation, CreateInstanceIntentionalAllocFailInvalidManifests) {
422     FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("error,warn")};
423     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
424 
425     std::vector<std::string> invalid_jsons;
426     invalid_jsons.push_back(",");
427     invalid_jsons.push_back("{},[]");
428     invalid_jsons.push_back("{ \"foo\":\"bar\", }");
429     invalid_jsons.push_back("{\"foo\":\"bar\", \"baz\": [], },");
430     invalid_jsons.push_back("{\"foo\":\"bar\", \"baz\": [{},] },");
431     invalid_jsons.push_back("{\"foo\":\"bar\", \"baz\": {\"fee\"} },");
432     invalid_jsons.push_back("{\"\":\"bar\", \"baz\": {}");
433     invalid_jsons.push_back("{\"foo\":\"bar\", \"baz\": {\"fee\":1234, true, \"ab\":\"bc\"} },");
434 
435     for (size_t i = 0; i < invalid_jsons.size(); i++) {
436         auto file_name = std::string("invalid_implicit_layer_") + std::to_string(i) + ".json";
437         fs::path new_path = env.get_folder(ManifestLocation::implicit_layer).write_manifest(file_name, invalid_jsons[i]);
438         env.platform_shim->add_manifest(ManifestCategory::implicit_layer, new_path);
439     }
440 
441     const char* layer_name = "VkLayerImplicit0";
442     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
443                                                          .set_name(layer_name)
444                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
445                                                          .set_disable_environment("DISABLE_ENV")),
446                            "test_layer.json");
447 
448     size_t fail_index = 0;
449     VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
450     while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
451         MemoryTracker tracker({false, 0, true, fail_index});
452 
453         VkInstance instance;
454         InstanceCreateInfo inst_create_info{};
455         result = env.vulkan_functions.vkCreateInstance(inst_create_info.get(), tracker.get(), &instance);
456         if (result == VK_SUCCESS) {
457             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
458         }
459         ASSERT_TRUE(tracker.empty());
460         fail_index++;
461     }
462 }
463 
464 // Test failure during vkCreateInstance & surface creation to make sure we don't leak memory if
465 // one of the out-of-memory conditions trigger.
TEST(Allocation, CreateSurfaceIntentionalAllocFail)466 TEST(Allocation, CreateSurfaceIntentionalAllocFail) {
467     FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("error,warn")};
468     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).setup_WSI();
469 
470     const char* layer_name = "VK_LAYER_implicit";
471     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
472                                                          .set_name(layer_name)
473                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
474                                                          .set_disable_environment("DISABLE_ENV")),
475                            "test_layer.json");
476     env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
477 
478     size_t fail_index = 0;
479     VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
480     while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
481         MemoryTracker tracker({false, 0, true, fail_index});
482 
483         VkInstance instance;
484         InstanceCreateInfo inst_create_info{};
485         inst_create_info.setup_WSI();
486         result = env.vulkan_functions.vkCreateInstance(inst_create_info.get(), tracker.get(), &instance);
487         if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
488             ASSERT_TRUE(tracker.empty());
489             fail_index++;
490             continue;
491         }
492 
493         VkSurfaceKHR surface{};
494         result = create_surface(&env.vulkan_functions, instance, surface);
495         if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
496             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
497             ASSERT_TRUE(tracker.empty());
498             fail_index++;
499             continue;
500         }
501         env.vulkan_functions.vkDestroySurfaceKHR(instance, surface, tracker.get());
502 
503         env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
504         ASSERT_TRUE(tracker.empty());
505         fail_index++;
506     }
507 }
508 
509 // Test failure during vkCreateInstance to make sure we don't leak memory if
510 // one of the out-of-memory conditions trigger.
TEST(Allocation, CreateInstanceIntentionalAllocFailWithSettingsFilePresent)511 TEST(Allocation, CreateInstanceIntentionalAllocFailWithSettingsFilePresent) {
512     FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("error,warn")};
513     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
514 
515     const char* layer_name = "VK_LAYER_implicit";
516     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
517                                                          .set_name(layer_name)
518                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
519                                                          .set_disable_environment("DISABLE_ENV")),
520                            "test_layer.json");
521     env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
522 
523     env.update_loader_settings(
524         env.loader_settings.add_app_specific_setting(AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
525             LoaderSettingsLayerConfiguration{}
526                 .set_name(layer_name)
527                 .set_control("auto")
528                 .set_path(env.get_shimmed_layer_manifest_path(0).str()))));
529 
530     size_t fail_index = 0;
531     VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
532     while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
533         MemoryTracker tracker({false, 0, true, fail_index});
534 
535         VkInstance instance;
536         InstanceCreateInfo inst_create_info{};
537         result = env.vulkan_functions.vkCreateInstance(inst_create_info.get(), tracker.get(), &instance);
538         if (result == VK_SUCCESS) {
539             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
540         }
541         ASSERT_TRUE(tracker.empty());
542         fail_index++;
543     }
544 }
545 
546 // Test failure during vkCreateInstance & surface creation to make sure we don't leak memory if
547 // one of the out-of-memory conditions trigger.
TEST(Allocation, CreateSurfaceIntentionalAllocFailWithSettingsFilePresent)548 TEST(Allocation, CreateSurfaceIntentionalAllocFailWithSettingsFilePresent) {
549     FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("error,warn")};
550     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).setup_WSI();
551 
552     const char* layer_name = "VK_LAYER_implicit";
553     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
554                                                          .set_name(layer_name)
555                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
556                                                          .set_disable_environment("DISABLE_ENV")),
557                            "test_layer.json");
558     env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
559     env.update_loader_settings(
560         env.loader_settings.add_app_specific_setting(AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
561             LoaderSettingsLayerConfiguration{}
562                 .set_name(layer_name)
563                 .set_control("auto")
564                 .set_path(env.get_shimmed_layer_manifest_path(0).str()))));
565 
566     size_t fail_index = 0;
567     VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
568     while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
569         MemoryTracker tracker({false, 0, true, fail_index});
570 
571         VkInstance instance;
572         InstanceCreateInfo inst_create_info{};
573         inst_create_info.setup_WSI();
574         result = env.vulkan_functions.vkCreateInstance(inst_create_info.get(), tracker.get(), &instance);
575         if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
576             ASSERT_TRUE(tracker.empty());
577             fail_index++;
578             continue;
579         }
580 
581         VkSurfaceKHR surface{};
582         result = create_surface(&env.vulkan_functions, instance, surface);
583         if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
584             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
585             ASSERT_TRUE(tracker.empty());
586             fail_index++;
587             continue;
588         }
589         env.vulkan_functions.vkDestroySurfaceKHR(instance, surface, tracker.get());
590 
591         env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
592         ASSERT_TRUE(tracker.empty());
593         fail_index++;
594     }
595 }
596 
597 // Test failure during vkCreateInstance to make sure we don't leak memory if
598 // one of the out-of-memory conditions trigger.
TEST(Allocation, DriverEnvVarIntentionalAllocFail)599 TEST(Allocation, DriverEnvVarIntentionalAllocFail) {
600     FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("error,warn")};
601     env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_2}.set_discovery_type(ManifestDiscoveryType::env_var));
602 
603     const char* layer_name = "VK_LAYER_implicit";
604     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
605                                                          .set_name(layer_name)
606                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
607                                                          .set_disable_environment("DISABLE_ENV")),
608                            "test_layer.json");
609     env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
610 
611     env.env_var_vk_icd_filenames.add_to_list((fs::path("totally_made_up") / "path_to_fake" / "jason_file.json").str());
612     size_t fail_index = 0;
613     VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
614     while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
615         MemoryTracker tracker({false, 0, true, fail_index});
616 
617         VkInstance instance;
618         InstanceCreateInfo inst_create_info{};
619         result = env.vulkan_functions.vkCreateInstance(inst_create_info.get(), tracker.get(), &instance);
620         if (result == VK_SUCCESS) {
621             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
622         }
623         ASSERT_TRUE(tracker.empty());
624         fail_index++;
625     }
626 }
627 
628 // Test failure during vkCreateDevice to make sure we don't leak memory if
629 // one of the out-of-memory conditions trigger.
630 // Use 2 physical devices so that anything which copies a list of devices item by item
631 // may fail.
TEST(Allocation, CreateDeviceIntentionalAllocFail)632 TEST(Allocation, CreateDeviceIntentionalAllocFail) {
633     FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("error,warn")};
634     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2))
635         .add_physical_device(PhysicalDevice{"physical_device_0"}
636                                  .add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false})
637                                  .finish())
638         .add_physical_device(PhysicalDevice{"physical_device_1"}
639                                  .add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false})
640                                  .finish());
641 
642     const char* layer_name = "VK_LAYER_implicit";
643     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
644                                                          .set_name(layer_name)
645                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
646                                                          .set_disable_environment("DISABLE_ENV")),
647                            "test_layer.json");
648     env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
649 
650     InstWrapper inst{env.vulkan_functions};
651     ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
652 
653     uint32_t physical_count = 2;
654     uint32_t returned_physical_count = 0;
655     ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, nullptr));
656     ASSERT_EQ(physical_count, returned_physical_count);
657 
658     VkPhysicalDevice physical_devices[2];
659     ASSERT_EQ(VK_SUCCESS, inst->vkEnumeratePhysicalDevices(inst.inst, &returned_physical_count, physical_devices));
660     ASSERT_EQ(physical_count, returned_physical_count);
661 
662     uint32_t family_count = 1;
663     uint32_t returned_family_count = 0;
664     env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[0], &returned_family_count, nullptr);
665     ASSERT_EQ(returned_family_count, family_count);
666 
667     VkQueueFamilyProperties family;
668     env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[0], &returned_family_count, &family);
669     ASSERT_EQ(returned_family_count, family_count);
670     ASSERT_EQ(family.queueFlags, static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT));
671     ASSERT_EQ(family.queueCount, family_count);
672     ASSERT_EQ(family.timestampValidBits, 0U);
673 
674     size_t fail_index = 0;
675     VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
676     while (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
677         MemoryTracker tracker({false, 0, true, fail_index});
678 
679         DeviceCreateInfo dev_create_info;
680         dev_create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
681 
682         VkDevice device;
683         result = inst->vkCreateDevice(physical_devices[0], dev_create_info.get(), tracker.get(), &device);
684         if (result == VK_SUCCESS || fail_index > 10000) {
685             VkQueue queue;
686             inst->vkGetDeviceQueue(device, 0, 0, &queue);
687 
688             inst->vkDestroyDevice(device, tracker.get());
689             break;
690         }
691         ASSERT_TRUE(tracker.empty());
692         fail_index++;
693     }
694 }
695 
696 // Test failure during vkCreateInstance and vkCreateDevice to make sure we don't
697 // leak memory if one of the out-of-memory conditions trigger.
698 // Includes drivers with several instance extensions, drivers that will fail to load, directly loaded drivers
TEST(Allocation, CreateInstanceDeviceIntentionalAllocFail)699 TEST(Allocation, CreateInstanceDeviceIntentionalAllocFail) {
700     FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("error,warn")};
701     uint32_t num_physical_devices = 4;
702     uint32_t num_implicit_layers = 3;
703     for (uint32_t i = 0; i < num_physical_devices; i++) {
704         env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)
705                         .icd_manifest.set_is_portability_driver(false)
706                         .set_library_arch(sizeof(void*) == 8 ? "64" : "32"))
707             .set_icd_api_version(VK_API_VERSION_1_1)
708             .add_instance_extension("VK_KHR_get_physical_device_properties2")
709             .add_physical_device("physical_device_0")
710             .physical_devices.at(0)
711             .add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false})
712             .add_extensions({"VK_EXT_one", "VK_EXT_two", "VK_EXT_three", "VK_EXT_four", "VK_EXT_five"});
713     }
714 
715     env.add_icd(TestICDDetails(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE).set_is_fake(true));
716 
717     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_7).set_discovery_type(ManifestDiscoveryType::none));
718 
719     VkDirectDriverLoadingInfoLUNARG ddl_info{};
720     ddl_info.sType = VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_INFO_LUNARG;
721     ddl_info.pfnGetInstanceProcAddr = env.icds.back().icd_library.get_symbol("vk_icdGetInstanceProcAddr");
722 
723     VkDirectDriverLoadingListLUNARG ddl_list{};
724     ddl_list.sType = VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG;
725     ddl_list.mode = VK_DIRECT_DRIVER_LOADING_MODE_INCLUSIVE_LUNARG;
726     ddl_list.driverCount = 1;
727     ddl_list.pDrivers = &ddl_info;
728 
729     const char* layer_name = "VK_LAYER_ImplicitAllocFail";
730     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
731                                                          .set_name(layer_name)
732                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
733                                                          .set_disable_environment("DISABLE_ENV")),
734                            "test_layer.json");
735     env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
736     for (uint32_t i = 1; i < num_implicit_layers + 1; i++) {
737         env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
738                                                              .set_name("VK_LAYER_Implicit1" + std::to_string(i))
739                                                              .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
740                                                              .set_disable_environment("DISABLE_ENV")),
741                                "test_layer_" + std::to_string(i) + ".json");
742     }
743     std::fstream custom_json_file{COMPLEX_JSON_FILE, std::ios_base::in};
744     ASSERT_TRUE(custom_json_file.is_open());
745     std::stringstream custom_json_file_contents;
746     custom_json_file_contents << custom_json_file.rdbuf();
747 
748     fs::path new_path = env.get_folder(ManifestLocation::explicit_layer)
749                             .write_manifest("VK_LAYER_complex_file.json", custom_json_file_contents.str());
750     env.platform_shim->add_manifest(ManifestCategory::explicit_layer, new_path);
751 
752     size_t fail_index = 0;
753     VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
754     while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
755         MemoryTracker tracker{{false, 0, true, fail_index}};
756         fail_index++;  // applies to the next loop
757 
758         VkInstance instance;
759         InstanceCreateInfo inst_create_info{};
760         inst_create_info.add_extension(VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME);
761         inst_create_info.instance_info.pNext = reinterpret_cast<const void*>(&ddl_list);
762         result = env.vulkan_functions.vkCreateInstance(inst_create_info.get(), tracker.get(), &instance);
763         if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
764             ASSERT_TRUE(tracker.empty());
765             continue;
766         }
767         ASSERT_EQ(result, VK_SUCCESS);
768 
769         uint32_t returned_physical_count = 0;
770         result = env.vulkan_functions.vkEnumeratePhysicalDevices(instance, &returned_physical_count, nullptr);
771         if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
772             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
773             ASSERT_TRUE(tracker.empty());
774             continue;
775         }
776         ASSERT_EQ(result, VK_SUCCESS);
777         ASSERT_EQ(num_physical_devices, returned_physical_count);
778 
779         std::vector<VkPhysicalDevice> physical_devices;
780         physical_devices.resize(returned_physical_count);
781         result = env.vulkan_functions.vkEnumeratePhysicalDevices(instance, &returned_physical_count, physical_devices.data());
782         if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
783             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
784             ASSERT_TRUE(tracker.empty());
785             continue;
786         }
787         ASSERT_EQ(result, VK_SUCCESS);
788         ASSERT_EQ(num_physical_devices, returned_physical_count);
789         for (uint32_t i = 0; i < returned_physical_count; i++) {
790             uint32_t family_count = 1;
791             uint32_t returned_family_count = 0;
792             env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_devices.at(i), &returned_family_count, nullptr);
793             ASSERT_EQ(returned_family_count, family_count);
794 
795             VkQueueFamilyProperties family;
796             env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_devices.at(i), &returned_family_count, &family);
797             ASSERT_EQ(returned_family_count, family_count);
798             ASSERT_EQ(family.queueFlags, static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT));
799             ASSERT_EQ(family.queueCount, family_count);
800             ASSERT_EQ(family.timestampValidBits, 0U);
801 
802             DeviceCreateInfo dev_create_info;
803             dev_create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
804 
805             VkDevice device;
806             result = env.vulkan_functions.vkCreateDevice(physical_devices.at(i), dev_create_info.get(), tracker.get(), &device);
807             if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
808                 break;
809             }
810             ASSERT_EQ(result, VK_SUCCESS);
811 
812             VkQueue queue;
813             env.vulkan_functions.vkGetDeviceQueue(device, 0, 0, &queue);
814 
815             env.vulkan_functions.vkDestroyDevice(device, tracker.get());
816         }
817         env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
818 
819         ASSERT_TRUE(tracker.empty());
820     }
821 }
822 
823 // Test failure during vkCreateInstance when a driver of the wrong architecture is present
824 // to make sure the loader uses the valid ICD and doesn't report incompatible driver just because
825 // an incompatible driver exists
TEST(TryLoadWrongBinaries, CreateInstanceIntentionalAllocFail)826 TEST(TryLoadWrongBinaries, CreateInstanceIntentionalAllocFail) {
827     FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("error,warn")};
828     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
829     env.add_icd(TestICDDetails(CURRENT_PLATFORM_DUMMY_BINARY_WRONG_TYPE).set_is_fake(true));
830 
831     const char* layer_name = "VK_LAYER_implicit";
832     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
833                                                          .set_name(layer_name)
834                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
835                                                          .set_disable_environment("DISABLE_ENV")),
836                            "test_layer.json");
837     env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
838 
839     size_t fail_index = 0;
840     VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
841     while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
842         MemoryTracker tracker({false, 0, true, fail_index});
843 
844         VkInstance instance;
845         InstanceCreateInfo inst_create_info{};
846         result = env.vulkan_functions.vkCreateInstance(inst_create_info.get(), tracker.get(), &instance);
847         if (result == VK_SUCCESS) {
848             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
849         }
850         ASSERT_NE(result, VK_ERROR_INCOMPATIBLE_DRIVER);
851         ASSERT_TRUE(tracker.empty());
852         fail_index++;
853     }
854 }
855 
856 // Test failure during vkCreateInstance and vkCreateDevice to make sure we don't
857 // leak memory if one of the out-of-memory conditions trigger.
TEST(Allocation, EnumeratePhysicalDevicesIntentionalAllocFail)858 TEST(Allocation, EnumeratePhysicalDevicesIntentionalAllocFail) {
859     FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("error,warn")};
860     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
861 
862     const char* layer_name = "VK_LAYER_implicit";
863     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
864                                                          .set_name(layer_name)
865                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
866                                                          .set_disable_environment("DISABLE_ENV")),
867                            "test_layer.json");
868     env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
869 
870     size_t fail_index = 0;
871     bool reached_the_end = false;
872     uint32_t starting_physical_dev_count = 3;
873     while (!reached_the_end && fail_index <= 100) {
874         fail_index++;  // applies to the next loop
875         uint32_t physical_dev_count = starting_physical_dev_count;
876         VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
877         auto& driver = env.reset_icd();
878 
879         for (uint32_t i = 0; i < physical_dev_count; i++) {
880             driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i))
881                 .add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false});
882         }
883         MemoryTracker tracker{{false, 0, true, fail_index}};
884         InstanceCreateInfo inst_create_info;
885         VkInstance instance;
886         result = env.vulkan_functions.vkCreateInstance(inst_create_info.get(), tracker.get(), &instance);
887         if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
888             ASSERT_TRUE(tracker.empty());
889             continue;
890         }
891 
892         uint32_t returned_physical_count = 0;
893         result = env.vulkan_functions.vkEnumeratePhysicalDevices(instance, &returned_physical_count, nullptr);
894         if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
895             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
896             ASSERT_TRUE(tracker.empty());
897             continue;
898         }
899         ASSERT_EQ(physical_dev_count, returned_physical_count);
900 
901         for (uint32_t i = 0; i < 2; i++) {
902             driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(physical_dev_count))
903                 .add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false});
904             physical_dev_count += 1;
905         }
906 
907         std::vector<VkPhysicalDevice> physical_devices{physical_dev_count, VK_NULL_HANDLE};
908         result = env.vulkan_functions.vkEnumeratePhysicalDevices(instance, &returned_physical_count, physical_devices.data());
909         if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
910             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
911             ASSERT_TRUE(tracker.empty());
912             continue;
913         }
914         if (result == VK_INCOMPLETE) {
915             result = env.vulkan_functions.vkEnumeratePhysicalDevices(instance, &returned_physical_count, nullptr);
916             if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
917                 env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
918                 ASSERT_TRUE(tracker.empty());
919                 continue;
920             }
921             physical_devices.resize(returned_physical_count);
922             result = env.vulkan_functions.vkEnumeratePhysicalDevices(instance, &returned_physical_count, physical_devices.data());
923             if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
924                 env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
925                 ASSERT_TRUE(tracker.empty());
926                 continue;
927             }
928         }
929         ASSERT_EQ(physical_dev_count, returned_physical_count);
930 
931         std::array<VkDevice, 5> devices;
932         for (uint32_t i = 0; i < returned_physical_count; i++) {
933             uint32_t family_count = 1;
934             uint32_t returned_family_count = 0;
935             env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &returned_family_count, nullptr);
936             ASSERT_EQ(returned_family_count, family_count);
937 
938             VkQueueFamilyProperties family;
939             env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &returned_family_count, &family);
940             ASSERT_EQ(returned_family_count, family_count);
941             ASSERT_EQ(family.queueFlags, static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT));
942             ASSERT_EQ(family.queueCount, family_count);
943             ASSERT_EQ(family.timestampValidBits, 0U);
944 
945             DeviceCreateInfo dev_create_info;
946             dev_create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
947 
948             result = env.vulkan_functions.vkCreateDevice(physical_devices[i], dev_create_info.get(), tracker.get(), &devices[i]);
949 
950             VkQueue queue;
951             if (result == VK_SUCCESS) {
952                 env.vulkan_functions.vkGetDeviceQueue(devices[i], 0, 0, &queue);
953             }
954         }
955         for (uint32_t i = 0; i < returned_physical_count; i++) {
956             if (result == VK_SUCCESS) {
957                 env.vulkan_functions.vkDestroyDevice(devices[i], tracker.get());
958             }
959         }
960 
961         env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
962         ASSERT_TRUE(tracker.empty());
963         reached_the_end = true;
964     }
965 }
966 #if defined(WIN32)
967 // Test failure during vkCreateInstance and vkCreateDevice to make sure we don't
968 // leak memory if one of the out-of-memory conditions trigger.
TEST(Allocation, CreateInstanceDeviceWithDXGIDriverIntentionalAllocFail)969 TEST(Allocation, CreateInstanceDeviceWithDXGIDriverIntentionalAllocFail) {
970     FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("error,warn")};
971     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6).set_discovery_type(ManifestDiscoveryType::null_dir));
972     env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
973 
974     for (uint32_t i = 0; i < 2; i++) {
975         auto& driver = env.get_test_icd(i);
976         driver.physical_devices.emplace_back(std::string("physical_device_") + std::to_string(i))
977             .add_queue_family_properties({{VK_QUEUE_GRAPHICS_BIT, 1, 0, {1, 1, 1}}, false});
978     }
979 
980     const char* layer_name = "VK_LAYER_implicit";
981     env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
982                                                          .set_name(layer_name)
983                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
984                                                          .set_disable_environment("DISABLE_ENV")),
985                            "test_layer.json");
986     env.get_test_layer().set_do_spurious_allocations_in_create_instance(true).set_do_spurious_allocations_in_create_device(true);
987 
988     auto& known_driver = known_driver_list.at(2);  // which drive this test pretends to be
989     DXGI_ADAPTER_DESC1 desc1{};
990     desc1.VendorId = known_driver.vendor_id;
991     desc1.AdapterLuid = _LUID{10, 1000};
992     env.platform_shim->add_dxgi_adapter(GpuType::discrete, desc1);
993     env.get_test_icd(0).set_adapterLUID(desc1.AdapterLuid);
994 
995     env.platform_shim->add_d3dkmt_adapter(D3DKMT_Adapter{0, _LUID{10, 1000}}.add_driver_manifest_path(env.get_icd_manifest_path()));
996 
997     size_t fail_index = 0;
998     VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
999     while (result == VK_ERROR_OUT_OF_HOST_MEMORY && fail_index <= 10000) {
1000         MemoryTracker tracker({false, 0, true, fail_index});
1001         fail_index++;  // applies to the next loop
1002 
1003         VkInstance instance;
1004         InstanceCreateInfo inst_create_info{};
1005         result = env.vulkan_functions.vkCreateInstance(inst_create_info.get(), tracker.get(), &instance);
1006         if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
1007             ASSERT_TRUE(tracker.empty());
1008             continue;
1009         }
1010 
1011         uint32_t physical_count = 2;
1012         uint32_t returned_physical_count = 0;
1013         result = env.vulkan_functions.vkEnumeratePhysicalDevices(instance, &returned_physical_count, nullptr);
1014         if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_INCOMPLETE) {
1015             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
1016             ASSERT_TRUE(tracker.empty());
1017             continue;
1018         }
1019         ASSERT_EQ(physical_count, returned_physical_count);
1020 
1021         std::array<VkPhysicalDevice, 2> physical_devices;
1022         result = env.vulkan_functions.vkEnumeratePhysicalDevices(instance, &returned_physical_count, physical_devices.data());
1023         if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_INCOMPLETE) {
1024             env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
1025             ASSERT_TRUE(tracker.empty());
1026             continue;
1027         }
1028         ASSERT_EQ(physical_count, returned_physical_count);
1029 
1030         std::array<VkDevice, 2> devices;
1031         for (uint32_t i = 0; i < returned_physical_count; i++) {
1032             uint32_t family_count = 1;
1033             uint32_t returned_family_count = 0;
1034             env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &returned_family_count, nullptr);
1035             ASSERT_EQ(returned_family_count, family_count);
1036 
1037             VkQueueFamilyProperties family;
1038             env.vulkan_functions.vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &returned_family_count, &family);
1039             ASSERT_EQ(returned_family_count, family_count);
1040             ASSERT_EQ(family.queueFlags, static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT));
1041             ASSERT_EQ(family.queueCount, family_count);
1042             ASSERT_EQ(family.timestampValidBits, 0U);
1043 
1044             DeviceCreateInfo dev_create_info;
1045             dev_create_info.add_device_queue(DeviceQueueCreateInfo{}.add_priority(0.0f));
1046 
1047             result = env.vulkan_functions.vkCreateDevice(physical_devices[i], dev_create_info.get(), tracker.get(), &devices[i]);
1048             if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
1049                 devices[i] = VK_NULL_HANDLE;
1050             } else {
1051                 VkQueue queue;
1052                 env.vulkan_functions.vkGetDeviceQueue(devices[i], 0, 0, &queue);
1053             }
1054         }
1055         for (uint32_t i = 0; i < returned_physical_count; i++) {
1056             if (devices[i] != VK_NULL_HANDLE) {
1057                 env.vulkan_functions.vkDestroyDevice(devices[i], tracker.get());
1058             }
1059         }
1060         env.vulkan_functions.vkDestroyInstance(instance, tracker.get());
1061 
1062         ASSERT_TRUE(tracker.empty());
1063     }
1064 }
1065 #endif
1066