-
Notifications
You must be signed in to change notification settings - Fork 61
/
Copy pathDoNotUsePointerArithmeticOnNonArrayObjectPointers.ql
112 lines (102 loc) · 3.91 KB
/
DoNotUsePointerArithmeticOnNonArrayObjectPointers.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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
* @id c/cert/do-not-use-pointer-arithmetic-on-non-array-object-pointers
* @name ARR37-C: Do not add or subtract an integer to a pointer to a non-array object
* @description A pair of elements that are not elements in the same array are not guaranteed to be
* contiguous in memory and therefore should not be addressed using pointer arithmetic.
* @kind path-problem
* @precision high
* @problem.severity error
* @tags external/cert/id/arr37-c
* correctness
* external/cert/obligation/rule
*/
import cpp
import codingstandards.c.cert
import semmle.code.cpp.dataflow.new.DataFlow
import NonArrayPointerToArrayIndexingExprFlow::PathGraph
/**
* A data-flow configuration that tracks flow from an `AddressOfExpr` of a variable
* of `PointerType` that is not also an `ArrayType` to a `PointerArithmeticOrArrayExpr`
*/
module NonArrayPointerToArrayIndexingExprConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(AddressOfExpr ao, Type t |
source.asExpr() = ao and
not ao.getOperand() instanceof ArrayExpr and
not ao.getOperand() instanceof PointerDereferenceExpr and
t = ao.getOperand().getType() and
not t instanceof PointerType and
not t instanceof ArrayType and
not t.(PointerType).getBaseType() instanceof ArrayType
)
}
predicate isSink(DataFlow::Node sink) {
exists(PointerArithmeticOrArrayExpr ae |
sink.asExpr() = ae.getPointerOperand() and
not sink.asExpr() instanceof Literal and
not ae.isNonPointerOperandZero()
)
}
predicate isBarrierOut(DataFlow::Node node) {
// the default interprocedural data-flow model flows through any field or array assignment
// expressions to the qualifier (array base, pointer dereferenced, or qualifier) instead of the
// individual element or field that the assignment modifies. this default behaviour causes
// false positives for future accesses of any element of that object, so we remove the edges
// between those assignments from the graph with `isBarrierOut`.
exists(AssignExpr a |
node.asExpr() = a.getRValue() and
(
a.getLValue() instanceof ArrayExpr or
a.getLValue() instanceof PointerDereferenceExpr or
a.getLValue() instanceof FieldAccess
)
)
or
// ignore AddressOfExpr output e.g. call(&s1)
node.asDefiningArgument() instanceof AddressOfExpr
}
}
module NonArrayPointerToArrayIndexingExprFlow =
DataFlow::Global<NonArrayPointerToArrayIndexingExprConfig>;
class PointerArithmeticOrArrayExpr extends Expr {
Expr operand;
PointerArithmeticOrArrayExpr() {
operand = this.(ArrayExpr).getArrayBase()
or
operand = this.(ArrayExpr).getArrayOffset()
or
operand = this.(PointerAddExpr).getAnOperand()
or
operand = this.(PointerSubExpr).getAnOperand()
or
operand = this.(Operation).getAnOperand() and
operand.getUnderlyingType() instanceof PointerType and
(
this instanceof PostfixCrementOperation
or
this instanceof PrefixIncrExpr
or
this instanceof PrefixDecrExpr
)
}
/**
* Gets the operands of this expression. If the expression is an
* `ArrayExpr`, the results are the array base and offset `Expr`s.
*/
Expr getPointerOperand() {
result = operand or
result = this.(PointerArithmeticOrArrayExpr).getPointerOperand()
}
/**
* Holds if there exists an operand that is a `Literal` with a value of `0`.
*/
predicate isNonPointerOperandZero() { operand.(Literal).getValue().toInt() = 0 }
}
from
NonArrayPointerToArrayIndexingExprFlow::PathNode source,
NonArrayPointerToArrayIndexingExprFlow::PathNode sink
where
not isExcluded(sink.getNode().asExpr(),
InvalidMemory2Package::doNotUsePointerArithmeticOnNonArrayObjectPointersQuery()) and
NonArrayPointerToArrayIndexingExprFlow::flowPath(source, sink)
select sink, source, sink, "Pointer arithmetic on non-array object pointer."