Skip to content

Commit 0f0170a

Browse files
authored
Merge branch 'main' into rvermeulen/fix-424
2 parents 1d5a2a8 + d087031 commit 0f0170a

15 files changed

+163
-6
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
`M8-5-2` - `AggregateLiteralEnhancements.qll`:
2+
- recognise aggregate literals initialized with parameters from variadic templates.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `A2-10-1`, `RULE-5-3`:
2+
- Reduce false positives by considering point of declaration for local variables.
3+
- Reduce false negatives by considering catch block parameters to be in scope in the catch block.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `M6-5-5`:
2+
- Reduce false positives by no longer considering the taking of a const reference as a modification.
3+
- Improve detection of non-local modification of loop iteration variables to reduce false positives.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
`M5-2-10` - `IncrementAndDecrementOperatorsMixedWithOtherOperatorsInExpression.ql`:
2+
- only report use of the increment and decrement operations in conjunction with arithmetic operators, as specified by the rule. Notably we no longer report the expressions of the form `*p++`, which combine increment and dereferencing operations.

cpp/autosar/src/rules/M5-2-10/IncrementAndDecrementOperatorsMixedWithOtherOperatorsInExpression.ql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616

1717
import cpp
1818
import codingstandards.cpp.autosar
19+
import codingstandards.cpp.Expr
1920

20-
from CrementOperation cop, Operation op, string name
21+
from CrementOperation cop, ArithmeticOperation op, string name
2122
where
2223
not isExcluded(cop) and
2324
not isExcluded(op,

cpp/autosar/test/rules/M5-2-10/test.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ void f1() {
66
++l1; // COMPLIANT
77
--l2; // COMPLIANT
88
l3 = l1 * l2;
9+
int *p;
10+
*p++; // COMPLIANT - * is not an arithmetic operator
911
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
| test.cpp:24:8:24:15 | testFlag | Loop control variable testFlag is modified in the loop update expression. |
2+
| test.cpp:47:12:47:12 | y | Loop control variable y is modified in the loop update expression. |

cpp/autosar/test/rules/M6-5-5/test.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,27 @@ void test_loop_control_variable_modified_in_expression() {
2424
testFlag = updateFlagWithIncrement(++x)) { // NON_COMPLIANT
2525
}
2626
}
27+
28+
#include <vector>
29+
30+
void test_const_refs(std::vector<int> v) {
31+
std::vector<int>::iterator first = v.begin();
32+
std::vector<int>::iterator last = v.end();
33+
// call to operator!= passes a const reference to first
34+
for (; first != last; first++) { // COMPLIANT
35+
}
36+
}
37+
38+
void update(std::vector<int>::iterator &f, const int &x, int &y) {}
39+
40+
void test_const_refs_update(std::vector<int> v) {
41+
std::vector<int>::iterator last = v.end();
42+
int x = 0;
43+
int y = 0;
44+
// call to operator!= passes a const reference to first
45+
for (std::vector<int>::iterator first = v.begin(); first != last; update(
46+
first, x, // COMPLIANT - first is a loop counter, so can be modified
47+
y)) { // NON_COMPLIANT - y is modified and is not a loop counter
48+
first + 1;
49+
}
50+
}

cpp/autosar/test/rules/M8-5-2/test.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,13 @@ void test() {
5555
Bar b2{{0}}; // NON_COMPLIANT - missing explicit init, nested zero init
5656
StructNested n{}; // COMPLIANT
5757
StructNested n1 = {}; // COMPLIANT
58-
}
58+
}
59+
60+
#include <initializer_list>
61+
template <class T> bool all_of(std::initializer_list<T>);
62+
63+
template <typename... Args> constexpr bool all_of(Args... args) noexcept {
64+
return all_of({args...}); // COMPLIANT - explicitly initialized via varargs
65+
}
66+
67+
void test_all_of() { all_of(true, false, false); }

cpp/common/src/codingstandards/cpp/Expr.qll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@ import cpp
22
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
33
import codingstandards.cpp.AccessPath
44

5+
/**
6+
* A unary or binary arithmetic operation.
7+
*/
8+
class ArithmeticOperation extends Operation {
9+
ArithmeticOperation() {
10+
this instanceof UnaryArithmeticOperation or this instanceof BinaryArithmeticOperation
11+
}
12+
}
13+
514
/** A full expression as defined in [intro.execution] of N3797. */
615
class FullExpr extends Expr {
716
FullExpr() {

cpp/common/src/codingstandards/cpp/Loops.qll

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ class MemberAssignmentOperation extends FunctionCall {
7070
*/
7171
pragma[noopt]
7272
Variable getALoopCounter(ForStmt fs) {
73+
// ------------------------------------------------------------------------------------------------
74+
// NOTE: This is an updated version of ForStmt.getAnIterationVariable(), handling additional cases.
75+
// The use of pragma[noopt] is retained from the original code, as we haven't determined
76+
// whether it's still necessary across a broad range of databases. As a noopt predicate, it
77+
// includes a degree of duplication as the join order is defined based on the order of the
78+
// conditions.
79+
// ------------------------------------------------------------------------------------------------
7380
// check that it is assigned to, incremented or decremented in the update
7481
exists(Expr updateOpRoot, Expr updateOp |
7582
updateOpRoot = fs.getUpdate() and
@@ -106,6 +113,15 @@ Variable getALoopCounter(ForStmt fs) {
106113
)
107114
or
108115
updateOp = result.getAnAssignedValue()
116+
or
117+
// updateOp is an access whose address is taken in a non-const way
118+
exists(FunctionCall fc, VariableAccess va |
119+
fc = updateOp and
120+
fc instanceof FunctionCall and
121+
fc.getAnArgument() = va and
122+
va = result.getAnAccess() and
123+
va.isAddressOfAccessNonConst()
124+
)
109125
) and
110126
result instanceof Variable and
111127
// checked or used in the condition
@@ -260,7 +276,7 @@ predicate isLoopControlVarModifiedInLoopCondition(
260276
loopControlVariableAccess = forLoop.getCondition().getAChild+() and
261277
(
262278
loopControlVariableAccess.isModified() or
263-
loopControlVariableAccess.isAddressOfAccess()
279+
loopControlVariableAccess.isAddressOfAccessNonConst()
264280
)
265281
}
266282

@@ -277,7 +293,7 @@ predicate isLoopControlVarModifiedInLoopExpr(
277293
loopControlVariableAccess = forLoop.getUpdate().getAChild() and
278294
(
279295
loopControlVariableAccess.isModified() or
280-
loopControlVariableAccess.isAddressOfAccess()
296+
loopControlVariableAccess.isAddressOfAccessNonConst()
281297
)
282298
}
283299

cpp/common/src/codingstandards/cpp/Scope.qll

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,16 @@ private Element getParentScope(Element e) {
4242
then result = e.getParentScope()
4343
else (
4444
// Statements do no have a parent scope, so return the enclosing block.
45-
result = e.(Stmt).getEnclosingBlock() or result = e.(Expr).getEnclosingBlock()
45+
result = e.(Stmt).getEnclosingBlock()
46+
or
47+
result = e.(Expr).getEnclosingBlock()
48+
or
49+
// Catch block parameters don't have an enclosing scope, so attach them to the
50+
// the block itself
51+
exists(CatchBlock cb |
52+
e = cb.getParameter() and
53+
result = cb
54+
)
4655
)
4756
}
4857

@@ -209,7 +218,42 @@ private predicate hides_candidateStrict(UserVariable v1, UserVariable v2) {
209218
v2 = getPotentialScopeOfVariableStrict(v1) and
210219
v1.getName() = v2.getName() and
211220
// Member variables cannot hide other variables nor be hidden because the can be referenced through their qualified name.
212-
not (v1.isMember() or v2.isMember())
221+
not (v1.isMember() or v2.isMember()) and
222+
(
223+
// If v1 is a local variable, ensure that v1 is declared before v2
224+
(
225+
v1 instanceof LocalVariable and
226+
// Ignore variables declared in conditional expressions, as they apply to
227+
// the nested scope
228+
not v1 = any(ConditionDeclExpr cde).getVariable() and
229+
// Ignore variables declared in loops
230+
not exists(Loop l | l.getADeclaration() = v1)
231+
)
232+
implies
233+
exists(BlockStmt bs, DeclStmt v1Stmt, Stmt v2Stmt |
234+
v1 = v1Stmt.getADeclaration() and
235+
getEnclosingStmt(v2).getParentStmt*() = v2Stmt
236+
|
237+
bs.getIndexOfStmt(v1Stmt) <= bs.getIndexOfStmt(v2Stmt)
238+
)
239+
)
240+
}
241+
242+
/**
243+
* Gets the enclosing statement of the given variable, if any.
244+
*/
245+
private Stmt getEnclosingStmt(LocalScopeVariable v) {
246+
result.(DeclStmt).getADeclaration() = v
247+
or
248+
exists(ConditionDeclExpr cde |
249+
cde.getVariable() = v and
250+
result = cde.getEnclosingStmt()
251+
)
252+
or
253+
exists(CatchBlock cb |
254+
cb.getParameter() = v and
255+
result = cb.getEnclosingStmt()
256+
)
213257
}
214258

215259
/** Holds if `v2` hides `v1`. */

cpp/common/src/codingstandards/cpp/enhancements/AggregateLiteralEnhancements.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ module ArrayAggregateLiterals {
8585
// The aggregate itself not be compiler generated, or in a macro expansion, otherwise our line numbers will be off
8686
not cal.isCompilerGenerated() and
8787
not cal.isInMacroExpansion() and
88+
// Ignore cases where the compilerGenerated value is a variable access targeting
89+
// a parameter, as these are generated from variadic templates
90+
not compilerGeneratedVal.(VariableAccess).getTarget() instanceof Parameter and
8891
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
8992
compilerGeneratedVal.getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn) and
9093
previousExpr

cpp/common/test/rules/identifierhidden/IdentifierHidden.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@
55
| test.cpp:23:13:23:15 | id1 | Variable is hiding variable $@. | test.cpp:1:5:1:7 | id1 | id1 |
66
| test.cpp:26:12:26:14 | id1 | Variable is hiding variable $@. | test.cpp:1:5:1:7 | id1 | id1 |
77
| test.cpp:27:14:27:16 | id1 | Variable is hiding variable $@. | test.cpp:26:12:26:14 | id1 | id1 |
8+
| test.cpp:65:11:65:11 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i |
9+
| test.cpp:67:9:67:9 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i |
10+
| test.cpp:70:12:70:12 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i |
11+
| test.cpp:75:16:75:16 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i |

cpp/common/test/rules/identifierhidden/test.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,38 @@ template <class T> constexpr T foo1 = T(1.1L);
4040
template <class T, class R> T f(T r) {
4141
T v = foo1<T> * r * r; // COMPLIANT
4242
T v1 = foo1<R> * r * r; // COMPLIANT
43+
}
44+
45+
void test_scope_order() {
46+
{
47+
{
48+
int i; // COMPLIANT
49+
}
50+
int i; // COMPLIANT
51+
}
52+
53+
for (int i = 0; i < 10; i++) { // COMPLIANT
54+
}
55+
56+
try {
57+
58+
} catch (int i) { // COMPLIANT
59+
}
60+
61+
int i; // COMPLIANT
62+
63+
{
64+
{
65+
int i; // NON_COMPLIANT
66+
}
67+
int i; // NON_COMPLIANT
68+
}
69+
70+
for (int i = 0; i < 10; i++) { // NON_COMPLIANT
71+
}
72+
73+
try {
74+
75+
} catch (int i) { // NON_COMPLIANT
76+
}
4377
}

0 commit comments

Comments
 (0)