@@ -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-
12096def test_language(language):
12197 return language == 'C++'
12298
12399# def - loop definition checking
124100def 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