Skip to content

Commit cc841a6

Browse files
authored
Merge pull request github#11921 from gsingh93/range-node
C++: Add RangeNode class
2 parents dec1e4d + bae1dfe commit cc841a6

File tree

1 file changed

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

1 file changed

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

0 commit comments

Comments
 (0)