diff options
| author | Gabríel Arthúr Pétursson <gabriel@system.is> | 2018-03-20 21:52:06 +0000 |
|---|---|---|
| committer | Dave Houlton <daveh@lunarg.com> | 2018-04-04 16:16:14 -0600 |
| commit | e86bb48e0aa57fb85865447c8d573cc724d71920 (patch) | |
| tree | 1e6ef9310b828dc70ac44bab518ea562a000a109 | |
| parent | bd6c0d64e053529cf7947582a5b960bcfee538e6 (diff) | |
| download | usermoji-e86bb48e0aa57fb85865447c8d573cc724d71920.tar.xz | |
layers: Destroy object tracking after reporting undestroyed objects
Fixes a memleak in VkLayerTest.LeakAnObject.
| -rw-r--r-- | layers/object_tracker.h | 35 | ||||
| -rw-r--r-- | layers/object_tracker_utils.cpp | 17 | ||||
| -rw-r--r-- | scripts/object_tracker_generator.py | 18 |
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() |
