diff --git a/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll index bcd214ec0000..83f8dc8b3bc7 100644 --- a/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll +++ b/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll @@ -790,6 +790,27 @@ private predicate simple_comparison_eq(Instruction test, Operand op, int k, Abst exists(switch.getSuccessor(case)) and case.getValue().toInt() = k ) + or + // There's no implicit CompareInstruction in files compiled as C since C + // doesn't have implicit boolean conversions. So instead we check whether + // there's a branch on a value of pointer or integer type. + exists(ConditionalBranchInstruction branch, IRType type | + not test instanceof CompareInstruction and + type = test.getResultIRType() and + (type instanceof IRAddressType or type instanceof IRIntegerType) and + test = branch.getCondition() and + op.getDef() = test + | + // We'd like to also include a case such as: + // ``` + // k = 1 and + // value.(BooleanValue).getValue() = true + // ``` + // but all we know is that the value is non-zero in the true branch. + // So we can only conclude something in the false branch. + k = 0 and + value.(BooleanValue).getValue() = false + ) } private predicate complex_eq( diff --git a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected index 943d7028a5d2..d50ca1609163 100644 --- a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected +++ b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected @@ -148,6 +148,24 @@ astGuardsCompare | 109 | y < 0+0 when ... < ... is true | | 109 | y >= 0+0 when ... < ... is false | | 109 | y >= 0+0 when ... \|\| ... is false | +| 126 | 1 != 0 when 1 is true | +| 126 | 1 != 0 when ... && ... is true | +| 126 | 1 == 0 when 1 is false | +| 126 | call to test3_condition != 0 when ... && ... is true | +| 126 | call to test3_condition != 0 when call to test3_condition is true | +| 126 | call to test3_condition == 0 when call to test3_condition is false | +| 131 | b != 0 when b is true | +| 131 | b == 0 when b is false | +| 137 | 0 != 0 when 0 is true | +| 137 | 0 == 0 when 0 is false | +| 146 | ! ... != 0 when ! ... is true | +| 146 | ! ... == 0 when ! ... is false | +| 152 | x != 0 when ... && ... is true | +| 152 | x != 0 when x is true | +| 152 | x == 0 when x is false | +| 152 | y != 0 when ... && ... is true | +| 152 | y != 0 when y is true | +| 152 | y == 0 when y is false | | 156 | ... + ... != x+0 when ... == ... is false | | 156 | ... + ... == x+0 when ... == ... is true | | 156 | x != ... + ...+0 when ... == ... is false | @@ -186,6 +204,8 @@ astGuardsCompare | 175 | call to foo != 0+0 when ... == ... is false | | 175 | call to foo == 0 when ... == ... is true | | 175 | call to foo == 0+0 when ... == ... is true | +| 181 | x != 0 when x is true | +| 181 | x == 0 when x is false | astGuardsControl | test.c:7:9:7:13 | ... > ... | false | 10 | 11 | | test.c:7:9:7:13 | ... > ... | true | 7 | 9 | @@ -487,8 +507,27 @@ astGuardsEnsure_const | test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 109 | 109 | | test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 | | test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 | +| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 | +| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 | +| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 | +| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 | +| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 | +| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 | +| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 | +| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 | +| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 | +| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 | +| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 | +| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 151 | 152 | +| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 152 | 152 | +| test.c:152:10:152:15 | ... && ... | test.c:152:10:152:10 | x | != | 0 | 151 | 152 | +| test.c:152:10:152:15 | ... && ... | test.c:152:15:152:15 | y | != | 0 | 151 | 152 | +| test.c:152:15:152:15 | y | test.c:152:15:152:15 | y | != | 0 | 151 | 152 | | test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | != | 0 | 175 | 175 | | test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | == | 0 | 175 | 175 | +| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 181 | 182 | +| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 186 | 180 | +| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | == | 0 | 183 | 184 | | test.cpp:18:8:18:10 | call to get | test.cpp:18:8:18:10 | call to get | != | 0 | 19 | 19 | | test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 30 | 30 | | test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 | @@ -640,6 +679,20 @@ irGuardsCompare | 109 | y < 0+0 when CompareLT: ... < ... is true | | 109 | y >= 0 when CompareLT: ... < ... is false | | 109 | y >= 0+0 when CompareLT: ... < ... is false | +| 126 | 1 != 0 when Constant: 1 is true | +| 126 | 1 == 0 when Constant: 1 is false | +| 126 | call to test3_condition != 0 when Call: call to test3_condition is true | +| 126 | call to test3_condition == 0 when Call: call to test3_condition is false | +| 131 | b != 0 when Load: b is true | +| 131 | b == 0 when Load: b is false | +| 137 | 0 != 0 when Constant: 0 is true | +| 137 | 0 == 0 when Constant: 0 is false | +| 146 | ! ... != 0 when LogicalNot: ! ... is true | +| 146 | ! ... == 0 when LogicalNot: ! ... is false | +| 152 | x != 0 when Load: x is true | +| 152 | x == 0 when Load: x is false | +| 152 | y != 0 when Load: y is true | +| 152 | y == 0 when Load: y is false | | 156 | ... + ... != x+0 when CompareEQ: ... == ... is false | | 156 | ... + ... == x+0 when CompareEQ: ... == ... is true | | 156 | x != ... + ...+0 when CompareEQ: ... == ... is false | @@ -678,6 +731,8 @@ irGuardsCompare | 175 | call to foo != 0+0 when CompareEQ: ... == ... is false | | 175 | call to foo == 0 when CompareEQ: ... == ... is true | | 175 | call to foo == 0+0 when CompareEQ: ... == ... is true | +| 181 | x != 0 when Load: x is true | +| 181 | x == 0 when Load: x is false | irGuardsControl | test.c:7:9:7:13 | CompareGT: ... > ... | false | 11 | 11 | | test.c:7:9:7:13 | CompareGT: ... > ... | true | 8 | 8 | @@ -999,8 +1054,21 @@ irGuardsEnsure_const | test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 109 | 109 | | test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 113 | 113 | | test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:19 | Load: y | >= | 0 | 113 | 113 | +| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 126 | 126 | +| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 127 | 127 | +| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 131 | 131 | +| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 132 | 132 | +| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 134 | 134 | +| test.c:126:12:126:26 | Call: call to test3_condition | test.c:126:12:126:26 | Call: call to test3_condition | != | 0 | 127 | 127 | +| test.c:131:7:131:7 | Load: b | test.c:131:7:131:7 | Load: b | != | 0 | 132 | 132 | +| test.c:137:7:137:7 | Constant: 0 | test.c:137:7:137:7 | Constant: 0 | == | 0 | 142 | 142 | +| test.c:146:7:146:8 | LogicalNot: ! ... | test.c:146:7:146:8 | LogicalNot: ! ... | != | 0 | 147 | 147 | +| test.c:152:10:152:10 | Load: x | test.c:152:10:152:10 | Load: x | != | 0 | 152 | 152 | +| test.c:152:15:152:15 | Load: y | test.c:152:15:152:15 | Load: y | != | 0 | 152 | 152 | | test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | != | 0 | 175 | 175 | | test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | == | 0 | 175 | 175 | +| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | != | 0 | 182 | 182 | +| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | == | 0 | 184 | 184 | | test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | 0 | 19 | 19 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | -1 | 34 | 34 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 30 | 30 | diff --git a/cpp/ql/test/library-tests/controlflow/guards/Guards.expected b/cpp/ql/test/library-tests/controlflow/guards/Guards.expected index 08a8a9281bb1..13d6c2b654ff 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/Guards.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/Guards.expected @@ -26,6 +26,12 @@ | test.c:137:7:137:7 | 0 | | test.c:146:7:146:8 | ! ... | | test.c:146:8:146:8 | x | +| test.c:152:8:152:8 | p | +| test.c:158:8:158:9 | ! ... | +| test.c:158:9:158:9 | p | +| test.c:164:8:164:8 | s | +| test.c:170:8:170:9 | ! ... | +| test.c:170:9:170:9 | s | | test.cpp:18:8:18:10 | call to get | | test.cpp:31:7:31:13 | ... == ... | | test.cpp:42:13:42:20 | call to getABool | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected index 756140604e13..a2f418b3d7bb 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected @@ -149,3 +149,23 @@ | 111 | 0.0 == i+0 when ... != ... is false | | 111 | i != 0.0+0 when ... != ... is true | | 111 | i == 0.0+0 when ... != ... is false | +| 126 | 1 != 0 when 1 is true | +| 126 | 1 != 0 when ... && ... is true | +| 126 | 1 == 0 when 1 is false | +| 126 | call to test3_condition != 0 when ... && ... is true | +| 126 | call to test3_condition != 0 when call to test3_condition is true | +| 126 | call to test3_condition == 0 when call to test3_condition is false | +| 131 | b != 0 when b is true | +| 131 | b == 0 when b is false | +| 137 | 0 != 0 when 0 is true | +| 137 | 0 == 0 when 0 is false | +| 146 | ! ... != 0 when ! ... is true | +| 146 | ! ... == 0 when ! ... is false | +| 152 | p != 0 when p is true | +| 152 | p == 0 when p is false | +| 158 | ! ... != 0 when ! ... is true | +| 158 | ! ... == 0 when ! ... is false | +| 164 | s != 0 when s is true | +| 164 | s == 0 when s is false | +| 170 | ! ... != 0 when ! ... is true | +| 170 | ! ... == 0 when ! ... is false | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected index 62d9b0a12294..cf36a58a515b 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected @@ -79,6 +79,12 @@ | test.c:137:7:137:7 | 0 | false | 142 | 136 | | test.c:146:7:146:8 | ! ... | true | 146 | 147 | | test.c:146:8:146:8 | x | false | 146 | 147 | +| test.c:152:8:152:8 | p | true | 152 | 154 | +| test.c:158:8:158:9 | ! ... | true | 158 | 160 | +| test.c:158:9:158:9 | p | false | 158 | 160 | +| test.c:164:8:164:8 | s | true | 164 | 166 | +| test.c:170:8:170:9 | ! ... | true | 170 | 172 | +| test.c:170:9:170:9 | s | false | 170 | 172 | | test.cpp:18:8:18:10 | call to get | true | 19 | 19 | | test.cpp:31:7:31:13 | ... == ... | false | 30 | 30 | | test.cpp:31:7:31:13 | ... == ... | false | 34 | 34 | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected index f9eaced1276a..45d63f6dd536 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected @@ -234,6 +234,21 @@ unary | test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 | | test.c:109:9:109:23 | ... \|\| ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 | | test.c:109:19:109:23 | ... < ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 | +| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 | +| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 | +| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 | +| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 | +| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 | +| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 | +| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 | +| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 | +| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 | +| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 | +| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 | +| test.c:152:8:152:8 | p | test.c:152:8:152:8 | p | != | 0 | 152 | 154 | +| test.c:158:8:158:9 | ! ... | test.c:158:8:158:9 | ! ... | != | 0 | 158 | 160 | +| test.c:164:8:164:8 | s | test.c:164:8:164:8 | s | != | 0 | 164 | 166 | +| test.c:170:8:170:9 | ! ... | test.c:170:8:170:9 | ! ... | != | 0 | 170 | 172 | | test.cpp:18:8:18:10 | call to get | test.cpp:18:8:18:10 | call to get | != | 0 | 19 | 19 | | test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 30 | 30 | | test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 | diff --git a/cpp/ql/test/library-tests/controlflow/guards/test.c b/cpp/ql/test/library-tests/controlflow/guards/test.c index 186244d4fca2..207e23baa0e3 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/test.c +++ b/cpp/ql/test/library-tests/controlflow/guards/test.c @@ -147,3 +147,27 @@ void test5(int x) { test3(); } } + +void test6(char* p) { + if(p) { + + } +} + +void test7(char* p) { + if(!p) { + + } +} + +void test8(short s) { + if(s) { + + } +} + +void test9(short s) { + if(!s) { + + } +} \ No newline at end of file