Skip to content

Commit 5cab737

Browse files
committed
Shared: sync AccessPathSyntax.qll
1 parent abd4933 commit 5cab737

File tree

3 files changed

+294
-0
lines changed

3 files changed

+294
-0
lines changed

csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,111 @@
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+
private int parseLowerBound(string arg) {
46+
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
47+
}
48+
49+
/**
50+
* Parses an integer constant or interval (bounded or unbounded) that explicitly
51+
* references the arity, such as `N-1` or `N-3..N-1`.
52+
*
53+
* Note that expressions of form `N-x` will never resolve to a negative index,
54+
* even if `N` is zero (it will have no result in that case).
55+
*/
56+
bindingset[arg, arity]
57+
private int parseIntWithExplicitArity(string arg, int arity) {
58+
result >= 0 and // do not allow N-1 to resolve to a negative index
59+
exists(string lo |
60+
// N-x
61+
lo = arg.regexpCapture("N-(\\d+)", 1) and
62+
result = arity - lo.toInt()
63+
or
64+
// N-x..
65+
lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and
66+
result = [arity - lo.toInt(), arity - 1]
67+
)
68+
or
69+
exists(string lo, string hi |
70+
// x..N-y
71+
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.N-(\\d+)", lo, hi) and
72+
result = [lo.toInt() .. arity - hi.toInt()]
73+
or
74+
// N-x..Ny
75+
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and
76+
result = [arity - lo.toInt() .. arity - hi.toInt()] and
77+
result >= 0
78+
or
79+
// N-x..y
80+
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and
81+
result = [arity - lo.toInt() .. hi.toInt()] and
82+
result >= 0
83+
)
84+
}
85+
86+
/**
87+
* Parses an integer constant or interval (bounded or unbounded) and gets any
88+
* of the integers contained within (of which there may be infinitely many).
89+
*
90+
* Has no result for arguments involving an explicit arity, such as `N-1`.
91+
*/
92+
bindingset[arg, result]
93+
int parseIntUnbounded(string arg) {
94+
result = parseInt(arg)
95+
or
96+
result >= parseLowerBound(arg)
97+
}
98+
99+
/**
100+
* Parses an integer constant or interval (bounded or unbounded) that
101+
* may reference the arity of a call, such as `N-1` or `N-3..N-1`.
102+
*
103+
* Note that expressions of form `N-x` will never resolve to a negative index,
104+
* even if `N` is zero (it will have no result in that case).
105+
*/
106+
bindingset[arg, arity]
107+
int parseIntWithArity(string arg, int arity) {
108+
result = parseInt(arg)
109+
or
110+
result in [parseLowerBound(arg) .. arity - 1]
111+
or
112+
result = parseIntWithExplicitArity(arg, arity)
113+
}
16114
}
17115

18116
/** Gets the `n`th token on the access path as a string. */

java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,111 @@
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+
private int parseLowerBound(string arg) {
46+
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
47+
}
48+
49+
/**
50+
* Parses an integer constant or interval (bounded or unbounded) that explicitly
51+
* references the arity, such as `N-1` or `N-3..N-1`.
52+
*
53+
* Note that expressions of form `N-x` will never resolve to a negative index,
54+
* even if `N` is zero (it will have no result in that case).
55+
*/
56+
bindingset[arg, arity]
57+
private int parseIntWithExplicitArity(string arg, int arity) {
58+
result >= 0 and // do not allow N-1 to resolve to a negative index
59+
exists(string lo |
60+
// N-x
61+
lo = arg.regexpCapture("N-(\\d+)", 1) and
62+
result = arity - lo.toInt()
63+
or
64+
// N-x..
65+
lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and
66+
result = [arity - lo.toInt(), arity - 1]
67+
)
68+
or
69+
exists(string lo, string hi |
70+
// x..N-y
71+
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.N-(\\d+)", lo, hi) and
72+
result = [lo.toInt() .. arity - hi.toInt()]
73+
or
74+
// N-x..Ny
75+
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and
76+
result = [arity - lo.toInt() .. arity - hi.toInt()] and
77+
result >= 0
78+
or
79+
// N-x..y
80+
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and
81+
result = [arity - lo.toInt() .. hi.toInt()] and
82+
result >= 0
83+
)
84+
}
85+
86+
/**
87+
* Parses an integer constant or interval (bounded or unbounded) and gets any
88+
* of the integers contained within (of which there may be infinitely many).
89+
*
90+
* Has no result for arguments involving an explicit arity, such as `N-1`.
91+
*/
92+
bindingset[arg, result]
93+
int parseIntUnbounded(string arg) {
94+
result = parseInt(arg)
95+
or
96+
result >= parseLowerBound(arg)
97+
}
98+
99+
/**
100+
* Parses an integer constant or interval (bounded or unbounded) that
101+
* may reference the arity of a call, such as `N-1` or `N-3..N-1`.
102+
*
103+
* Note that expressions of form `N-x` will never resolve to a negative index,
104+
* even if `N` is zero (it will have no result in that case).
105+
*/
106+
bindingset[arg, arity]
107+
int parseIntWithArity(string arg, int arity) {
108+
result = parseInt(arg)
109+
or
110+
result in [parseLowerBound(arg) .. arity - 1]
111+
or
112+
result = parseIntWithExplicitArity(arg, arity)
113+
}
16114
}
17115

18116
/** Gets the `n`th token on the access path as a string. */

ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,111 @@
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+
private int parseLowerBound(string arg) {
46+
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
47+
}
48+
49+
/**
50+
* Parses an integer constant or interval (bounded or unbounded) that explicitly
51+
* references the arity, such as `N-1` or `N-3..N-1`.
52+
*
53+
* Note that expressions of form `N-x` will never resolve to a negative index,
54+
* even if `N` is zero (it will have no result in that case).
55+
*/
56+
bindingset[arg, arity]
57+
private int parseIntWithExplicitArity(string arg, int arity) {
58+
result >= 0 and // do not allow N-1 to resolve to a negative index
59+
exists(string lo |
60+
// N-x
61+
lo = arg.regexpCapture("N-(\\d+)", 1) and
62+
result = arity - lo.toInt()
63+
or
64+
// N-x..
65+
lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and
66+
result = [arity - lo.toInt(), arity - 1]
67+
)
68+
or
69+
exists(string lo, string hi |
70+
// x..N-y
71+
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.N-(\\d+)", lo, hi) and
72+
result = [lo.toInt() .. arity - hi.toInt()]
73+
or
74+
// N-x..Ny
75+
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and
76+
result = [arity - lo.toInt() .. arity - hi.toInt()] and
77+
result >= 0
78+
or
79+
// N-x..y
80+
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and
81+
result = [arity - lo.toInt() .. hi.toInt()] and
82+
result >= 0
83+
)
84+
}
85+
86+
/**
87+
* Parses an integer constant or interval (bounded or unbounded) and gets any
88+
* of the integers contained within (of which there may be infinitely many).
89+
*
90+
* Has no result for arguments involving an explicit arity, such as `N-1`.
91+
*/
92+
bindingset[arg, result]
93+
int parseIntUnbounded(string arg) {
94+
result = parseInt(arg)
95+
or
96+
result >= parseLowerBound(arg)
97+
}
98+
99+
/**
100+
* Parses an integer constant or interval (bounded or unbounded) that
101+
* may reference the arity of a call, such as `N-1` or `N-3..N-1`.
102+
*
103+
* Note that expressions of form `N-x` will never resolve to a negative index,
104+
* even if `N` is zero (it will have no result in that case).
105+
*/
106+
bindingset[arg, arity]
107+
int parseIntWithArity(string arg, int arity) {
108+
result = parseInt(arg)
109+
or
110+
result in [parseLowerBound(arg) .. arity - 1]
111+
or
112+
result = parseIntWithExplicitArity(arg, arity)
113+
}
16114
}
17115

18116
/** Gets the `n`th token on the access path as a string. */

0 commit comments

Comments
 (0)