layers: Handle indirection in param_checker

Code was being generated for param_checker that looked like:
  validate_pointer(pAllocInfo);
  validate_array(pAllocInfo->count, array);
Where validate_array could dereference a NULL pointer.  The code
generator was updated to insert NULL checks for this case:
  validate_pointer(pAllocInfo);
  if (pAllocInfo != NULL) {
      validate_array(pAllocInfo->count, array);
  }

Change-Id: I1eda66530dbff2e95d604a20d122179be172bedf
diff --git a/generator.py b/generator.py
index 2ab8e49..df5b7fe 100644
--- a/generator.py
+++ b/generator.py
@@ -2861,9 +2861,7 @@
     def genCmd(self, cmdinfo, name):
         OutputGenerator.genCmd(self, cmdinfo, name)
         if name not in self.blacklist:
-            proto = cmdinfo.elem.find('proto')       # Function name and return type
             params = cmdinfo.elem.findall('param')
-            usages = cmdinfo.elem.findall('validity/usage')
             # Get list of array lengths
             lens = set()
             for param in params:
@@ -2961,7 +2959,7 @@
         lines[1] = '    debug_report_data*                          report_data,'
         return '\n'.join(lines)
     #
-    # Generate the command text from the captured data
+    # Generate the command param check code from the captured data
     def processCmdData(self):
         indent = self.incIndent(None)
         for command in self.commands:
@@ -2974,6 +2972,7 @@
                 if (param.ispointer or param.isstaticarray) and not param.iscount:
                     #
                     # Parameters for function argument generation
+                    checkExpr = ''     # Code to check the current parameter
                     req = 'VK_TRUE'    # Paramerter can be NULL
                     cpReq = 'VK_TRUE'  # Count pointer can be NULL
                     cvReq = 'VK_TRUE'  # Count value can be 0
@@ -3007,41 +3006,42 @@
                     #
                     # If this is a pointer to a struct with an sType field, verify the type
                     if param.type in self.structTypes:
-                        # Add this command to the file; TODO: pre-determine this
-                        cmdBody += '\n'
-                        #
                         stype = self.structTypes[param.type]
                         if lenParam:
                             # This is an array
                             if lenParam.ispointer:
-                                cmdBody += indent + 'skipCall |= validate_struct_type_array(report_data, "{}", "{}", "{}", "{}", {}, {}, {}, {}, {}, {});\n'.format(command.name, lenParam.name, param.name, stype.value, lenParam.name, param.name, stype.value, cpReq, cvReq, req)
+                                # 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, "{}", "{}", "{}", "{}", {}, {}, {}, {}, {}, {});\n'.format(command.name, lenParam.name, param.name, stype.value, lenParam.name, param.name, stype.value, cpReq, cvReq, req)
                             else:
-                                cmdBody += indent + 'skipCall |= validate_struct_type_array(report_data, "{}", "{}", "{}", "{}", {}, {}, {}, {}, {});\n'.format(command.name, lenParam.name, param.name, stype.value, lenParam.name, param.name, stype.value, cvReq, req)
+                                checkExpr = 'skipCall |= validate_struct_type_array(report_data, "{}", "{}", "{}", "{}", {}, {}, {}, {}, {});\n'.format(command.name, lenParam.name, param.name, stype.value, lenParam.name, param.name, stype.value, cvReq, req)
                         else:
-                            cmdBody += indent + 'skipCall |= validate_struct_type(report_data, "{}", "{}", "{}", {}, {}, {});\n'.format(command.name, param.name, stype.value, param.name, stype.value, req)
+                            checkExpr = 'skipCall |= validate_struct_type(report_data, "{}", "{}", "{}", {}, {}, {});\n'.format(command.name, param.name, stype.value, param.name, stype.value, req)
                     else:
                         if lenParam:
-                            # Add this command to the file; TODO: pre-determine this
-                            cmdBody += '\n'
-                            #
                             # This is an array
                             if lenParam.ispointer:
-                                cmdBody += indent + 'skipCall |= validate_array(report_data, "{}", "{}", "{}", {}, {}, {}, {}, {});\n'.format(command.name, lenParam.name, param.name, lenParam.name, param.name, cpReq, cvReq, req)
+                                # 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, "{}", "{}", "{}", {}, {}, {}, {}, {});\n'.format(command.name, lenParam.name, param.name, lenParam.name, param.name, cpReq, cvReq, req)
                             else:
-                                cmdBody += indent + 'skipCall |= validate_array(report_data, "{}", "{}", "{}", {}, {}, {}, {});\n'.format(command.name, lenParam.name, param.name, lenParam.name, param.name, cvReq, req)
+                                checkExpr = 'skipCall |= validate_array(report_data, "{}", "{}", "{}", {}, {}, {}, {});\n'.format(command.name, lenParam.name, param.name, lenParam.name, param.name, cvReq, req)
                         elif not param.isoptional:
-                            # Add this command to the file; TODO: pre-determine this
-                            cmdBody += '\n'
-                            #
-                            cmdBody += indent + 'skipCall |= validate_required_pointer(report_data, "{}", "{}", {});\n'.format(command.name, param.name, param.name)
+                            checkExpr = indent + 'skipCall |= validate_required_pointer(report_data, "{}", "{}", {});\n'.format(command.name, param.name, param.name)
                         else:
                             unused.append(param.name)
+                    # Append the parameter check to the function body for the current command
+                    if checkExpr:
+                        cmdBody += '\n'
+                        if lenParam and ('->' in lenParam.name):
+                            # Add checks to ensure the validation call does not dereference a NULL pointer to obtain the count
+                            cmdBody += self.genCheckedLengthCall(indent, lenParam.name, checkExpr)
+                        else:
+                            cmdBody += indent + checkExpr
                 elif not param.iscount:
                     unused.append(param.name)
             if cmdBody:
                 cmdDef = self.getCmdDef(command) + '\n'
                 cmdDef += '{\n'
-                indDnt = self.incIndent(None)
+                indent = self.incIndent(None)
                 # Ignore the first dispatch handle parameter, which is not
                 # processed by param_check
                 for name in unused[1:]:
@@ -3054,4 +3054,27 @@
                 cmdDef += indent + 'return skipCall;\n'
                 cmdDef += '}\n'
                 self.appendSection('command', cmdDef)
+    #
+    # Generate the code to check for a NULL dereference before calling the
+    # validation function
+    def genCheckedLengthCall(self, indent, name, expr):
+        count = name.count('->')
+        if count:
+            checkedExpr = ''
+            localIndent = indent
+            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]))
+                localIndent = self.incIndent(localIndent)
+            # Add the validation expression
+            checkedExpr += localIndent + expr
+            # Close the if blocks
+            for i in range(0, count):
+                localIndent = self.decIndent(localIndent)
+                checkedExpr += localIndent + '}\n'
+            return checkedExpr
+        # No if statements were required
+        return indent + expr
+