layers: Avoid reading pointer to array when count is zero
Take for example VkSubmitInfo. It has, amongst others, two fields:
waitSemaphoreCount and pWaitSemaphores. The specification states that
if waitSemaphoreCount is zero, the application may leave pWaitSemaphores
uninitialized (in essence, that field is ignored).
The layers read that value anyway, triggering uninitialized read errors
by memory sanitization tools.
Fixes uninitialized read in QueueSubmitSemaphoresAndLayoutTracking.
diff --git a/layers/parameter_validation.h b/layers/parameter_validation.h
index 675d224..15ebcbf 100644
--- a/layers/parameter_validation.h
+++ b/layers/parameter_validation.h
@@ -227,9 +227,9 @@
* @param arrayRequired The 'array' parameter may not be NULL when true.
* @return Boolean value indicating that the call should be skipped.
*/
-template <typename T>
+template <typename T1, typename T2>
bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
- const ParameterName &arrayName, T count, const void *array, bool countRequired, bool arrayRequired,
+ const ParameterName &arrayName, T1 count, const T2 *array, bool countRequired, bool arrayRequired,
UNIQUE_VALIDATION_ERROR_CODE count_required_vuid, UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
bool skip_call = false;
@@ -241,7 +241,7 @@
}
// Array parameters not tagged as optional cannot be NULL, unless the count is 0
- if ((array == NULL) && arrayRequired && (count != 0)) {
+ if (arrayRequired && (count != 0) && (*array == NULL)) {
skip_call |=
log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, array_required_vuid,
"%s: required parameter %s specified as NULL.", apiName, arrayName.get_name().c_str());
@@ -270,9 +270,9 @@
* @param arrayRequired The 'array' parameter may not be NULL when true.
* @return Boolean value indicating that the call should be skipped.
*/
-template <typename T>
+template <typename T1, typename T2>
bool validate_array(debug_report_data *report_data, const char *apiName, const ParameterName &countName,
- const ParameterName &arrayName, const T *count, const void *array, bool countPtrRequired,
+ const ParameterName &arrayName, const T1 *count, const T2 *array, bool countPtrRequired,
bool countValueRequired, bool arrayRequired, UNIQUE_VALIDATION_ERROR_CODE count_required_vuid,
UNIQUE_VALIDATION_ERROR_CODE array_required_vuid) {
bool skip_call = false;
@@ -284,7 +284,7 @@
"%s: required parameter %s specified as NULL", apiName, countName.get_name().c_str());
}
} else {
- skip_call |= validate_array(report_data, apiName, countName, arrayName, array ? (*count) : 0, array, countValueRequired,
+ skip_call |= validate_array(report_data, apiName, countName, arrayName, *array ? (*count) : 0, &array, countValueRequired,
arrayRequired, count_required_vuid, array_required_vuid);
}
@@ -353,7 +353,7 @@
bool skip_call = false;
if ((count == 0) || (array == NULL)) {
- skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
+ skip_call |= validate_array(report_data, apiName, countName, arrayName, count, &array, countRequired, arrayRequired,
VALIDATION_ERROR_UNDEFINED, vuid);
} else {
// Verify that all structs in the array have the correct type
@@ -464,7 +464,7 @@
bool skip_call = false;
if ((count == 0) || (array == NULL)) {
- skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required,
+ skip_call |= validate_array(report_data, api_name, count_name, array_name, count, &array, count_required, array_required,
VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
} else {
// Verify that no handles in the array are VK_NULL_HANDLE
@@ -505,7 +505,7 @@
bool skip_call = false;
if ((count == 0) || (array == NULL)) {
- skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
+ skip_call |= validate_array(report_data, apiName, countName, arrayName, count, &array, countRequired, arrayRequired,
count_required_vuid, array_required_vuid);
} else {
// Verify that strings in the array are not NULL
@@ -700,7 +700,7 @@
bool skip_call = false;
if ((count == 0) || (array == NULL)) {
- skip_call |= validate_array(report_data, apiName, countName, arrayName, count, array, countRequired, arrayRequired,
+ skip_call |= validate_array(report_data, apiName, countName, arrayName, count, &array, countRequired, arrayRequired,
VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
} else {
for (uint32_t i = 0; i < count; ++i) {
@@ -805,7 +805,7 @@
bool skip_call = false;
if ((count == 0) || (array == NULL)) {
- skip_call |= validate_array(report_data, api_name, count_name, array_name, count, array, count_required, array_required,
+ skip_call |= validate_array(report_data, api_name, count_name, array_name, count, &array, count_required, array_required,
VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
} else {
// Verify that all VkFlags values in the array
diff --git a/layers/parameter_validation_utils.cpp b/layers/parameter_validation_utils.cpp
index b9adf03..ba071d8 100644
--- a/layers/parameter_validation_utils.cpp
+++ b/layers/parameter_validation_utils.cpp
@@ -1599,7 +1599,7 @@
report_data, "vkCreateGraphicsPipelines",
ParameterName("pCreateInfos[%i].pMultisampleState->rasterizationSamples", ParameterName::IndexVector{i}),
ParameterName("pCreateInfos[%i].pMultisampleState->pSampleMask", ParameterName::IndexVector{i}),
- pCreateInfos[i].pMultisampleState->rasterizationSamples, pCreateInfos[i].pMultisampleState->pSampleMask,
+ pCreateInfos[i].pMultisampleState->rasterizationSamples, &pCreateInfos[i].pMultisampleState->pSampleMask,
true, false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
skip |= validate_bool32(
@@ -1765,7 +1765,7 @@
report_data, "vkCreateGraphicsPipelines",
ParameterName("pCreateInfos[%i].pColorBlendState->attachmentCount", ParameterName::IndexVector{i}),
ParameterName("pCreateInfos[%i].pColorBlendState->pAttachments", ParameterName::IndexVector{i}),
- pCreateInfos[i].pColorBlendState->attachmentCount, pCreateInfos[i].pColorBlendState->pAttachments, false,
+ pCreateInfos[i].pColorBlendState->attachmentCount, &pCreateInfos[i].pColorBlendState->pAttachments, false,
true, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
if (pCreateInfos[i].pColorBlendState->pAttachments != NULL) {
@@ -2054,7 +2054,7 @@
// This is an array of handles, where the elements are allowed to be VK_NULL_HANDLE, and does not require any validation beyond
// validate_array()
skip |= validate_array(report_data, "vkFreeDescriptorSets", "descriptorSetCount", "pDescriptorSets", descriptorSetCount,
- pDescriptorSets, true, true, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
+ &pDescriptorSets, true, true, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
return skip;
}
@@ -2238,7 +2238,7 @@
// This is an array of handles, where the elements are allowed to be VK_NULL_HANDLE, and does not require any validation beyond
// validate_array()
skip |= validate_array(report_data, "vkFreeCommandBuffers", "commandBufferCount", "pCommandBuffers", commandBufferCount,
- pCommandBuffers, true, true, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
+ &pCommandBuffers, true, true, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
return skip;
}
@@ -2639,7 +2639,7 @@
instance_layer_data *local_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
bool skip =
validate_array(local_data->report_data, "vkEnumerateDeviceExtensionProperties", "pPropertyCount", "pProperties",
- pPropertyCount, pProperties, true, false, false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_2761f401);
+ pPropertyCount, &pProperties, true, false, false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_2761f401);
if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
return local_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pPropertyCount, pProperties);
@@ -2742,12 +2742,12 @@
skip |= validate_struct_pnext(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->pNext", NULL,
present_regions->pNext, 0, NULL, GeneratedHeaderVersion, VALIDATION_ERROR_1121c40d);
skip |= validate_array(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->swapchainCount",
- "pCreateInfo->pNext->pRegions", present_regions->swapchainCount, present_regions->pRegions, true,
- false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
+ "pCreateInfo->pNext->pRegions", present_regions->swapchainCount, &present_regions->pRegions,
+ true, false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
skip |= validate_array(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->pRegions[].rectangleCount",
"pCreateInfo->pNext->pRegions[].pRectangles", present_regions->pRegions[i].rectangleCount,
- present_regions->pRegions[i].pRectangles, true, false, VALIDATION_ERROR_UNDEFINED,
+ &present_regions->pRegions[i].pRectangles, true, false, VALIDATION_ERROR_UNDEFINED,
VALIDATION_ERROR_UNDEFINED);
}
}
diff --git a/scripts/object_tracker_generator.py b/scripts/object_tracker_generator.py
index 00b9bcd..5130e0f 100644
--- a/scripts/object_tracker_generator.py
+++ b/scripts/object_tracker_generator.py
@@ -744,15 +744,11 @@
commonparent_vuid_string = 'VUID-%s-commonparent' % parent_name
parent_vuid = self.GetVuid(commonparent_vuid_string)
if obj_count is not None:
- pre_call_code += '%s if (%s%s) {\n' % (indent, prefix, obj_name)
- indent = self.incIndent(indent)
pre_call_code += '%s for (uint32_t %s = 0; %s < %s; ++%s) {\n' % (indent, index, index, obj_count, index)
indent = self.incIndent(indent)
pre_call_code += '%s skip |= ValidateObject(%s, %s%s[%s], %s, %s, %s, %s);\n' % (indent, disp_name, prefix, obj_name, index, self.GetVulkanObjType(obj_type), null_allowed, param_vuid, parent_vuid)
indent = self.decIndent(indent)
pre_call_code += '%s }\n' % indent
- indent = self.decIndent(indent)
- pre_call_code += '%s }\n' % indent
else:
pre_call_code += '%s skip |= ValidateObject(%s, %s%s, %s, %s, %s, %s);\n' % (indent, disp_name, prefix, obj_name, self.GetVulkanObjType(obj_type), null_allowed, param_vuid, parent_vuid)
return decl_code, pre_call_code, post_call_code
diff --git a/scripts/parameter_validation_generator.py b/scripts/parameter_validation_generator.py
index ecb98ff..44c6576 100644
--- a/scripts/parameter_validation_generator.py
+++ b/scripts/parameter_validation_generator.py
@@ -873,14 +873,14 @@
# If count and array parameters are optional, there will be no validation
if valueRequired == 'true' or lenPtrRequired == 'true' or lenValueRequired == 'true':
# When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required
- checkExpr.append('skip |= validate_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {}, {}, {}, {});\n'.format(
+ checkExpr.append('skip |= validate_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {}, {});\n'.format(
funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
# This is an array with an integer count value
else:
# If count and array parameters are optional, there will be no validation
if valueRequired == 'true' or lenValueRequired == 'true':
if value.type != 'char':
- checkExpr.append('skip |= validate_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {}, {}, {});\n'.format(
+ checkExpr.append('skip |= validate_array(local_data->report_data, "{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {});\n'.format(
funcPrintName, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec))
else:
# Arrays of strings receive special processing