layers: Simplify generated param validation code
- Remove unnecessary conditional checks for input vs. output parameters
from the generated C++ code.
- Split some generator code into smaller functions.
Change-Id: I32e47d417ab884e5cc0fc7af40cb5657b39c176d
diff --git a/generator.py b/generator.py
index c2ee28e..a96ada8 100644
--- a/generator.py
+++ b/generator.py
@@ -2835,12 +2835,6 @@
diagFile = sys.stdout):
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
self.INDENT_SPACES = 4
- # Struct member categories, to be used to avoid validating output values retrieved by queries such as vkGetPhysicalDeviceProperties
- # For example, VkPhysicalDeviceProperties will be ignored for vkGetPhysicalDeviceProperties where it is an ouput, but will be processed
- # for vkCreateDevice where is it a member of the VkDeviceCreateInfo input parameter.
- self.STRUCT_MEMBERS_INPUT_ONLY_NONE = 1 # The struct contains no 'input-only' members and will always be processed
- self.STRUCT_MEMBERS_INPUT_ONLY_MIXED = 2 # The struct contains some 'input-only' members; these members will only be processed when the struct is an input parameter
- self.STRUCT_MEMBERS_INPUT_ONLY_EXCLUSIVE = 3 # The struct contains only 'input-only' members; the entire struct will only be processed when it is an input parameter
# Commands to ignore
self.blacklist = [
'vkGetInstanceProcAddr',
@@ -2858,8 +2852,7 @@
self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType
self.commands = [] # List of CommandData records for all Vulkan commands
self.structMembers = [] # List of StructMemberData records for all Vulkan structs
- self.validatedStructs = dict() # Map of structs containing members that require validation to a value indicating
- # that the struct contains members that are only validated when it is an input parameter
+ self.validatedStructs = set() # Set of structs containing members that require validation
self.enumRanges = dict() # Map of enum name to BEGIN/END range values
# Named tuples to store struct and command data
self.StructType = namedtuple('StructType', ['name', 'value'])
@@ -2929,7 +2922,7 @@
self.structTypes = dict()
self.commands = []
self.structMembers = []
- self.validatedStructs = dict()
+ self.validatedStructs = set()
self.enumRanges = dict()
def endFeature(self):
# C-specific
@@ -3243,52 +3236,116 @@
#
# Generate the code to check for a NULL dereference before calling the
# validation function
- def genCheckedLengthCall(self, indent, name, expr):
+ def genCheckedLengthCall(self, name, exprs):
count = name.count('->')
if count:
- checkedExpr = ''
- localIndent = indent
+ checkedExpr = []
+ localIndent = ''
elements = name.split('->')
# Open the if expression blocks
for i in range(0, count):
- checkedExpr += localIndent + 'if ({} != NULL) {{\n'.format('->'.join(elements[0:i+1]))
+ checkedExpr.append(localIndent + 'if ({} != NULL) {{\n'.format('->'.join(elements[0:i+1])))
localIndent = self.incIndent(localIndent)
# Add the validation expression
- checkedExpr += localIndent + expr
+ for expr in exprs:
+ checkedExpr.append(localIndent + expr)
# Close the if blocks
for i in range(0, count):
localIndent = self.decIndent(localIndent)
- checkedExpr += localIndent + '}\n'
- return checkedExpr
+ checkedExpr.append(localIndent + '}\n')
+ return [checkedExpr]
# No if statements were required
- return indent + expr
+ return exprs
+ #
+ # Generate the sType check string
+ def makeStructTypeCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, lenPtrRequired, funcPrintName, lenPrintName, valuePrintName):
+ checkExpr = []
+ stype = self.structTypes[value.type]
+ if lenValue:
+ # This is an array with a pointer to a count value
+ if lenValue.ispointer:
+ # 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('skipCall |= validate_struct_type_array(report_data, {}, {ldn}, {dn}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {});\n'.format(
+ funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype.value, pf=prefix))
+ # This is an array with an integer count value
+ else:
+ checkExpr.append('skipCall |= validate_struct_type_array(report_data, {}, {ldn}, {dn}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {});\n'.format(
+ funcPrintName, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype.value, pf=prefix))
+ # This is an individual struct
+ else:
+ checkExpr.append('skipCall |= validate_struct_type(report_data, {}, {}, "{sv}", {}{vn}, {sv}, {});\n'.format(
+ funcPrintName, valuePrintName, prefix, valueRequired, vn=value.name, sv=stype.value))
+ return checkExpr
+ #
+ # Generate pNext check string
+ def makeStructNextCheck(self, prefix, value, funcPrintName, valuePrintName):
+ checkExpr = []
+ # Generate an array of acceptable VkStructureType values for pNext
+ extStructCount = 0
+ extStructVar = 'NULL'
+ extStructNames = 'NULL'
+ if value.extstructs:
+ structs = value.extstructs.split(',')
+ checkExpr.append('const VkStructureType allowedStructs[] = {' + ', '.join([self.structTypes[s].value for s in structs]) + '};\n')
+ extStructCount = 'ARRAY_SIZE(allowedStructs)'
+ extStructVar = 'allowedStructs'
+ extStructNames = '"' + ', '.join(structs) + '"'
+ checkExpr.append('skipCall |= validate_struct_pnext(report_data, {}, {}, {}, {}{}, {}, {});\n'.format(
+ funcPrintName, valuePrintName, extStructNames, prefix, value.name, extStructCount, extStructVar))
+ return checkExpr
+ #
+ # Generate the pointer check string
+ def makePointerCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, lenPtrRequired, funcPrintName, lenPrintName, valuePrintName):
+ checkExpr = []
+ if lenValue:
+ # This is an array with a pointer to a count value
+ if lenValue.ispointer:
+ # 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('skipCall |= validate_array(report_data, {}, {ldn}, {dn}, {pf}{ln}, {pf}{vn}, {}, {}, {});\n'.format(
+ funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix))
+ # 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':
+ # Arrays of strings receive special processing
+ funcName = 'validate_array' if value.type != 'char' else 'validate_string_array'
+ checkExpr.append('skipCall |= {}(report_data, {}, {ldn}, {dn}, {pf}{ln}, {pf}{vn}, {}, {});\n'.format(
+ funcName, funcPrintName, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix))
+ if checkExpr:
+ if lenValue and ('->' in lenValue.name):
+ # Add checks to ensure the validation call does not dereference a NULL pointer to obtain the count
+ checkExpr = self.genCheckedLengthCall(lenValue.name, checkExpr)
+ # This is an individual struct that is not allowed to be NULL
+ elif not value.isoptional:
+ # Function pointers need a reinterpret_cast to void*
+ if value.type[:4] == 'PFN_':
+ checkExpr.append('skipCall |= validate_required_pointer(report_data, {}, {}, reinterpret_cast<const void*>({}{}));\n'.format(funcPrintName, valuePrintName, prefix, value.name))
+ else:
+ checkExpr.append('skipCall |= validate_required_pointer(report_data, {}, {}, {}{});\n'.format(funcPrintName, valuePrintName, prefix, value.name))
+ return checkExpr
#
# Generate the parameter checking code
- def genFuncBody(self, indent, name, values, valuePrefix, variablePrefix, structName, needConditionCheck):
- funcBody = ''
- unused = []
- # Code to conditionally check parameters only when they are inputs. Primarily avoids
- # checking uninitialized members of output structs used to retrieve bools and enums.
- # Conditional checks are grouped together to be appended to funcBody within a single
- # if check for input parameter direction.
- conditionalExprs = []
+ def genFuncBody(self, funcName, values, valuePrefix, displayNamePrefix, structTypeName):
+ lines = [] # Generated lines of code
+ unused = [] # Unused variable names
for value in values:
- checkExpr = '' # Code to check the current parameter
+ usedAlways = []
+ usedOnInput = []
lenParam = None
#
- # Generate the full name of the value, which will be printed in
- # the error message, by adding the variable prefix to the
- # value name
- valueDisplayName = '(std::string({}) + std::string("{}")).c_str()'.format(variablePrefix, value.name) if variablePrefix else '"{}"'.format(value.name)
+ # Generate the full name of the value, which will be printed in the error message, by adding the variable prefix to the value name
+ valueDisplayName = '(std::string({}) + std::string("{}")).c_str()'.format(displayNamePrefix, value.name) if displayNamePrefix else '"{}"'.format(value.name)
#
# Check for NULL pointers, ignore the inout count parameters that
# will be validated with their associated array
if (value.ispointer or value.isstaticarray) and not value.iscount:
#
# Parameters for function argument generation
- req = 'true' # Paramerter can be NULL
- cpReq = 'true' # Count pointer can be NULL
- cvReq = 'true' # Count value can be 0
+ req = 'true' # Paramerter cannot be NULL
+ cpReq = 'true' # Count pointer cannot be NULL
+ cvReq = 'true' # Count value cannot be 0
lenDisplayName = None # Name of length parameter to print with validation messages; parameter name with prefix applied
#
# Generate required/optional parameter strings for the pointer and count values
@@ -3297,7 +3354,7 @@
if value.len:
# The parameter is an array with an explicit count parameter
lenParam = self.getLenParam(values, value.len)
- lenDisplayName = '(std::string({}) + std::string("{}")).c_str()'.format(variablePrefix, lenParam.name) if variablePrefix else '"{}"'.format(lenParam.name)
+ lenDisplayName = '(std::string({}) + std::string("{}")).c_str()'.format(displayNamePrefix, lenParam.name) if displayNamePrefix else '"{}"'.format(lenParam.name)
if lenParam.ispointer:
# Count parameters that are pointers are inout
if type(lenParam.isoptional) is list:
@@ -3314,207 +3371,73 @@
#
# If this is a pointer to a struct with an sType field, verify the type
if value.type in self.structTypes:
- stype = self.structTypes[value.type]
- if lenParam:
- # This is an array
- if lenParam.ispointer:
- # When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required
- checkExpr = 'skipCall |= validate_struct_type_array(report_data, {}, {ldn}, {dn}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {});\n'.format(name, cpReq, cvReq, req, ln=lenParam.name, ldn=lenDisplayName, dn=valueDisplayName, vn=value.name, sv=stype.value, pf=valuePrefix)
- else:
- checkExpr = 'skipCall |= validate_struct_type_array(report_data, {}, {ldn}, {dn}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {});\n'.format(name, cvReq, req, ln=lenParam.name, ldn=lenDisplayName, dn=valueDisplayName, vn=value.name, sv=stype.value, pf=valuePrefix)
- else:
- checkExpr = 'skipCall |= validate_struct_type(report_data, {}, {}, "{sv}", {}{vn}, {sv}, {});\n'.format(name, valueDisplayName, valuePrefix, req, vn=value.name, sv=stype.value)
+ usedAlways += self.makeStructTypeCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName)
elif value.name == 'pNext':
# We need to ignore VkDeviceCreateInfo and VkInstanceCreateInfo, as the loader manipulates them in a way that is not documented in vk.xml
- if not structName in ['VkDeviceCreateInfo', 'VkInstanceCreateInfo']:
- # Generate an array of acceptable VkStructureType values for pNext
- extStructCount = 0
- extStructVar = 'NULL'
- extStructNames = 'NULL'
- if value.extstructs:
- structs = value.extstructs.split(',')
- checkExpr = 'const VkStructureType allowedStructs[] = {' + ', '.join([self.structTypes[s].value for s in structs]) + '};\n' + indent
- extStructCount = 'ARRAY_SIZE(allowedStructs)'
- extStructVar = 'allowedStructs'
- extStructNames = '"' + ', '.join(structs) + '"'
- checkExpr += 'skipCall |= validate_struct_pnext(report_data, {}, {}, {}, {}{vn}, {}, {});\n'.format(name, valueDisplayName, extStructNames, valuePrefix, extStructCount, extStructVar, vn=value.name)
+ if not structTypeName in ['VkDeviceCreateInfo', 'VkInstanceCreateInfo']:
+ usedAlways += self.makeStructNextCheck(valuePrefix, value, funcName, valueDisplayName)
else:
- if lenParam:
- # This is an array
- if lenParam.ispointer:
- # If count and array parameters are optional, there will be no validation
- if req == 'true' or cpReq == 'true' or cvReq == '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 = 'skipCall |= validate_array(report_data, {}, {ldn}, {dn}, {pf}{ln}, {pf}{vn}, {}, {}, {});\n'.format(name, cpReq, cvReq, req, ln=lenParam.name, ldn=lenDisplayName, dn=valueDisplayName, vn=value.name, pf=valuePrefix)
- else:
- # If count and array parameters are optional, there will be no validation
- if req == 'true' or cvReq == 'true':
- funcName = 'validate_array' if value.type != 'char' else 'validate_string_array'
- checkExpr = 'skipCall |= {}(report_data, {}, {ldn}, {dn}, {pf}{ln}, {pf}{vn}, {}, {});\n'.format(funcName, name, cvReq, req, ln=lenParam.name, ldn=lenDisplayName, dn=valueDisplayName, vn=value.name, pf=valuePrefix)
- elif not value.isoptional:
- # Function pointers need a reinterpret_cast to void*
- if value.type[:4] == 'PFN_':
- checkExpr = 'skipCall |= validate_required_pointer(report_data, {}, {}, reinterpret_cast<const void*>({}{vn}));\n'.format(name, valueDisplayName, valuePrefix, vn=value.name)
- else:
- checkExpr = 'skipCall |= validate_required_pointer(report_data, {}, {}, {}{vn});\n'.format(name, valueDisplayName, valuePrefix, vn=value.name)
+ usedAlways += self.makePointerCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName)
#
# If this is a pointer to a struct (input), see if it contains members that need to be checked
if value.type in self.validatedStructs and value.isconst:
#
# The name prefix used when reporting an error with a struct member (eg. the 'pCreateInfor->' in 'pCreateInfo->sType')
if lenParam:
- prefix = '(std::string({}) + std::string("{}[i]->")).c_str()'.format(variablePrefix, value.name) if variablePrefix else '(std::string("{}[i]->")).c_str()'.format(value.name)
+ prefix = '(std::string({}) + std::string("{}[i]->")).c_str()'.format(displayNamePrefix, value.name) if displayNamePrefix else '(std::string("{}[i]->")).c_str()'.format(value.name)
else:
- prefix = '(std::string({}) + std::string("{}->")).c_str()'.format(variablePrefix, value.name) if variablePrefix else '"{}->"'.format(value.name)
- #
- membersInputOnly = self.validatedStructs[value.type]
- #
- # If the current struct has mixed 'input-only' and 'non-input-only' members, it needs an isInput flag
- if membersInputOnly == self.STRUCT_MEMBERS_INPUT_ONLY_MIXED:
- # If this function is called from another struct validation function (valuePrefix is not empty), then we forward the 'isInput' prameter
- isInput = 'isInput'
- if not valuePrefix:
- # We are validating function parameters and need to determine if the current value is an input parameter
- isInput = 'true' if value.isconst else 'false'
- if checkExpr:
- checkExpr += '\n' + indent
- if lenParam:
- # Need to process all elements in the array
- checkExpr += 'if ({}{} != NULL) {{\n'.format(valuePrefix, value.name)
- indent = self.incIndent(indent)
- checkExpr += indent + 'for (uint32_t i = 0; i < {}{}; ++i) {{\n'.format(valuePrefix, lenParam.name)
- indent = self.incIndent(indent)
- checkExpr += indent + 'skipCall |= parameter_validation_{}(report_data, {}, {}, {}, &({}{}[i]));\n'.format(value.type, name, prefix, isInput, valuePrefix, value.name)
- indent = self.decIndent(indent)
- checkExpr += indent + '}\n'
- indent = self.decIndent(indent)
- checkExpr += indent + '}\n'
- else:
- checkExpr += 'skipCall |= parameter_validation_{}(report_data, {}, {}, {}, {}{});\n'.format(value.type, name, prefix, isInput, valuePrefix, value.name)
+ prefix = '(std::string({}) + std::string("{}->")).c_str()'.format(displayNamePrefix, value.name) if displayNamePrefix else '"{}->"'.format(value.name)
+ # Validation function does not have an isInput field
+ if lenParam:
+ expr = []
+ # Need to process all elements in the array
+ expr.append('if ({}{} != NULL) {{\n'.format(valuePrefix, value.name))
+ indent = self.incIndent(None)
+ expr.append(indent + 'for (uint32_t i = 0; i < {}{}; ++i) {{\n'.format(valuePrefix, lenParam.name))
+ indent = self.incIndent(indent)
+ expr.append(indent + 'skipCall |= parameter_validation_{}(report_data, {}, {}, &({}{}[i]));\n'.format(value.type, funcName, prefix, valuePrefix, value.name))
+ indent = self.decIndent(indent)
+ expr.append(indent + '}\n')
+ indent = self.decIndent(indent)
+ expr.append(indent + '}\n')
else:
- # Validation function does not have an isInput field
- if lenParam:
- # Need to process all elements in the array
- expr = 'if ({}{} != NULL) {{\n'.format(valuePrefix, value.name)
- indent = self.incIndent(indent)
- expr += indent + 'for (uint32_t i = 0; i < {}{}; ++i) {{\n'.format(valuePrefix, lenParam.name)
- indent = self.incIndent(indent)
- expr += indent + 'skipCall |= parameter_validation_{}(report_data, {}, {}, &({}{}[i]));\n'.format(value.type, name, prefix, valuePrefix, value.name)
- indent = self.decIndent(indent)
- expr += indent + '}\n'
- indent = self.decIndent(indent)
- expr += indent + '}\n'
- else:
- expr = 'skipCall |= parameter_validation_{}(report_data, {}, {}, {}{});\n'.format(value.type, name, prefix, valuePrefix, value.name)
- #
- # If the struct only has input-only members and is a member of another struct, it is conditionally processed based on 'isInput'
- if valuePrefix and membersInputOnly == self.STRUCT_MEMBERS_INPUT_ONLY_EXCLUSIVE:
- if needConditionCheck:
- if expr.count('\n') > 1:
- # TODO: Proper fix for this formatting workaround
- conditionalExprs.append(expr.replace(' ' * 8, ' ' * 12))
- else:
- conditionalExprs.append(expr)
- else:
- if checkExpr:
- checkExpr += '\n' + indent
- checkExpr += expr
- #
- # If the struct is a function parameter (valuePrefix is empty) and only contains input-only parameters, it can be ignored if it is not an input
- elif (membersInputOnly == self.STRUCT_MEMBERS_INPUT_ONLY_NONE) or (not valuePrefix and membersInputOnly == self.STRUCT_MEMBERS_INPUT_ONLY_EXCLUSIVE and value.isconst):
- if checkExpr:
- checkExpr += '\n' + indent
- checkExpr += expr
+ expr = 'skipCall |= parameter_validation_{}(report_data, {}, {}, {}{});\n'.format(value.type, funcName, prefix, valuePrefix, value.name)
+ usedAlways.append(expr)
elif value.isbool and value.isconst:
- expr = 'skipCall |= validate_bool32_array(report_data, {}, {}, {pf}{}, {pf}{});\n'.format(name, valueDisplayName, lenParam.name, value.name, pf=valuePrefix)
- if checkExpr:
- checkExpr += '\n' + indent
- checkExpr += expr
+ usedOnInput.append('skipCall |= validate_bool32_array(report_data, {}, {}, {pf}{}, {pf}{});\n'.format(funcName, valueDisplayName, lenParam.name, value.name, pf=valuePrefix))
elif value.israngedenum and value.isconst:
enumRange = self.enumRanges[value.type]
- expr = 'skipCall |= validate_ranged_enum_array(report_data, {}, {}, "{}", {}, {}, {pf}{}, {pf}{});\n'.format(name, valueDisplayName, value.type, enumRange[0], enumRange[1], lenParam.name, value.name, pf=valuePrefix)
- if checkExpr:
- checkExpr += '\n' + indent
- checkExpr += expr
+ usedOnInput.append('skipCall |= validate_ranged_enum_array(report_data, {}, {}, "{}", {}, {}, {pf}{}, {pf}{});\n'.format(funcName, valueDisplayName, value.type, enumRange[0], enumRange[1], lenParam.name, value.name, pf=valuePrefix))
elif value.type in self.validatedStructs:
# The name of the value with prefix applied
- prefix = '(std::string({}) + std::string("{}.")).c_str()'.format(variablePrefix, value.name) if variablePrefix else '"{}."'.format(value.name)
- #
- membersInputOnly = self.validatedStructs[value.type]
- #
- # If the current struct has mixed 'input-only' and 'non-input-only' members, it needs an isInput flag
- if membersInputOnly == self.STRUCT_MEMBERS_INPUT_ONLY_MIXED:
- # If this function is called from another struct validation function (valuePrefix is not empty), then we forward the 'isInput' prameter
- isInput = 'isInput'
- if not valuePrefix:
- # We are validating function parameters and need to determine if the current value is an input parameter
- isInput = 'true' if value.isconst else 'false'
- if checkExpr:
- checkExpr += '\n' + indent
- checkExpr += 'skipCall |= parameter_validation_{}(report_data, {}, {}, {}, &({}{}));\n'.format(value.type, name, prefix, isInput, valuePrefix, value.name)
- else:
- # Validation function does not have an isInput field
- expr = 'skipCall |= parameter_validation_{}(report_data, {}, {}, &({}{}));\n'.format(value.type, name, prefix, valuePrefix, value.name)
- #
- # If the struct only has input-only members and is a member of another struct, it is conditionally processed based on 'isInput'
- if valuePrefix and membersInputOnly == self.STRUCT_MEMBERS_INPUT_ONLY_EXCLUSIVE:
- if needConditionCheck:
- conditionalExprs.append(expr)
- else:
- if checkExpr:
- checkExpr += '\n' + indent
- checkExpr += expr
- #
- # If the struct is a function parameter (valuePrefix is empty) and only contains input-only parameters, it can be ignored if it is not an input
- elif (membersInputOnly == self.STRUCT_MEMBERS_INPUT_ONLY_NONE) or (not valuePrefix and membersInputOnly == self.STRUCT_MEMBERS_INPUT_ONLY_EXCLUSIVE and value.isconst):
- if checkExpr:
- checkExpr += '\n' + indent
- checkExpr += expr
+ prefix = '(std::string({}) + std::string("{}.")).c_str()'.format(displayNamePrefix, value.name) if displayNamePrefix else '"{}."'.format(value.name)
+ usedAlways.append('skipCall |= parameter_validation_{}(report_data, {}, {}, &({}{}));\n'.format(value.type, funcName, prefix, valuePrefix, value.name))
elif value.isbool:
- expr = 'skipCall |= validate_bool32(report_data, {}, {}, {}{});\n'.format(name, valueDisplayName, valuePrefix, value.name)
- if needConditionCheck:
- conditionalExprs.append(expr)
- else:
- checkExpr = expr
+ usedOnInput.append('skipCall |= validate_bool32(report_data, {}, {}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name))
elif value.israngedenum:
enumRange = self.enumRanges[value.type]
- expr = 'skipCall |= validate_ranged_enum(report_data, {}, {}, "{}", {}, {}, {}{});\n'.format(name, valueDisplayName, value.type, enumRange[0], enumRange[1], valuePrefix, value.name)
- if needConditionCheck:
- conditionalExprs.append(expr)
- else:
- checkExpr = expr
+ usedOnInput.append('skipCall |= validate_ranged_enum(report_data, {}, {}, "{}", {}, {}, {}{});\n'.format(funcName, valueDisplayName, value.type, enumRange[0], enumRange[1], valuePrefix, value.name))
#
# Append the parameter check to the function body for the current command
- if checkExpr:
- funcBody += '\n'
- if lenParam and ('->' in lenParam.name):
- # Add checks to ensure the validation call does not dereference a NULL pointer to obtain the count
- funcBody += self.genCheckedLengthCall(indent, lenParam.name, checkExpr)
- else:
- funcBody += indent + checkExpr
+ if usedAlways or usedOnInput:
+ # Both used always and used on input are currently treated the same
+ if usedAlways:
+ lines += usedAlways
+ if usedOnInput:
+ lines += usedOnInput
elif not value.iscount:
# If no expression was generated for this value, it is unreferenced by the validation function, unless
# it is an array count, which is indirectly referenced for array valiadation.
unused.append(value.name)
- # Add the 'input' only checks
- if conditionalExprs:
- funcBody += '\n'
- funcBody += indent + 'if (isInput) {'
- indent = self.incIndent(indent)
- for conditionalExpr in conditionalExprs:
- funcBody += '\n'
- funcBody += indent + conditionalExpr
- indent = self.decIndent(indent)
- funcBody += indent + '}\n'
- return funcBody, unused
+ return lines, unused
#
# Post-process the collected struct member data to create a list of structs
# with members that need to be validated
def prepareStructMemberData(self):
for struct in self.structMembers:
- inputOnly = False
validated = False
for member in struct.members:
+ # Counts will be validated with their associated array
if not member.iscount:
lenParam = self.getLenParam(struct.members, member.len)
# The sType value needs to be validated
@@ -3538,50 +3461,37 @@
elif member.ispointer and not member.isoptional:
validated = True
elif member.isbool or member.israngedenum:
- inputOnly = True
+ validated = True
#
- if validated or inputOnly:
- if not validated:
- self.validatedStructs[struct.name] = self.STRUCT_MEMBERS_INPUT_ONLY_EXCLUSIVE
- elif not inputOnly:
- self.validatedStructs[struct.name] = self.STRUCT_MEMBERS_INPUT_ONLY_NONE
- else:
- self.validatedStructs[struct.name] = self.STRUCT_MEMBERS_INPUT_ONLY_MIXED
- # Second pass to check for struct members that are structs requiring validation
- # May not be necessary, as structs seem to always be defined before first use in the XML registry
- for member in struct.members:
- if member.type in self.validatedStructs:
- memberInputOnly = self.validatedStructs[member.type]
- if not struct.name in self.validatedStructs:
- self.validatedStructs[struct.name] = memberInputOnly
- elif self.validatedStructs[struct.name] != memberInputOnly:
- self.validatedStructs[struct.name] = self.STRUCT_MEMBERS_INPUT_ONLY_MIXED
+ if validated:
+ self.validatedStructs.add(struct.name)
#
# Generate the struct member check code from the captured data
def processStructMemberData(self):
indent = self.incIndent(None)
for struct in self.structMembers:
- needConditionCheck = False
- if struct.name in self.validatedStructs and self.validatedStructs[struct.name] == self.STRUCT_MEMBERS_INPUT_ONLY_MIXED:
- needConditionCheck = True
#
# The string returned by genFuncBody will be nested in an if check for a NULL pointer, so needs its indent incremented
- funcBody, unused = self.genFuncBody(self.incIndent(indent), 'pFuncName', struct.members, 'pStruct->', 'pVariableName', struct.name, needConditionCheck)
- if funcBody:
+ lines, unused = self.genFuncBody('pFuncName', struct.members, 'pStruct->', 'pVariableName', struct.name)
+ if lines:
cmdDef = 'static bool parameter_validation_{}(\n'.format(struct.name)
cmdDef += ' debug_report_data*'.ljust(self.genOpts.alignFuncParam) + ' report_data,\n'
cmdDef += ' const char*'.ljust(self.genOpts.alignFuncParam) + ' pFuncName,\n'
cmdDef += ' const char*'.ljust(self.genOpts.alignFuncParam) + ' pVariableName,\n'
- # If there is a funcBody, this struct must have an entry in the validatedStructs dictionary
- if self.validatedStructs[struct.name] == self.STRUCT_MEMBERS_INPUT_ONLY_MIXED:
- # If the struct has mixed input only and non-input only members, it needs a flag to indicate if it is an input or output
- cmdDef += ' bool'.ljust(self.genOpts.alignFuncParam) + ' isInput,\n'
cmdDef += ' const {}*'.format(struct.name).ljust(self.genOpts.alignFuncParam) + ' pStruct)\n'
cmdDef += '{\n'
cmdDef += indent + 'bool skipCall = false;\n'
cmdDef += '\n'
cmdDef += indent + 'if (pStruct != NULL) {'
- cmdDef += funcBody
+ indent = self.incIndent(indent)
+ for line in lines:
+ cmdDef += '\n'
+ if type(line) is list:
+ for sub in line:
+ cmdDef += indent + sub
+ else:
+ cmdDef += indent + line
+ indent = self.decIndent(indent)
cmdDef += indent +'}\n'
cmdDef += '\n'
cmdDef += indent + 'return skipCall;\n'
@@ -3592,23 +3502,27 @@
def processCmdData(self):
indent = self.incIndent(None)
for command in self.commands:
- cmdBody, unused = self.genFuncBody(indent, '"{}"'.format(command.name), command.params, '', None, None, False)
- if cmdBody:
+ lines, unused = self.genFuncBody('"{}"'.format(command.name), command.params, '', None, None)
+ if lines:
cmdDef = self.getCmdDef(command) + '\n'
cmdDef += '{\n'
- # Process unused parameters
- # Ignore the first dispatch handle parameter, which is not
- # processed by parameter_validation (except for vkCreateInstance, which
- # does not have a handle as its first parameter)
- startIndex = 1
- if command.name == 'vkCreateInstance':
- startIndex = 0
- for name in unused[startIndex:]:
- cmdDef += indent + 'UNUSED_PARAMETER({});\n'.format(name)
- if len(unused) > 1:
- cmdDef += '\n'
+ # Process unused parameters, Ignoring the first dispatch handle parameter, which is not
+ # processed by parameter_validation (except for vkCreateInstance, which does not have a
+ # handle as its first parameter)
+ if unused:
+ startIndex = 0 if command.name == 'vkCreateInstance' else 1
+ for name in unused[startIndex:]:
+ cmdDef += indent + 'UNUSED_PARAMETER({});\n'.format(name)
+ if len(unused) > startIndex:
+ cmdDef += '\n'
cmdDef += indent + 'bool skipCall = false;\n'
- cmdDef += cmdBody
+ for line in lines:
+ cmdDef += '\n'
+ if type(line) is list:
+ for sub in line:
+ cmdDef += indent + sub
+ else:
+ cmdDef += indent + line
cmdDef += '\n'
cmdDef += indent + 'return skipCall;\n'
cmdDef += '}\n'