Skip to content

Commit

Permalink
Fix #10854: False positive: misra-c2012-9.2: inner union
Browse files Browse the repository at this point in the history
  • Loading branch information
swasti16 committed Nov 22, 2023
1 parent 3e47acd commit 981ac05
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 38 deletions.
94 changes: 56 additions & 38 deletions addons/misra_9.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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:
Expand All @@ -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):
Expand Down Expand Up @@ -223,15 +223,15 @@ 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)
dummyRoot.children = [self.root]

self.rootStack = []
self.root = dummyRoot
self.ed = self.root.getFirstValueElement()
self.ed = self.root.getFirstValueElement(data)
isFirstElement = False
isDesignated = False

Expand All @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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

Expand All @@ -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:
Expand Down
15 changes: 15 additions & 0 deletions addons/test/misra/misra-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 981ac05

Please sign in to comment.