Skip to content

Commit 61686f8

Browse files
jfdevergeJean-François DEVERGE
authored andcommitted
fix: improve misra.py for missing prototype false positives
1 parent 2e19539 commit 61686f8

3 files changed

Lines changed: 49 additions & 3 deletions

File tree

addons/misra.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,20 @@ def is_source_file(file):
538538
return file.endswith('.c')
539539

540540

541+
def has_prior_function_prototype(cfg, function):
542+
"""Return whether a global prototype precedes the function definition."""
543+
for token in cfg.tokenlist:
544+
if token == function.tokenDef:
545+
break
546+
if token.str != function.name or token.scope.type != 'Global':
547+
continue
548+
opening = token.next
549+
if opening and opening.str == '(' and opening.link and \
550+
opening.link.next and opening.link.next.str == ';':
551+
return True
552+
return False
553+
554+
541555
def is_header(file):
542556
return file.endswith('.h')
543557

@@ -803,7 +817,8 @@ def get_function_pointer_type(tok):
803817
ret += '('
804818
tok = tok.next.next
805819
while tok and (tok.str not in '()'):
806-
ret += ' ' + tok.str
820+
if tok.varId is None:
821+
ret += ' ' + tok.str
807822
tok = tok.next
808823
if (tok is None) or tok.str != ')':
809824
return None
@@ -2248,6 +2263,8 @@ def misra_8_4(self, cfg):
22482263
continue
22492264
if func.token != func.tokenDef:
22502265
continue
2266+
if has_prior_function_prototype(cfg, func):
2267+
continue
22512268
if func.tokenDef.str == 'main':
22522269
continue
22532270
self.reportError(func.tokenDef, 8, 4)
@@ -3497,8 +3514,9 @@ def misra_17_3(self, cfg):
34973514

34983515
# Additional check for implicit function calls in expressions
34993516
for token in cfg.tokenlist:
3500-
if token.isName and token.function is None and token.valueType is None:
3501-
if token.next and token.next.str == "(" and token.next.valueType is None:
3517+
if token.isName and token.scope.type != 'Global' and token.function is None and token.valueType is None:
3518+
if token.next and token.next.str == "(" and token.next.valueType is None and \
3519+
isFunctionCall(token.next, cfg.standards.c):
35023520
if token.next.next.str == "*" and \
35033521
token.next.next.next.isName and token.next.next.next.valueType is not None and \
35043522
token.next.next.next.valueType.pointer > 0 :
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
int regression_function(int value);
2+
3+
int regression_function(int value)
4+
{
5+
return value;
6+
}
7+
8+
int main(void)
9+
{
10+
int local_prototype(int value);
11+
int (*callback)(int) = regression_function;
12+
return callback(0);
13+
}

addons/test/misra_test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from addons.misra import C11_STDLIB_IDENTIFIERS, C99_STDLIB_IDENTIFIERS,C90_STDLIB_IDENTIFIERS, isStdLibId, isKeyword
1212

1313
TEST_SOURCE_FILES = [os.path.join('addons','test','misra','misra-test.c')]
14+
REGRESSION_SOURCE_FILE = os.path.join('addons', 'test', 'misra', 'misra-regression-prototypes.c')
1415

1516

1617
def remove_misra_config(s:str):
@@ -93,6 +94,20 @@ def test_json_out(checker, capsys, test_files):
9394
assert("Required" in json_output['c2012-21.3'][0]['extra'])
9495
assert("Advisory" in json_output['c2012-20.1'][0]['extra'])
9596

97+
def test_function_prototype_and_pointer_call_regressions(checker, capsys):
98+
dump_create(REGRESSION_SOURCE_FILE)
99+
sys.argv.append("--cli")
100+
try:
101+
checker.loadRuleTexts("./addons/test/misra/misra_rules_dummy.txt")
102+
checker.parseDump(REGRESSION_SOURCE_FILE + ".dump")
103+
captured = capsys.readouterr().out
104+
json_output = convert_json_output(captured.splitlines())
105+
assert "c2012-8.4" not in json_output
106+
assert "c2012-17.3" not in json_output
107+
finally:
108+
sys.argv.remove("--cli")
109+
dump_remove(REGRESSION_SOURCE_FILE)
110+
96111

97112
def test_rules_cppcheck_severity(checker, capsys, test_files):
98113
checker.loadRuleTexts("./addons/test/misra/misra_rules_dummy.txt")

0 commit comments

Comments
 (0)