Skip to content

Commit a5f4d43

Browse files
committed
C++: Fix false positive by adding another allow-list pattern in AssignWhereCompareMeant.
1 parent 7045597 commit a5f4d43

File tree

3 files changed

+20
-9
lines changed

3 files changed

+20
-9
lines changed

cpp/ql/src/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,29 @@ class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
5454
override predicate isWhitelisted() {
5555
this.getConversion().(ParenthesisExpr).isParenthesised()
5656
or
57-
// whitelist this assignment if all comparison operations in the expression that this
57+
// Allow this assignment if all comparison operations in the expression that this
5858
// assignment is part of, are not parenthesized. In that case it seems like programmer
5959
// is fine with unparenthesized comparison operands to binary logical operators, and
6060
// the parenthesis around this assignment was used to call it out as an assignment.
6161
this.isParenthesised() and
6262
forex(ComparisonOperation op | op = getComparisonOperand*(this.getParent+()) |
6363
not op.isParenthesised()
6464
)
65+
or
66+
// Match a pattern like:
67+
// ```
68+
// if((a = b) && use_value(a)) { ... }
69+
// ```
70+
// where the assignment is meant to update the value of `a` before it's used in some other boolean
71+
// subexpression that is guarenteed to be evaluate _after_ the assignment.
72+
this.isParenthesised() and
73+
exists(LogicalAndExpr parent, Variable var, VariableAccess access |
74+
var = this.getLValue().(VariableAccess).getTarget() and
75+
access = var.getAnAccess() and
76+
not access.isUsedAsLValue() and
77+
parent.getRightOperand() = access.getParent*() and
78+
parent.getLeftOperand() = this.getParent*()
79+
)
6580
}
6681
}
6782

cpp/ql/test/query-tests/Likely Bugs/Likely Typos/AssignWhereCompareMeant/AssignWhereCompareMeant.expected

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@
1919
| test.cpp:144:32:144:36 | ... = ... | Use of '=' where '==' may have been intended. |
2020
| test.cpp:150:32:150:36 | ... = ... | Use of '=' where '==' may have been intended. |
2121
| test.cpp:153:46:153:50 | ... = ... | Use of '=' where '==' may have been intended. |
22-
| test.cpp:160:7:160:12 | ... = ... | Use of '=' where '==' may have been intended. |
23-
| test.cpp:162:7:162:12 | ... = ... | Use of '=' where '==' may have been intended. |
24-
| test.cpp:163:7:163:12 | ... = ... | Use of '=' where '==' may have been intended. |
25-
| test.cpp:164:7:164:12 | ... = ... | Use of '=' where '==' may have been intended. |
2622
| test.cpp:166:22:166:27 | ... = ... | Use of '=' where '==' may have been intended. |
2723
| test.cpp:168:24:168:29 | ... = ... | Use of '=' where '==' may have been intended. |
2824
| test.cpp:169:23:169:28 | ... = ... | Use of '=' where '==' may have been intended. |

cpp/ql/test/query-tests/Likely Bugs/Likely Typos/AssignWhereCompareMeant/test.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,11 @@ void f3(int x, int y) {
157157
bool use(int);
158158

159159
void f4(int x, bool b) {
160-
if((x = 10) && use(x)) {} // GOOD [FALSE POSITIVE]: This is likely just a short-hand way of writing an assignment
160+
if((x = 10) && use(x)) {} // GOOD: This is likely just a short-hand way of writing an assignment
161161
// followed by a boolean check.
162-
if((x = 10) && b && use(x)) {} // GOOD [FALSE POSITIVE]: Same reason as above
163-
if((x = 10) && use(x) && b) {} // GOOD [FALSE POSITIVE]: Same reason as above
164-
if((x = 10) && (use(x) && b)) {} // GOOD [FALSE POSITIVE]: Same reason as above
162+
if((x = 10) && b && use(x)) {} // GOOD: Same reason as above
163+
if((x = 10) && use(x) && b) {} // GOOD: Same reason as above
164+
if((x = 10) && (use(x) && b)) {} // GOOD: Same reason as above
165165

166166
if(use(x) && b && (x = 10)) {} // BAD: The assignment is the last thing that happens in the comparison.
167167
// This doesn't match the usual pattern.

0 commit comments

Comments
 (0)