Skip to content

Commit 300ea6b

Browse files
Checks: Fixed: Falsepositives in MISRA08_6-5-5 #4880 [autosync]
1 parent 6255e0a commit 300ea6b

2 files changed

Lines changed: 96 additions & 49 deletions

File tree

CodeCheck/Published Standards/AUTOSAR/M6-5-5/M6-5-5.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,54 @@ void f()
4545

4646
for(int x =0, y=10; x>y; x++, y--) // UndCC_Valid
4747
{
48-
48+
4949
}
5050

5151
}
52+
53+
// Issue #4880: false positives reported by wmullen@dekaresearch.com
54+
55+
class Parameter {
56+
public:
57+
void clear() {}
58+
};
59+
60+
class Container {
61+
unsigned m_count;
62+
Parameter* m_params[10];
63+
public:
64+
unsigned numParameters() { return m_count; }
65+
Parameter* operator[](unsigned i) { return m_params[i]; }
66+
void addParameter(Parameter* p) { m_params[m_count++] = p; }
67+
void parameters_clear()
68+
{
69+
// Function call in condition whose return-entity is modified elsewhere
70+
// must not be flagged as a loop-control-variable modification.
71+
for (unsigned i = 0u; i < numParameters(); i++) // UndCC_Valid
72+
{
73+
m_params[i]->clear();
74+
}
75+
}
76+
};
77+
78+
struct FileEntry { const char* name; };
79+
struct FileList {
80+
FileEntry* begin() { return nullptr; }
81+
FileEntry* end() { return nullptr; }
82+
};
83+
84+
struct JsonObject { JsonObject() {} };
85+
86+
void range_based_for_is_not_a_classic_for(FileList& files)
87+
{
88+
// Range-based for loops have no init/condition/expression structure,
89+
// so this rule does not apply.
90+
int counter = 0;
91+
for (const FileEntry& entry : files) // UndCC_Valid
92+
{
93+
JsonObject obj;
94+
counter = 1;
95+
(void)obj;
96+
(void)entry;
97+
}
98+
}

CodeCheck/Published Standards/AUTOSAR/M6-5-5/check.upy

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -93,73 +93,73 @@ def check_entity(ent, ctr_ent):
9393
return True
9494
return False
9595

96-
# def - function definition checking
97-
def validate_function(lex):
98-
bool_return = False
99-
ent_func = lex.ent()
100-
101-
if ent_func.ref("Return"):
102-
bool_return = ent_func.ref("Return").ent().ref("Modifyby, Setby")
103-
104-
# move lex to the end of function definition to skip parameter entities
105-
while lex and lex.text() != "(":
106-
lex = lex.next(ignore_whitespace=True,ignore_comments=True)
107-
lex = lex.next(ignore_whitespace=True,ignore_comments=True)
108-
paren = 1
109-
while lex and paren != 0:
110-
if lex.text() == "(":
111-
paren = paren + 1
112-
if lex.text() == ")":
113-
paren = paren - 1
114-
lex = lex.next(ignore_whitespace=True,ignore_comments=True)
115-
116-
# check if return entity value was modified or set
117-
# return lex to skip the whole function call
118-
return bool_return, lex
119-
12096
def test_language(language):
12197
return language == 'C++'
12298

12399
# def - loop definition checking
124100
def validate_loop(lex, file, check):
125-
# get the for loop entity
101+
# Pass 1: collect loop-counter entities from the init clause.
102+
# The MISRA rule targets traditional for(init; cond; expr) loops; a
103+
# range-based for has no separate init/condition/expression, so bail out
104+
# if we see ':' (or close the for-parens) before a ';'.
126105
ctr_ent = []
127-
while lex and lex.text() != ";":
128-
if lex.ent() and lex.ent().kind().check("Object"):
106+
paren = 0
107+
while lex:
108+
if lex.text() == "(":
109+
paren += 1
110+
elif lex.text() == ")":
111+
paren -= 1
112+
if paren == 0:
113+
return # closed for(...) without an init-clause terminator
114+
elif paren == 1 and lex.text() == ":":
115+
return # range-based for loop — rule does not apply
116+
elif paren == 1 and lex.text() == ";":
117+
break # end of init clause
118+
elif lex.ent() and lex.ent().kind().check("Object"):
129119
ctr_ent.append(lex.ent())
130-
lex = lex.next(ignore_whitespace=True,ignore_comments=True)
131-
lex = lex.next(ignore_whitespace=True,ignore_comments=True)
132-
133-
# init variables
120+
lex = lex.next(ignore_whitespace=True, ignore_comments=True)
121+
122+
if not lex:
123+
return
124+
lex = lex.next(ignore_whitespace=True, ignore_comments=True)
125+
126+
# Pass 2: scan condition + expression for modifications of non-counter
127+
# loop-control-variables. Flag two patterns:
128+
# 1) Direct Modifyby/Setby on a non-counter Object on this line.
129+
# 2) `&var` taking the address of a non-counter Object — the address
130+
# may flow into a function that mutates the variable through the
131+
# pointer. Per-function dataflow would be more precise but is out
132+
# of scope; this heuristic preserves coverage of the canonical
133+
# `test_a(&bool_a)` example from MISRA C++ 2008 6-5-5.
134134
paren = 1
135135
is_breach = False
136136
ent_breach = None
137-
# traverse thru all the entities inside for loop
137+
line, column = -1, -1
138+
prev_text = None
138139
while lex and paren != 0 and len(ctr_ent) != 0:
139140
if lex.text() == "(":
140-
paren = paren + 1
141-
if lex.text() == ")":
142-
paren = paren - 1
141+
paren += 1
142+
elif lex.text() == ")":
143+
paren -= 1
143144

144-
if lex.ent() and not check_entity(lex.ent(), ctr_ent):
145-
line, column = -1, -1
145+
if lex.ent() and lex.ent().kind().check("Object") and not check_entity(lex.ent(), ctr_ent):
146146
for ref in lex.ent().refs():
147-
if lex.ent() and lex.line_begin() == ref.line() and file == ref.file():
148-
# check if modify or set
149-
if ref.kind().check("Modifyby, Setby") and lex.ent().kind().check("Object"):
147+
if lex.line_begin() == ref.line() and file == ref.file():
148+
if ref.kind().check("Modifyby, Setby"):
150149
ent_breach = lex.ent()
151150
line, column = lex.line_begin(), lex.column_begin()
152151
is_breach = True
153152
paren = 0
154-
# if function, check for further details
155-
elif ref.kind().check("Callby") and lex.ent().kind().check("Function"):
156-
ent_breach = lex.ent()
157-
line, column = lex.line_begin(), lex.column_begin()
158-
is_breach, lex = validate_function(lex)
159-
paren = 0
160-
lex = lex.next(ignore_whitespace=True,ignore_comments=True)
153+
break
154+
if not is_breach and prev_text == "&":
155+
ent_breach = lex.ent()
156+
line, column = lex.line_begin(), lex.column_begin()
157+
is_breach = True
158+
paren = 0
159+
160+
prev_text = lex.text()
161+
lex = lex.next(ignore_whitespace=True, ignore_comments=True)
161162

162-
# entity validation
163163
if is_breach:
164164
check.violation(ent_breach, file, line, column, ERR1)
165165

0 commit comments

Comments
 (0)