Skip to content

Commit e2fdfbb

Browse files
author
Gulshan Singh
committed
Add RangeNode class
1 parent ac58299 commit e2fdfbb

File tree

1 file changed

+111
-0
lines changed
  • cpp/ql/lib/experimental/semmle/code/cpp/rangeanalysis/extensions

1 file changed

+111
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
private import cpp
2+
private import semmle.code.cpp.dataflow.DataFlow
3+
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
4+
5+
string getExprBoundAsString(Expr e) {
6+
if exists(lowerBound(e)) and exists(upperBound(e))
7+
then result = "[" + lowerBound(e) + ", " + upperBound(e) + "]"
8+
else result = "[unknown range]"
9+
}
10+
11+
/**
12+
* Holds for any integer type after resolving typedefs and stripping `const`
13+
* specifiers, such as for `const size_t`
14+
*/
15+
predicate isIntegralType(Type t) {
16+
// We use `getUnspecifiedType` here because without it things like
17+
// `const size_t` aren't considered to be integral
18+
t.getUnspecifiedType() instanceof IntegralType
19+
}
20+
21+
/**
22+
* Holds for any reference to an integer type after resolving typedefs and
23+
* stripping `const` specifiers, such as for `const size_t&`
24+
*/
25+
predicate isIntegralReferenceType(Type t) { isIntegralType(t.(ReferenceType).stripType()) }
26+
27+
/**
28+
* Holds for any pointer to an integer type after resolving typedefs and
29+
* stripping `const` specifiers, such as for `const size_t*`. This predicate
30+
* holds for any pointer depth, such as for `const size_t**`.
31+
*/
32+
predicate isIntegralPointerType(Type t) { isIntegralType(t.(PointerType).stripType()) }
33+
34+
predicate hasIntegralOrReferenceIntegralType(Locatable e) {
35+
exists(Type t |
36+
(
37+
t = e.(Expr).getUnspecifiedType()
38+
or
39+
// This will cover variables, parameters, type declarations, etc.
40+
t = e.(DeclarationEntry).getUnspecifiedType()
41+
) and
42+
isIntegralType(t)
43+
or
44+
isIntegralReferenceType(t)
45+
)
46+
}
47+
48+
Expr getLOp(Operation o) {
49+
result = o.(BinaryOperation).getLeftOperand() or
50+
result = o.(Assignment).getLValue()
51+
}
52+
53+
Expr getROp(Operation o) {
54+
result = o.(BinaryOperation).getRightOperand() or
55+
result = o.(Assignment).getRValue()
56+
}
57+
58+
/**
59+
* Display the ranges of expressions in the path view
60+
*/
61+
private class ExprRangeNode extends DataFlow::ExprNode {
62+
pragma[inline]
63+
private string getIntegralBounds(Expr arg) {
64+
if hasIntegralOrReferenceIntegralType(arg)
65+
then result = getExprBoundAsString(arg)
66+
else result = ""
67+
}
68+
69+
private string getOperationBounds(Operation e) {
70+
result =
71+
getExprBoundAsString(e) + " = " + getExprBoundAsString(getLOp(e)) +
72+
e.(Operation).getOperator() + getExprBoundAsString(getROp(e))
73+
}
74+
75+
private string getCallBounds(Call e) {
76+
result =
77+
getExprBoundAsString(e) + "(" +
78+
concat(Expr arg, int i |
79+
arg = e.(Call).getArgument(i)
80+
|
81+
getIntegralBounds(arg) order by i, ","
82+
) + ")"
83+
}
84+
85+
override string toString() {
86+
exists(Expr e | e = getExpr() |
87+
if hasIntegralOrReferenceIntegralType(e)
88+
then
89+
exists(getOperationBounds(e)) and result = super.toString() + ": " + getOperationBounds(e)
90+
or
91+
exists(getCallBounds(e)) and result = super.toString() + ": " + getCallBounds(e)
92+
or
93+
not exists(getOperationBounds(e)) and
94+
not exists(getCallBounds(e)) and
95+
result = super.toString() + ": " + getExprBoundAsString(e)
96+
else result = super.toString()
97+
)
98+
}
99+
}
100+
101+
/**
102+
* Display the ranges of expressions in the path view
103+
*/
104+
private class ReferenceArgumentRangeNode extends DataFlow::DefinitionByReferenceNode {
105+
override string toString() {
106+
if hasIntegralOrReferenceIntegralType(asDefiningArgument())
107+
then result = super.toString() + ": " + getExprBoundAsString(getArgument())
108+
else result = super.toString()
109+
}
110+
}
111+
// TODO: Show ranges for DataFlow::ExplicitParameterNode

0 commit comments

Comments
 (0)