Skip to content

Commit dae60c9

Browse files
committed
Update data flow libraries to 55e052a
1 parent 254a5b0 commit dae60c9

File tree

7 files changed

+3351
-1575
lines changed

7 files changed

+3351
-1575
lines changed

go/ql/lib/semmle/go/dataflow/internal/AccessPathSyntax.qll

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,109 @@
66
* (which does not use the shared data flow libraries).
77
*/
88

9+
/**
10+
* Convenience-predicate for extracting two capture groups at once.
11+
*/
12+
bindingset[input, regexp]
13+
private predicate regexpCaptureTwo(string input, string regexp, string capture1, string capture2) {
14+
capture1 = input.regexpCapture(regexp, 1) and
15+
capture2 = input.regexpCapture(regexp, 2)
16+
}
17+
918
/** Companion module to the `AccessPath` class. */
1019
module AccessPath {
1120
/** A string that should be parsed as an access path. */
1221
abstract class Range extends string {
1322
bindingset[this]
1423
Range() { any() }
1524
}
25+
26+
/**
27+
* Parses an integer constant `n` or interval `n1..n2` (inclusive) and gets the value
28+
* of the constant or any value contained in the interval.
29+
*/
30+
bindingset[arg]
31+
int parseInt(string arg) {
32+
result = arg.toInt()
33+
or
34+
// Match "n1..n2"
35+
exists(string lo, string hi |
36+
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.(-?\\d+)", lo, hi) and
37+
result = [lo.toInt() .. hi.toInt()]
38+
)
39+
}
40+
41+
/**
42+
* Parses a lower-bounded interval `n..` and gets the lower bound.
43+
*/
44+
bindingset[arg]
45+
int parseLowerBound(string arg) { result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt() }
46+
47+
/**
48+
* Parses an integer constant or interval (bounded or unbounded) that explicitly
49+
* references the arity, such as `N-1` or `N-3..N-1`.
50+
*
51+
* Note that expressions of form `N-x` will never resolve to a negative index,
52+
* even if `N` is zero (it will have no result in that case).
53+
*/
54+
bindingset[arg, arity]
55+
private int parseIntWithExplicitArity(string arg, int arity) {
56+
result >= 0 and // do not allow N-1 to resolve to a negative index
57+
exists(string lo |
58+
// N-x
59+
lo = arg.regexpCapture("N-(\\d+)", 1) and
60+
result = arity - lo.toInt()
61+
or
62+
// N-x..
63+
lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and
64+
result = [arity - lo.toInt(), arity - 1]
65+
)
66+
or
67+
exists(string lo, string hi |
68+
// x..N-y
69+
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.N-(\\d+)", lo, hi) and
70+
result = [lo.toInt() .. arity - hi.toInt()]
71+
or
72+
// N-x..N-y
73+
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and
74+
result = [arity - lo.toInt() .. arity - hi.toInt()] and
75+
result >= 0
76+
or
77+
// N-x..y
78+
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and
79+
result = [arity - lo.toInt() .. hi.toInt()] and
80+
result >= 0
81+
)
82+
}
83+
84+
/**
85+
* Parses an integer constant or interval (bounded or unbounded) and gets any
86+
* of the integers contained within (of which there may be infinitely many).
87+
*
88+
* Has no result for arguments involving an explicit arity, such as `N-1`.
89+
*/
90+
bindingset[arg, result]
91+
int parseIntUnbounded(string arg) {
92+
result = parseInt(arg)
93+
or
94+
result >= parseLowerBound(arg)
95+
}
96+
97+
/**
98+
* Parses an integer constant or interval (bounded or unbounded) that
99+
* may reference the arity of a call, such as `N-1` or `N-3..N-1`.
100+
*
101+
* Note that expressions of form `N-x` will never resolve to a negative index,
102+
* even if `N` is zero (it will have no result in that case).
103+
*/
104+
bindingset[arg, arity]
105+
int parseIntWithArity(string arg, int arity) {
106+
result = parseInt(arg)
107+
or
108+
result in [parseLowerBound(arg) .. arity - 1]
109+
or
110+
result = parseIntWithExplicitArity(arg, arity)
111+
}
16112
}
17113

18114
/** Gets the `n`th token on the access path as a string. */
@@ -53,7 +149,7 @@ class AccessPath extends string instanceof AccessPath::Range {
53149
* An access part token such as `Argument[1]` or `ReturnValue`, appearing in one or more access paths.
54150
*/
55151
class AccessPathToken extends string {
56-
AccessPathToken() { this = getRawToken(any(AccessPath path), _) }
152+
AccessPathToken() { this = getRawToken(_, _) }
57153

58154
private string getPart(int part) {
59155
result = this.regexpCapture("([^\\[]+)(?:\\[([^\\]]*)\\])?", part)
@@ -71,9 +167,16 @@ class AccessPathToken extends string {
71167
/** Gets the `n`th argument to this token, such as `x` or `y` from `Member[x,y]`. */
72168
string getArgument(int n) { result = this.getArgumentList().splitAt(",", n).trim() }
73169

170+
/** Gets the `n`th argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
171+
pragma[nomagic]
172+
string getArgument(string name, int n) { name = this.getName() and result = this.getArgument(n) }
173+
74174
/** Gets an argument to this token, such as `x` or `y` from `Member[x,y]`. */
75175
string getAnArgument() { result = this.getArgument(_) }
76176

177+
/** Gets an argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
178+
string getAnArgument(string name) { result = this.getArgument(name, _) }
179+
77180
/** Gets the number of arguments to this token, such as 2 for `Member[x,y]` or zero for `ReturnValue`. */
78181
int getNumArgument() { result = count(int n | exists(this.getArgument(n))) }
79182
}

0 commit comments

Comments
 (0)