From 981ac05e5f1eceef369acea8cfdf3180027d893c Mon Sep 17 00:00:00 2001 From: swasti16 Date: Wed, 22 Nov 2023 17:19:42 +0530 Subject: [PATCH] Fix #10854: False positive: misra-c2012-9.2: inner union --- addons/misra_9.py | 94 ++++++++++++++++++++-------------- addons/test/misra/misra-test.c | 15 ++++++ 2 files changed, 71 insertions(+), 38 deletions(-) diff --git a/addons/misra_9.py b/addons/misra_9.py index b844170662e1..337fd529a550 100644 --- a/addons/misra_9.py +++ b/addons/misra_9.py @@ -81,14 +81,14 @@ def addChild(self, child): self.children.append(child) child.parent = self - def getNextChild(self): + def getNextChild(self, data): self.childIndex += 1 - return self.getChildByIndex(self.childIndex) + return self.getChildByIndex(self.childIndex, data) - def getChildByIndex(self, index): + def getChildByIndex(self, index, data): if self.isFlexible: while len(self.children) <= index: - createChild(self, self.flexibleToken, len(self.children), None) + createChild(self, self.flexibleToken, len(self.children), None, data) return self.children[index] if 0 <= index < len(self.children) else None def getChildByName(self, name): @@ -97,7 +97,7 @@ def getChildByName(self, name): return c return None - def getNextValueElement(self, root): + def getNextValueElement(self, root, data): current = self while current != root: if not current.parent: @@ -107,20 +107,20 @@ def getNextValueElement(self, root): # Next index of parent exists if i < len(current.parent.children): current = current.parent.children[i] - return current.getFirstValueElement() + return current.getFirstValueElement(data) # Next index of parent doesn't exist. Move up current = current.parent return None - def getFirstValueElement(self): + def getFirstValueElement(self, data): current = self # Move to first child as long as children exists - next_child = current.getChildByIndex(0) + next_child = current.getChildByIndex(0, data) while next_child: current = next_child - next_child = current.getChildByIndex(0) + next_child = current.getChildByIndex(0, data) return current def getLastValueElement(self): @@ -223,7 +223,7 @@ def __init__(self): self.ed = None self.rootStack = [] - def parseInitializer(self, root, token): + def parseInitializer(self, root, token, data): self.root = root self.token = token dummyRoot = ElementDef('array', '->', self.root.valueType) @@ -231,7 +231,7 @@ def parseInitializer(self, root, token): self.rootStack = [] self.root = dummyRoot - self.ed = self.root.getFirstValueElement() + self.ed = self.root.getFirstValueElement(data) isFirstElement = False isDesignated = False @@ -244,12 +244,12 @@ def parseInitializer(self, root, token): elif self.token.isAssignmentOp and not self.token.valueType: self.popFromStackIfExitElement() - self.ed = getElementByDesignator(self.root, self.token.astOperand1) + self.ed = getElementByDesignator(self.root, self.token.astOperand1, data) if self.ed: # Update root self.pushToRootStackAndMarkAsDesignated() # Make sure ed points to valueElement - self.ed = self.ed.getFirstValueElement() + self.ed = self.ed.getFirstValueElement(data) self.token = self.token.astOperand2 isFirstElement = False @@ -260,24 +260,24 @@ def parseInitializer(self, root, token): if self.token == self.token.astParent.astOperand1 and self.token.astParent.astOperand2: self.token = self.token.astParent.astOperand2 self.ed.markAsCurrent() - self.ed = self.root.getNextChild() + self.ed = self.root.getNextChild(data) else: - self.unwindAndContinue() + self.unwindAndContinue(data) continue elif self.token.str == '{': - nextChild = self.root.getNextChild() if self.root is not None else None + nextChild = self.root.getNextChild(data) if self.root is not None else None if nextChild: if nextChild.isArray or nextChild.isRecord: nextChild.unset() nextChild.setInitialized(isDesignated) - self.ed = nextChild.getFirstValueElement() + self.ed = nextChild.getFirstValueElement(data) isDesignated = False elif nextChild.valueType is None: # No type information available - unable to check structure - assume correct initialization nextChild.setInitialized(isDesignated) - self.unwindAndContinue() + self.unwindAndContinue(data) continue elif self.token.astOperand1: @@ -305,7 +305,7 @@ def parseInitializer(self, root, token): else: self.root.markStuctureViolation(self.token) self.ed = None - self.unwindAndContinue() + self.unwindAndContinue(data) else: if self.ed and self.ed.isValue: @@ -348,7 +348,7 @@ def parseInitializer(self, root, token): if self.token.isString and self.ed.parent.isArray: self.ed = self.ed.parent - self.unwindAndContinue() + self.unwindAndContinue(data) def pushToRootStackAndMarkAsDesignated(self): new = self.ed.parent @@ -369,12 +369,12 @@ def popFromStackIfExitElement(self): old.markAsCurrent() self.root = old - def unwindAndContinue(self): + def unwindAndContinue(self, data): while self.token: if self.token.astParent.astOperand1 == self.token and self.token.astParent.astOperand2: if self.ed: self.ed.markAsCurrent() - self.ed = self.ed.getNextValueElement(self.root) + self.ed = self.ed.getNextValueElement(self.root, data) self.token = self.token.astParent.astOperand2 break @@ -420,13 +420,13 @@ def misra_9_x(self, data, rule, rawTokens = None): continue if variable.isArray or variable.isClass: - ed = getElementDef(nameToken, rawTokens) + ed = getElementDef(nameToken, data, rawTokens) # No need to check non-arrays if valueType is missing, # since we can't say anything useful about the structure # without it. if ed.valueType is None and not variable.isArray: continue - parser.parseInitializer(ed, eq.astOperand2) + parser.parseInitializer(ed, eq.astOperand2, data) # print(rule, nameToken.str + '=', ed.getInitDump()) if rule == 902 and not ed.isMisra92Compliant(): self.reportError(nameToken, 9, 2) @@ -444,18 +444,18 @@ def misra_9_x(self, data, rule, rawTokens = None): if rule == 905 and not ed.isMisra95Compliant(): self.reportError(nameToken, 9, 5) -def getElementDef(nameToken, rawTokens = None): +def getElementDef(nameToken, data, rawTokens = None): if nameToken.variable.isArray: ed = ElementDef("array", nameToken.str, nameToken.valueType) - createArrayChildrenDefs(ed, nameToken.astParent, nameToken.variable, rawTokens) + createArrayChildrenDefs(ed, nameToken.astParent, nameToken.variable, data, rawTokens) elif nameToken.variable.isClass: ed = ElementDef("record", nameToken.str, nameToken.valueType) - createRecordChildrenDefs(ed, nameToken.variable) + createRecordChildrenDefs(ed, nameToken.variable, data) else: ed = ElementDef("value", nameToken.str, nameToken.valueType) return ed -def createArrayChildrenDefs(ed, token, var, rawTokens = None): +def createArrayChildrenDefs(ed, token, var, data, rawTokens = None): if token and token.str == '[': if rawTokens is not None: foundToken = next((rawToken for rawToken in rawTokens @@ -469,25 +469,25 @@ def createArrayChildrenDefs(ed, token, var, rawTokens = None): if (token.astOperand2 is not None) and (token.astOperand2.getKnownIntValue() is not None): for i in range(token.astOperand2.getKnownIntValue()): - createChild(ed, token, i, var) + createChild(ed, token, i, var, data) else: ed.markAsFlexibleArray(token) -def createChild(ed, token, name, var): +def createChild(ed, token, name, var, data): if token.astParent and token.astParent.str == '[': child = ElementDef("array", name, ed.valueType) - createArrayChildrenDefs(child, token.astParent, var) + createArrayChildrenDefs(child, token.astParent, var, data) else: if ed.valueType and ed.valueType.type == "record": child = ElementDef("record", name, ed.valueType) - createRecordChildrenDefs(child, var) + createRecordChildrenDefs(child, var, data) else: child = ElementDef("value", name, ed.valueType) ed.addChild(child) -def createRecordChildrenDefs(ed, var): +def createRecordChildrenDefs(ed, var, data): valueType = ed.valueType if not valueType or not valueType.typeScope: return @@ -500,13 +500,31 @@ def createRecordChildrenDefs(ed, var): child = ElementDef("pointer", var.nameToken, var.nameToken.valueType) ed.addChild(child) return + child_dict = {} for variable in valueType.typeScope.varlist: if variable is var: continue - child = getElementDef(variable.nameToken) - ed.addChild(child) - -def getElementByDesignator(ed, token): + child = getElementDef(variable.nameToken, data) + child_dict[variable.nameToken] = child + for scopes in data.scopes: + varscope = False + if scopes.nestedIn == valueType.typeScope: + for variable in data.variables: + if variable.nameToken and variable.nameToken.valueType and variable.nameToken.valueType.typeScope == scopes: + varscope = True + break + if not varscope: + ed1 = ElementDef("record", scopes.Id, valueType) + for variable in scopes.varlist: + child = getElementDef(variable.nameToken, data) + ed1.addChild(child) + child_dict[scopes.bodyStart] = ed1 + sorted_keys = sorted(list(child_dict.keys()), key=lambda k: "%s %s %s" % (k.file, k.linenr, k.column)) + for _key in sorted_keys: + ed.addChild(child_dict[_key]) + + +def getElementByDesignator(ed, token, data): if not token.str in [ '.', '[' ]: return None @@ -526,7 +544,7 @@ def getElementByDesignator(ed, token): elif token.astOperand1 is not None: chIndex = token.astOperand1.getKnownIntValue() - ed = ed.getChildByIndex(chIndex) if chIndex is not None else None + ed = ed.getChildByIndex(chIndex, data) if chIndex is not None else None elif token.str == '.': if not ed.isRecord: diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 14eddd8600cf..0413a2b27af2 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -418,6 +418,21 @@ static void misra_8_14(char * restrict str) {(void)str;} // 8.14 struct S_9_3 { struct S_9_3* p; int x; }; struct S_9_3* s_9_3_array[] = { x, NULL }; // 8.4 +// #10854 +struct Entry_9_2{ + union{ // 19.2 + const int *p; + int x; + }; + int y; +}; + +static void misra_9_2_10854(void){ + struct Entry_9_2 e1[] = + { + {{ .x = 1 }, .y = 2 } + }; +} static void misra_9_empty_or_zero_initializers(void) { int a[2] = {}; // 9.2 int b[2][2] = {}; // 9.2