aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabríel Arthúr Pétursson <gabriel@system.is>2018-03-20 21:52:06 +0000
committerDave Houlton <daveh@lunarg.com>2018-04-04 16:16:14 -0600
commite86bb48e0aa57fb85865447c8d573cc724d71920 (patch)
tree1e6ef9310b828dc70ac44bab518ea562a000a109
parentbd6c0d64e053529cf7947582a5b960bcfee538e6 (diff)
downloadusermoji-e86bb48e0aa57fb85865447c8d573cc724d71920.tar.xz
layers: Destroy object tracking after reporting undestroyed objects
Fixes a memleak in VkLayerTest.LeakAnObject.
-rw-r--r--layers/object_tracker.h35
-rw-r--r--layers/object_tracker_utils.cpp17
-rw-r--r--scripts/object_tracker_generator.py18
3 files changed, 59 insertions, 11 deletions
diff --git a/layers/object_tracker.h b/layers/object_tracker.h
index c7f79619..48ac9fae 100644
--- a/layers/object_tracker.h
+++ b/layers/object_tracker.h
@@ -140,6 +140,7 @@ extern uint32_t loader_layer_if_version;
extern const std::unordered_map<std::string, void *> name_to_funcptr_map;
void DeviceReportUndestroyedObjects(VkDevice device, VulkanObjectType object_type, enum UNIQUE_VALIDATION_ERROR_CODE error_code);
+void DeviceDestroyUndestroyedObjects(VkDevice device, VulkanObjectType object_type);
void CreateQueue(VkDevice device, VkQueue vkObj);
void AddQueueInfo(VkDevice device, uint32_t queue_node_index, VkQueue queue);
void ValidateQueueFlags(VkQueue queue, const char *function);
@@ -148,6 +149,7 @@ void AllocateCommandBuffer(VkDevice device, const VkCommandPool command_pool, co
void AllocateDescriptorSet(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set);
void CreateSwapchainImageObject(VkDevice dispatchable_object, VkImage swapchain_image, VkSwapchainKHR swapchain);
void ReportUndestroyedObjects(VkDevice device, UNIQUE_VALIDATION_ERROR_CODE error_code);
+void DestroyUndestroyedObjects(VkDevice device);
bool ValidateDeviceObject(uint64_t device_handle, enum UNIQUE_VALIDATION_ERROR_CODE invalid_handle_code,
enum UNIQUE_VALIDATION_ERROR_CODE wrong_device_code);
@@ -224,6 +226,28 @@ void CreateObject(T1 dispatchable_object, T2 object, VulkanObjectType object_typ
}
template <typename T1, typename T2>
+void DestroyObjectSilently(T1 dispatchable_object, T2 object, VulkanObjectType object_type) {
+ layer_data *device_data = GetLayerDataPtr(get_dispatch_key(dispatchable_object), layer_data_map);
+
+ auto object_handle = HandleToUint64(object);
+ assert(object_handle != VK_NULL_HANDLE);
+
+ auto item = device_data->object_map[object_type].find(object_handle);
+ assert(item != device_data->object_map[object_type].end());
+
+ ObjTrackState *pNode = item->second;
+ assert(device_data->num_total_objects > 0);
+
+ device_data->num_total_objects--;
+ assert(device_data->num_objects[pNode->object_type] > 0);
+
+ device_data->num_objects[pNode->object_type]--;
+
+ delete pNode;
+ device_data->object_map[object_type].erase(item);
+}
+
+template <typename T1, typename T2>
void DestroyObject(T1 dispatchable_object, T2 object, VulkanObjectType object_type, const VkAllocationCallbacks *pAllocator,
enum UNIQUE_VALIDATION_ERROR_CODE expected_custom_allocator_code,
enum UNIQUE_VALIDATION_ERROR_CODE expected_default_allocator_code) {
@@ -237,15 +261,11 @@ void DestroyObject(T1 dispatchable_object, T2 object, VulkanObjectType object_ty
auto item = device_data->object_map[object_type].find(object_handle);
if (item != device_data->object_map[object_type].end()) {
ObjTrackState *pNode = item->second;
- assert(device_data->num_total_objects > 0);
- device_data->num_total_objects--;
- assert(device_data->num_objects[pNode->object_type] > 0);
- device_data->num_objects[pNode->object_type]--;
log_msg(device_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, debug_object_type, object_handle, OBJTRACK_NONE,
"OBJ_STAT Destroy %s obj 0x%" PRIxLEAST64 " (%" PRIu64 " total objs remain & %" PRIu64 " %s objs).",
- object_string[object_type], HandleToUint64(object), device_data->num_total_objects,
- device_data->num_objects[pNode->object_type], object_string[object_type]);
+ object_string[object_type], HandleToUint64(object), device_data->num_total_objects - 1,
+ device_data->num_objects[pNode->object_type] - 1, object_string[object_type]);
auto allocated_with_custom = (pNode->status & OBJSTATUS_CUSTOM_ALLOCATOR) ? true : false;
if (allocated_with_custom && !custom_allocator && expected_custom_allocator_code != VALIDATION_ERROR_UNDEFINED) {
@@ -263,8 +283,7 @@ void DestroyObject(T1 dispatchable_object, T2 object, VulkanObjectType object_ty
object_string[object_type], object_handle);
}
- delete pNode;
- device_data->object_map[object_type].erase(item);
+ DestroyObjectSilently(dispatchable_object, object, object_type);
} else {
log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, object_handle,
OBJTRACK_UNKNOWN_OBJECT,
diff --git a/layers/object_tracker_utils.cpp b/layers/object_tracker_utils.cpp
index 00aa3e64..cb0f4c58 100644
--- a/layers/object_tracker_utils.cpp
+++ b/layers/object_tracker_utils.cpp
@@ -303,12 +303,21 @@ void CreateSwapchainImageObject(VkDevice dispatchable_object, VkImage swapchain_
void DeviceReportUndestroyedObjects(VkDevice device, VulkanObjectType object_type, enum UNIQUE_VALIDATION_ERROR_CODE error_code) {
layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
- for (auto item = device_data->object_map[object_type].begin(); item != device_data->object_map[object_type].end();) {
- ObjTrackState *object_info = item->second;
+ for (const auto &item : device_data->object_map[object_type]) {
+ const ObjTrackState *object_info = item.second;
log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object_type], object_info->handle,
error_code, "OBJ ERROR : For device 0x%" PRIxLEAST64 ", %s object 0x%" PRIxLEAST64 " has not been destroyed.",
HandleToUint64(device), object_string[object_type], object_info->handle);
- item = device_data->object_map[object_type].erase(item);
+ }
+}
+
+void DeviceDestroyUndestroyedObjects(VkDevice device, VulkanObjectType object_type) {
+ layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+ while (!device_data->object_map[object_type].empty()) {
+ auto item = device_data->object_map[object_type].begin();
+
+ ObjTrackState *object_info = item->second;
+ DestroyObjectSilently(device, object_info->handle, object_type);
}
}
@@ -356,6 +365,7 @@ VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocati
// Report any remaining objects in LL
ReportUndestroyedObjects(device, VALIDATION_ERROR_258004ea);
+ DestroyUndestroyedObjects(device);
DestroyObject(instance, device, kVulkanObjectTypeDevice, pAllocator, VALIDATION_ERROR_258004ec, VALIDATION_ERROR_258004ee);
iit = instance_data->object_map[kVulkanObjectTypeDevice].begin();
@@ -411,6 +421,7 @@ VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCall
// Report any remaining objects associated with this VkDevice object in LL
ReportUndestroyedObjects(device, VALIDATION_ERROR_24a002f4);
+ DestroyUndestroyedObjects(device);
// Clean up Queue's MemRef Linked Lists
DestroyQueueDataStructures(device);
diff --git a/scripts/object_tracker_generator.py b/scripts/object_tracker_generator.py
index e5475ec7..00b9bcd6 100644
--- a/scripts/object_tracker_generator.py
+++ b/scripts/object_tracker_generator.py
@@ -331,6 +331,7 @@ class ObjectTrackerOutputGenerator(OutputGenerator):
# Check if the parameter passed in is a pointer to an array
def paramIsArray(self, param):
return param.attrib.get('len') is not None
+
#
# Generate the object tracker undestroyed object validation function
def GenReportFunc(self):
@@ -342,6 +343,19 @@ class ObjectTrackerOutputGenerator(OutputGenerator):
output_func += ' DeviceReportUndestroyedObjects(device, %s, error_code);\n' % (self.GetVulkanObjType(handle))
output_func += '}\n'
return output_func
+
+ #
+ # Generate the object tracker undestroyed object destruction function
+ def GenDestroyFunc(self):
+ output_func = ''
+ output_func += 'void DestroyUndestroyedObjects(VkDevice device) {\n'
+ output_func += ' DeviceDestroyUndestroyedObjects(device, kVulkanObjectTypeCommandBuffer);\n'
+ for handle in self.object_types:
+ if self.isHandleTypeNonDispatchable(handle):
+ output_func += ' DeviceDestroyUndestroyedObjects(device, %s);\n' % (self.GetVulkanObjType(handle))
+ output_func += '}\n'
+ return output_func
+
#
# Called at beginning of processing as file is opened
def beginFile(self, genOpts):
@@ -401,8 +415,12 @@ class ObjectTrackerOutputGenerator(OutputGenerator):
# Build undestroyed objects reporting function
report_func = self.GenReportFunc()
self.newline()
+ # Build undestroyed objects destruction function
+ destroy_func = self.GenDestroyFunc()
+ self.newline()
write('// ObjectTracker undestroyed objects validation function', file=self.outFile)
write('%s' % report_func, file=self.outFile)
+ write('%s' % destroy_func, file=self.outFile)
# Actually write the interface to the output file.
if (self.emit):
self.newline()