Call DestroyInstance on each driver in error path
authorCharles Giessen <charles@lunarg.com>
Sat, 25 Feb 2023 01:09:47 +0000 (18:09 -0700)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Mon, 27 Feb 2023 20:41:16 +0000 (13:41 -0700)
If CreateInstance successfully calls terminator_CreateInstance but subsequently fails on the way
back up the chain, the loader should call DestroyInstance on each driver to give them a chance to
clean up. This path is possible during CTS OOM tests which cause VVL to fail which then causes
leaks to occur.

Additionally, the layer name allocations needed to be cleaned up in this error
path as well, since there is no chance for vkDestroyInstance to run.

loader/loader.c
loader/trampoline.c

index ac2843c64b97e73a6cff728cd87d047e59065a93..d9e6230bbb6c90d8ec7870ced7a4e55371ebaeab 100644 (file)
@@ -647,6 +647,7 @@ void loader_destroy_generic_list(const struct loader_instance *inst, struct load
     loader_instance_heap_free(inst, list->list);
     list->count = 0;
     list->capacity = 0;
+    list->list = NULL;
 }
 
 // Append non-duplicate extension properties defined in props to the given ext_list.
index 7a3901a78f65430c0044ca355844138908c1a7a3..f264e53dbe6de6dd230987148a7638e4fd407a51 100644 (file)
@@ -632,10 +632,25 @@ out:
             struct loader_icd_term *icd_term = NULL;
             while (NULL != ptr_instance->icd_terms) {
                 icd_term = ptr_instance->icd_terms;
+                // Call destroy Instance on each driver in case we successfully called down the chain but failed on
+                // our way back out of it.
+                if (icd_term->instance) {
+                    icd_term->dispatch.DestroyInstance(icd_term->instance, pAllocator);
+                }
+                icd_term->instance = VK_NULL_HANDLE;
                 ptr_instance->icd_terms = icd_term->next;
                 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
             }
 
+            for (uint32_t i = 0, n = ptr_instance->enabled_layer_count; i < n; ++i) {
+                loader_instance_heap_free(ptr_instance, ptr_instance->enabled_layer_names[i]);
+            }
+
+            if (ptr_instance->enabled_layer_count > 0) {
+                loader_instance_heap_free(ptr_instance, ptr_instance->enabled_layer_names);
+                memset(&ptr_instance->enabled_layer_names, 0, sizeof(ptr_instance->enabled_layer_names));
+            }
+
             loader_instance_heap_free(ptr_instance, ptr_instance);
         } else {
             // success path, swap out created debug callbacks out so they aren't used until instance destruction