Skip to content

Commit a868efc

Browse files
committed
C++: Support
``` x = (a == b) if(x != c) { ... } ``` in guard conditions.
1 parent ccfd383 commit a868efc

File tree

1 file changed

+92
-11
lines changed

1 file changed

+92
-11
lines changed

cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll

Lines changed: 92 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,16 @@ private module Cached {
936936
ValueNumber getUnary() { result.getAnInstruction() = instr.getUnary() }
937937
}
938938

939+
private class ConvertBoolToIntOrPointerInstruction extends ConvertInstruction {
940+
ConvertBoolToIntOrPointerInstruction() {
941+
this.getUnary().getResultIRType() instanceof IRBooleanType and
942+
(
943+
this.getResultIRType() instanceof IRIntegerType or
944+
this.getResultIRType() instanceof IRAddressType
945+
)
946+
}
947+
}
948+
939949
/**
940950
* Holds if `left == right + k` is `areEqual` given that test is `testIsTrue`.
941951
*
@@ -966,6 +976,26 @@ private module Cached {
966976
)
967977
or
968978
compares_eq(test.(BuiltinExpectCallValueNumber).getCondition(), left, right, k, areEqual, value)
979+
or
980+
// If we have e.g.:
981+
// ```
982+
// x = (a == b)
983+
// if(x != c) { ... }
984+
// ```
985+
// then `x != c` is true implies that `a == b` is true.
986+
// ```
987+
exists(Operand l, Operand r, ValueNumber vn, int c, AbstractValue v |
988+
test.(CompareValueNumber).hasOperands(l, r) and
989+
int_value(r.getDef()) = c and
990+
vn.getAnInstruction() = getBooleanInstruction(l.getDef()) and
991+
compares_eq(vn, left, right, k, areEqual, v)
992+
|
993+
test instanceof CompareNEValueNumber and
994+
if c = 0 then value = v else value = v.getDualValue()
995+
or
996+
test instanceof CompareEQValueNumber and
997+
if c = 0 then value = v.getDualValue() else value = v
998+
)
969999
}
9701000

9711001
private predicate isConvertedBool(Instruction instr) {
@@ -1006,19 +1036,24 @@ private module Cached {
10061036
k = k1 + k2
10071037
)
10081038
or
1009-
exists(CompareValueNumber cmp, Operand left, Operand right, AbstractValue v |
1010-
test = cmp and
1011-
pragma[only_bind_into](cmp)
1012-
.hasOperands(pragma[only_bind_into](left), pragma[only_bind_into](right)) and
1013-
isConvertedBool(left.getDef()) and
1014-
int_value(right.getDef()) = 0 and
1015-
unary_compares_eq(valueNumberOfOperand(left), op, k, areEqual, v)
1039+
// If we have e.g.:
1040+
// ```
1041+
// x = (a == 10)
1042+
// if(x != c) { ... }
1043+
// ```
1044+
// then `x != c` is true implies that `a == 10` is true.
1045+
// ```
1046+
exists(Operand l, Operand r, ValueNumber vn, int c, AbstractValue v |
1047+
test.(CompareValueNumber).hasOperands(l, r) and
1048+
int_value(r.getDef()) = c and
1049+
vn.getAnInstruction() = getBooleanInstruction(l.getDef()) and
1050+
compares_lt(vn, op, k, areEqual, v)
10161051
|
1017-
cmp instanceof CompareNEValueNumber and
1018-
v = value
1052+
test instanceof CompareNEValueNumber and
1053+
if c = 0 then value = v else value = v.getDualValue()
10191054
or
1020-
cmp instanceof CompareEQValueNumber and
1021-
v.getDualValue() = value
1055+
test instanceof CompareEQValueNumber and
1056+
if c = 0 then value = v.getDualValue() else value = v
10221057
)
10231058
or
10241059
unary_compares_eq(test.(BuiltinExpectCallValueNumber).getCondition(), op, k, areEqual, value)
@@ -1192,6 +1227,12 @@ private module Cached {
11921227
unary_builtin_expect_eq(test, op, k, areEqual, value)
11931228
}
11941229

1230+
private Instruction getBooleanInstruction(Instruction instr) {
1231+
result = instr.(ConvertBoolToIntOrPointerInstruction).getUnary()
1232+
or
1233+
result = getBooleanInstruction(instr.(CopyInstruction).getSourceValue())
1234+
}
1235+
11951236
/*
11961237
* Simplification of inequality expressions
11971238
* Simplify conditions in the source to the canonical form l < r + k.
@@ -1215,6 +1256,26 @@ private module Cached {
12151256
exists(AbstractValue dual | value = dual.getDualValue() |
12161257
compares_lt(test.(LogicalNotValueNumber).getUnary(), left, right, k, isLt, dual)
12171258
)
1259+
or
1260+
// If we have e.g.:
1261+
// ```
1262+
// x = (a < b)
1263+
// if(x != c) { ... }
1264+
// ```
1265+
// then `x != c` is true implies that `a < b` is true.
1266+
// ```
1267+
exists(Operand l, Operand r, ValueNumber vn, int c, AbstractValue v |
1268+
test.(CompareValueNumber).hasOperands(l, r) and
1269+
int_value(r.getDef()) = c and
1270+
vn.getAnInstruction() = getBooleanInstruction(l.getDef()) and
1271+
compares_lt(vn, left, right, k, isLt, v)
1272+
|
1273+
test instanceof CompareNEValueNumber and
1274+
if c = 0 then value = v else value = v.getDualValue()
1275+
or
1276+
test instanceof CompareEQValueNumber and
1277+
if c = 0 then value = v.getDualValue() else value = v
1278+
)
12181279
}
12191280

12201281
/** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */
@@ -1234,6 +1295,26 @@ private module Cached {
12341295
int_value(const) = k1 and
12351296
k = k1 + k2
12361297
)
1298+
or
1299+
// If we have e.g.:
1300+
// ```
1301+
// x = (a < 10)
1302+
// if(x != c) { ... }
1303+
// ```
1304+
// then `x != c` is true implies that `a < 10` is true.
1305+
// ```
1306+
exists(Operand l, Operand r, ValueNumber vn, int c, AbstractValue v |
1307+
test.(CompareValueNumber).hasOperands(l, r) and
1308+
int_value(r.getDef()) = c and
1309+
vn.getAnInstruction() = getBooleanInstruction(l.getDef()) and
1310+
compares_lt(vn, op, k, isLt, v)
1311+
|
1312+
test instanceof CompareNEValueNumber and
1313+
if c = 0 then value = v else value = v.getDualValue()
1314+
or
1315+
test instanceof CompareEQValueNumber and
1316+
if c = 0 then value = v.getDualValue() else value = v
1317+
)
12371318
}
12381319

12391320
/** `(a < b + k) => (b > a - k) => (b >= a + (1-k))` */

0 commit comments

Comments
 (0)