forked from github/codeql-coding-standards
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDoNotUseAnAdditiveOperatorOnAnIterator.ql
78 lines (73 loc) · 3.05 KB
/
DoNotUseAnAdditiveOperatorOnAnIterator.ql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/**
* @id cpp/cert/do-not-use-an-additive-operator-on-an-iterator
* @name CTR55-CPP: Do not use an additive operator on an iterator if the result would overflow
* @description Using an additive operator on an iterator without proper bounds checks can result in
* an overflow.
* @kind problem
* @precision high
* @problem.severity error
* @tags external/cert/id/ctr55-cpp
* correctness
* external/cert/obligation/rule
*/
import cpp
import codingstandards.cpp.cert
import codingstandards.cpp.Iterators
import semmle.code.cpp.controlflow.Dominance
/**
* something like:
* `end = begin() + size()`
*/
Expr calculatedEndCheck(AdditiveOperatorFunctionCall calc) {
exists(
ContainerAccessWithoutRangeCheck::ContainerSizeCall size,
ContainerAccessWithoutRangeCheck::ContainerBeginCall begin
|
calc.getTarget().hasName("operator+") and
DataFlow::localFlow(DataFlow::exprNode(size), DataFlow::exprNode(calc.getAChild*())) and
DataFlow::localFlow(DataFlow::exprNode(begin), DataFlow::exprNode(calc.getAChild*())) and
//make sure its the same container providing its size as giving the begin
globalValueNumber(begin.getQualifier()) = globalValueNumber(size.getQualifier()) and
result = begin.getQualifier()
)
}
Expr validEndCheck(FunctionCall end) {
end instanceof ContainerAccessWithoutRangeCheck::ContainerEndCall and
result = end.getQualifier()
or
result = calculatedEndCheck(end)
}
/**
* some guard exists like: `iterator != end`
* where a relevant`.end()` call flowed into end
*/
predicate validEndBoundCheck(ContainerIteratorAccess it, IteratorSource source) {
exists(
FunctionCall end, BasicBlock b, GuardCondition l, ContainerIteratorAccess otherAccess,
Expr qualifierToCheck
|
//sufficient end guard
qualifierToCheck = validEndCheck(end) and
//guard controls the access
l.controls(b, _) and
b.contains(it) and
//guard is comprised of end check and an iterator access
DataFlow::localFlow(DataFlow::exprNode(end), DataFlow::exprNode(l.getChild(_))) and
l.getChild(_) = otherAccess and
//make sure its the same iterator being checked in the guard as accessed
otherAccess.getOwningContainer() = it.getOwningContainer() and
//if its the end call itself (or its parts), make sure its the same container providing its end as giving the iterator
globalValueNumber(qualifierToCheck) = globalValueNumber(source.getQualifier()) and
// and the guard call we match must be after the assignment call (to avoid valid guards protecting new iterator accesses further down)
source.getASuccessor*() = l
)
}
from ContainerIteratorAccess it, IteratorSource source
where
not isExcluded(it, IteratorsPackage::doNotUseAnAdditiveOperatorOnAnIteratorQuery()) and
it.isAdditiveOperation() and
not exists(RangeBasedForStmt fs | fs.getUpdate().getAChild*() = it) and
source = it.getANearbyAssigningIteratorCall() and
not validEndBoundCheck(it, source) and
not sizeCompareBoundsChecked(source, it)
select it, "Increment of iterator may overflow since its bounds are not checked."