aboutsummaryrefslogtreecommitdiff
path: root/generator.py
diff options
context:
space:
mode:
authorDustin Graves <dustin@lunarg.com>2016-04-18 18:33:21 -0600
committerDustin Graves <dustin@lunarg.com>2016-04-20 10:06:41 -0600
commit43901a048d87f5b5dde23298df412c0775c63bfe (patch)
tree59ce2bdee5c4407294891f57f0daeb820f8a5151 /generator.py
parentf19bf1cab588dbfc51e9c2c8586598aeff43b93b (diff)
downloadusermoji-43901a048d87f5b5dde23298df412c0775c63bfe.tar.xz
layers: Add handle NULL checks to codegen
Add support for validating that required handle parameters are not specified as VK_NULL_HANDLE to the parameter validation layer's code generator. - Add new parameter validation utility functions to validate required handles and arrays of handles. - Add new parameter validation layer entrypoints for functions that previously had no parameters to validate. - Add handle validation logic to the parameter validation code generator. Change-Id: I7a5680954245db4c1b12587f78e30e17c3903d6c
Diffstat (limited to 'generator.py')
-rw-r--r--generator.py59
1 files changed, 52 insertions, 7 deletions
diff --git a/generator.py b/generator.py
index 8040346f..0bf6e95d 100644
--- a/generator.py
+++ b/generator.py
@@ -2845,6 +2845,7 @@ class ParamCheckerOutputGenerator(OutputGenerator):
self.structNames = [] # List of Vulkan struct typenames
self.stypes = [] # Values from the VkStructureType enumeration
self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType
+ self.handleTypes = set() # Set of handle type names
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 type names to generated validation code for that struct type
@@ -2852,7 +2853,8 @@ class ParamCheckerOutputGenerator(OutputGenerator):
# Named tuples to store struct and command data
self.StructType = namedtuple('StructType', ['name', 'value'])
self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isbool', 'israngedenum',
- 'isconst', 'isoptional', 'iscount', 'len', 'extstructs', 'condition', 'cdecl'])
+ 'isconst', 'isoptional', 'iscount', 'noautovalidity', 'len', 'extstructs',
+ 'condition', 'cdecl'])
self.CommandData = namedtuple('CommandData', ['name', 'params', 'cdecl'])
self.StructMemberData = namedtuple('StructMemberData', ['name', 'members'])
#
@@ -2915,6 +2917,7 @@ class ParamCheckerOutputGenerator(OutputGenerator):
self.structNames = []
self.stypes = []
self.structTypes = dict()
+ self.handleTypes = set()
self.commands = []
self.structMembers = []
self.validatedStructs = dict()
@@ -2960,6 +2963,8 @@ class ParamCheckerOutputGenerator(OutputGenerator):
if (category == 'struct' or category == 'union'):
self.structNames.append(name)
self.genStruct(typeinfo, name)
+ elif (category == 'handle'):
+ self.handleTypes.add(name)
#
# Struct parameter check generation.
# This is a special case of the <type> tag where the contents are
@@ -3034,6 +3039,7 @@ class ParamCheckerOutputGenerator(OutputGenerator):
isconst=True if 'const' in cdecl else False,
isoptional=isoptional,
iscount=iscount,
+ noautovalidity=True if member.attrib.get('noautovalidity') is not None else False,
len=self.getLen(member),
extstructs=member.attrib.get('validextensionstructs') if name == 'pNext' else None,
condition=conditions[name] if conditions and name in conditions else None,
@@ -3094,6 +3100,7 @@ class ParamCheckerOutputGenerator(OutputGenerator):
isconst=True if 'const' in cdecl else False,
isoptional=self.paramIsOptional(param),
iscount=iscount,
+ noautovalidity=True if param.attrib.get('noautovalidity') is not None else False,
len=self.getLen(param),
extstructs=None,
condition=None,
@@ -3142,6 +3149,20 @@ class ParamCheckerOutputGenerator(OutputGenerator):
isoptional = opts
return isoptional
#
+ # Check if the handle passed in is optional
+ # Uses the same logic as ValidityOutputGenerator.isHandleOptional
+ def isHandleOptional(self, param, lenParam):
+ # Simple, if it's optional, return true
+ if param.isoptional:
+ return True
+ # If no validity is being generated, it usually means that validity is complex and not absolute, so let's say yes.
+ if param.noautovalidity:
+ return True
+ # If the parameter is an array and we haven't already returned, find out if any of the len parameters are optional
+ if lenParam and lenParam.isoptional:
+ return True
+ return False
+ #
# Retrieve the value of the len tag
def getLen(self, param):
result = None
@@ -3201,7 +3222,8 @@ class ParamCheckerOutputGenerator(OutputGenerator):
if '->' in name:
# The count is obtained by dereferencing a member of a struct parameter
lenParam = self.CommandParam(name=name, iscount=True, ispointer=False, isbool=False, israngedenum=False, isconst=False,
- isstaticarray=None, isoptional=False, type=None, len=None, extstructs=None, condition=None, cdecl=None)
+ isstaticarray=None, isoptional=False, type=None, noautovalidity=False, len=None, extstructs=None,
+ condition=None, cdecl=None)
elif 'latexmath' in name:
lenName, decoratedName = self.parseLateXMath(name)
lenParam = self.getParamByName(params, lenName)
@@ -3211,7 +3233,7 @@ class ParamCheckerOutputGenerator(OutputGenerator):
#lenParam = self.CommandParam(name=decoratedName, iscount=param.iscount, ispointer=param.ispointer,
# isoptional=param.isoptional, type=param.type, len=param.len,
# isstaticarray=param.isstaticarray, extstructs=param.extstructs,
- # condition=None, cdecl=param.cdecl)
+ # noautovalidity=True, condition=None, cdecl=param.cdecl)
else:
lenParam = self.getParamByName(params, name)
return lenParam
@@ -3289,6 +3311,22 @@ class ParamCheckerOutputGenerator(OutputGenerator):
funcPrintName, valuePrintName, prefix, valueRequired, vn=value.name, sv=stype.value))
return checkExpr
#
+ # Generate the sType check string
+ def makeHandleCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, funcPrintName, lenPrintName, valuePrintName):
+ checkExpr = []
+ if lenValue:
+ # This is assumed to be an output array with a pointer to a count value
+ if lenValue.ispointer:
+ raise('Unsupported parameter validation case: Output handle array elements are not NULL checked')
+ # This is an array with an integer count value
+ else:
+ checkExpr.append('skipCall |= validate_handle_array(report_data, "{}", "{ldn}", "{dn}", {pf}{ln}, {pf}{vn}, {}, {});\n'.format(
+ funcPrintName, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix))
+ # This is assumed to be an output handle pointer
+ else:
+ raise('Unsupported parameter validation case: Output handles are not NULL checked')
+ return checkExpr
+ #
# Generate pNext check string
def makeStructNextCheck(self, prefix, value, funcPrintName, valuePrintName):
checkExpr = []
@@ -3431,6 +3469,9 @@ class ParamCheckerOutputGenerator(OutputGenerator):
# If this is a pointer to a struct with an sType field, verify the type
if value.type in self.structTypes:
usedLines += self.makeStructTypeCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName)
+ # If this is an input handle array that is not allowed to contain NULL handles, verify that none of the handles are VK_NULL_HANDLE
+ elif value.type in self.handleTypes and value.isconst and not self.isHandleOptional(value, lenParam):
+ usedLines += self.makeHandleCheck(valuePrefix, value, lenParam, req, cvReq, 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 structTypeName in ['VkDeviceCreateInfo', 'VkInstanceCreateInfo']:
@@ -3451,6 +3492,9 @@ class ParamCheckerOutputGenerator(OutputGenerator):
memberNamePrefix = '{}{}.'.format(valuePrefix, value.name)
memberDisplayNamePrefix = '{}.'.format(valueDisplayName)
usedLines.append(self.expandStructCode(self.validatedStructs[value.type], funcName, memberNamePrefix, memberDisplayNamePrefix, '', []))
+ elif value.type in self.handleTypes:
+ if not self.isHandleOptional(value, None):
+ usedLines.append('skipCall |= validate_required_handle(report_data, "{}", "{}", {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name))
elif value.isbool:
usedLines.append('skipCall |= validate_bool32(report_data, "{}", "{}", {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name))
elif value.israngedenum:
@@ -3483,7 +3527,9 @@ class ParamCheckerOutputGenerator(OutputGenerator):
def processCmdData(self):
indent = self.incIndent(None)
for command in self.commands:
- lines, unused = self.genFuncBody(command.name, command.params, '', '', None)
+ # Skip first parameter if it is a dispatch handle (everything except vkCreateInstance)
+ startIndex = 0 if command.name == 'vkCreateInstance' else 1
+ lines, unused = self.genFuncBody(command.name, command.params[startIndex:], '', '', None)
if lines:
cmdDef = self.getCmdDef(command) + '\n'
cmdDef += '{\n'
@@ -3491,10 +3537,9 @@ class ParamCheckerOutputGenerator(OutputGenerator):
# 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:]:
+ for name in unused:
cmdDef += indent + 'UNUSED_PARAMETER({});\n'.format(name)
- if len(unused) > startIndex:
+ if len(unused) > 0:
cmdDef += '\n'
cmdDef += indent + 'bool skipCall = false;\n'
for line in lines: