Skip to content

Commit 355fc0a

Browse files
committed
C++: Use Guards library in Overflow.qll
Replaces the ad-hoc guard handling with the Guards library. Fixes an observed false positive pattern, and (hopefully) means some pragmas are no longer necessary for performance.
1 parent 617bdbc commit 355fc0a

File tree

3 files changed

+5
-66
lines changed

3 files changed

+5
-66
lines changed

cpp/ql/lib/semmle/code/cpp/security/Overflow.qll

Lines changed: 4 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,64 +5,27 @@
55

66
import cpp
77
import semmle.code.cpp.controlflow.Dominance
8-
// `GlobalValueNumbering` is only imported to prevent IR re-evaluation.
98
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
109
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
1110
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
11+
import semmle.code.cpp.controlflow.Guards
1212

1313
/**
1414
* Holds if the value of `use` is guarded using `abs`.
1515
*/
1616
predicate guardedAbs(Operation e, Expr use) {
1717
exists(FunctionCall fc | fc.getTarget().getName() = ["abs", "labs", "llabs", "imaxabs"] |
1818
fc.getArgument(0).getAChild*() = use and
19-
guardedLesser(e, fc)
19+
exists(GuardCondition c | c.ensuresLt(use, _, _, e.getBasicBlock(), true))
2020
)
2121
}
2222

23-
/**
24-
* Gets the position of `stmt` in basic block `block` (this is a thin layer
25-
* over `BasicBlock.getNode`, intended to improve performance).
26-
*/
27-
pragma[noinline]
28-
private int getStmtIndexInBlock(BasicBlock block, Stmt stmt) { block.getNode(result) = stmt }
29-
30-
pragma[inline]
31-
private predicate stmtDominates(Stmt dominator, Stmt dominated) {
32-
// In same block
33-
exists(BasicBlock block, int dominatorIndex, int dominatedIndex |
34-
dominatorIndex = getStmtIndexInBlock(block, dominator) and
35-
dominatedIndex = getStmtIndexInBlock(block, dominated) and
36-
dominatedIndex >= dominatorIndex
37-
)
38-
or
39-
// In (possibly) different blocks
40-
bbStrictlyDominates(dominator.getBasicBlock(), dominated.getBasicBlock())
41-
}
42-
4323
/**
4424
* Holds if the value of `use` is guarded to be less than something, and `e`
4525
* is in code controlled by that guard (where the guard condition held).
4626
*/
47-
pragma[nomagic]
4827
predicate guardedLesser(Operation e, Expr use) {
49-
exists(IfStmt c, RelationalOperation guard |
50-
use = guard.getLesserOperand().getAChild*() and
51-
guard = c.getControllingExpr().getAChild*() and
52-
stmtDominates(c.getThen(), e.getEnclosingStmt())
53-
)
54-
or
55-
exists(Loop c, RelationalOperation guard |
56-
use = guard.getLesserOperand().getAChild*() and
57-
guard = c.getControllingExpr().getAChild*() and
58-
stmtDominates(c.getStmt(), e.getEnclosingStmt())
59-
)
60-
or
61-
exists(ConditionalExpr c, RelationalOperation guard |
62-
use = guard.getLesserOperand().getAChild*() and
63-
guard = c.getCondition().getAChild*() and
64-
c.getThen().getAChild*() = e
65-
)
28+
exists(GuardCondition c | c.ensuresLt(use, _, _, e.getBasicBlock(), true))
6629
or
6730
guardedAbs(e, use)
6831
}
@@ -71,25 +34,8 @@ predicate guardedLesser(Operation e, Expr use) {
7134
* Holds if the value of `use` is guarded to be greater than something, and `e`
7235
* is in code controlled by that guard (where the guard condition held).
7336
*/
74-
pragma[nomagic]
7537
predicate guardedGreater(Operation e, Expr use) {
76-
exists(IfStmt c, RelationalOperation guard |
77-
use = guard.getGreaterOperand().getAChild*() and
78-
guard = c.getControllingExpr().getAChild*() and
79-
stmtDominates(c.getThen(), e.getEnclosingStmt())
80-
)
81-
or
82-
exists(Loop c, RelationalOperation guard |
83-
use = guard.getGreaterOperand().getAChild*() and
84-
guard = c.getControllingExpr().getAChild*() and
85-
stmtDominates(c.getStmt(), e.getEnclosingStmt())
86-
)
87-
or
88-
exists(ConditionalExpr c, RelationalOperation guard |
89-
use = guard.getGreaterOperand().getAChild*() and
90-
guard = c.getCondition().getAChild*() and
91-
c.getThen().getAChild*() = e
92-
)
38+
exists(GuardCondition c | c.ensuresLt(use, _, _, e.getBasicBlock(), false))
9339
or
9440
guardedAbs(e, use)
9541
}

cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ArithmeticUncontrolled/ArithmeticUncontrolled.expected

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ edges
1111
| test.c:137:13:137:16 | call to rand | test.c:139:10:139:10 | r |
1212
| test.c:155:22:155:25 | call to rand | test.c:157:9:157:9 | r |
1313
| test.c:155:22:155:27 | (unsigned int)... | test.c:157:9:157:9 | r |
14-
| test.c:162:19:162:38 | (unsigned int)... | test.c:166:16:166:19 | data |
15-
| test.c:162:33:162:36 | call to rand | test.c:166:16:166:19 | data |
1614
| test.cpp:6:5:6:12 | ReturnValue | test.cpp:24:11:24:18 | call to get_rand |
1715
| test.cpp:8:9:8:12 | call to rand | test.cpp:6:5:6:12 | ReturnValue |
1816
| test.cpp:13:2:13:6 | * ... [post update] | test.cpp:30:13:30:14 | & ... [post update] |
@@ -59,9 +57,6 @@ nodes
5957
| test.c:155:22:155:25 | call to rand | semmle.label | call to rand |
6058
| test.c:155:22:155:27 | (unsigned int)... | semmle.label | (unsigned int)... |
6159
| test.c:157:9:157:9 | r | semmle.label | r |
62-
| test.c:162:19:162:38 | (unsigned int)... | semmle.label | (unsigned int)... |
63-
| test.c:162:33:162:36 | call to rand | semmle.label | call to rand |
64-
| test.c:166:16:166:19 | data | semmle.label | data |
6560
| test.cpp:6:5:6:12 | ReturnValue | semmle.label | ReturnValue |
6661
| test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand |
6762
| test.cpp:13:2:13:6 | * ... [post update] | semmle.label | * ... [post update] |
@@ -109,8 +104,6 @@ subpaths
109104
| test.c:139:10:139:10 | r | test.c:137:13:137:16 | call to rand | test.c:139:10:139:10 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:137:13:137:16 | call to rand | Uncontrolled value |
110105
| test.c:157:9:157:9 | r | test.c:155:22:155:25 | call to rand | test.c:157:9:157:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:155:22:155:25 | call to rand | Uncontrolled value |
111106
| test.c:157:9:157:9 | r | test.c:155:22:155:27 | (unsigned int)... | test.c:157:9:157:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:155:22:155:25 | call to rand | Uncontrolled value |
112-
| test.c:166:16:166:19 | data | test.c:162:19:162:38 | (unsigned int)... | test.c:166:16:166:19 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:162:33:162:36 | call to rand | Uncontrolled value |
113-
| test.c:166:16:166:19 | data | test.c:162:33:162:36 | call to rand | test.c:166:16:166:19 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:162:33:162:36 | call to rand | Uncontrolled value |
114107
| test.cpp:25:7:25:7 | r | test.cpp:8:9:8:12 | call to rand | test.cpp:25:7:25:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | Uncontrolled value |
115108
| test.cpp:31:7:31:7 | r | test.cpp:13:10:13:13 | call to rand | test.cpp:31:7:31:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:13:10:13:13 | call to rand | Uncontrolled value |
116109
| test.cpp:37:7:37:7 | r | test.cpp:18:9:18:12 | call to rand | test.cpp:37:7:37:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:18:9:18:12 | call to rand | Uncontrolled value |

cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ArithmeticUncontrolled/test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,5 +163,5 @@ void guarded_test(unsigned p) {
163163
if (p >= data) {
164164
return;
165165
}
166-
unsigned z = data - p; // GOOD [FALSE POSITIVE]
166+
unsigned z = data - p; // GOOD
167167
}

0 commit comments

Comments
 (0)