Skip to content

Commit 275902d

Browse files
authored
Merge pull request #8373 from hvitved/ruby/regex-multiples-parse-fix
Ruby: Fix incorrect parsing of ranges
2 parents a70ed71 + f5fbf50 commit 275902d

File tree

5 files changed

+188
-11
lines changed

5 files changed

+188
-11
lines changed

ruby/ql/consistency-queries/RegExpConsistency.ql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,9 @@ query predicate nonUniqueChild(RegExpParent parent, int i, RegExpTerm child) {
66
}
77

88
query predicate cyclic(RegExpParent parent) { parent = parent.getAChild+() }
9+
10+
query predicate nonConsecutive(RegExpParent parent, int i) {
11+
exists(parent.getChild(i)) and
12+
i > 0 and
13+
not exists(parent.getChild(i - 1))
14+
}

ruby/ql/lib/codeql/ruby/security/performance/ParseRegExp.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,8 @@ abstract class RegExp extends AST::StringlikeLiteral {
402402
not exists(int x, int y | this.backreference(x, y) and x <= start and y >= end) and
403403
not exists(int x, int y |
404404
this.pStyleNamedCharacterProperty(x, y, _) and x <= start and y >= end
405-
)
405+
) and
406+
not exists(int x, int y | this.multiples(x, y, _, _) and x <= start and y >= end)
406407
}
407408

408409
predicate normalCharacter(int start, int end) {

ruby/ql/test/library-tests/regexp/parse.expected

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,21 @@ regexp.rb:
2929
# 9| [RegExpRange] a{4,8}
3030
#-----| 0 -> [RegExpConstant, RegExpNormalChar] a
3131

32-
# 9| [RegExpNormalChar] 4,8}
33-
3432
# 10| [RegExpConstant, RegExpNormalChar] a
3533

3634
# 10| [RegExpRange] a{,8}
3735
#-----| 0 -> [RegExpConstant, RegExpNormalChar] a
3836

39-
# 10| [RegExpNormalChar] ,8}
40-
4137
# 11| [RegExpConstant, RegExpNormalChar] a
4238

4339
# 11| [InfiniteRepetitionQuantifier, RegExpRange] a{3,}
4440
#-----| 0 -> [RegExpConstant, RegExpNormalChar] a
4541

46-
# 11| [RegExpNormalChar] 3,}
47-
4842
# 12| [RegExpConstant, RegExpNormalChar] a
4943

5044
# 12| [RegExpRange] a{7}
5145
#-----| 0 -> [RegExpConstant, RegExpNormalChar] a
5246

53-
# 12| [RegExpNormalChar] 7}
54-
5547
# 15| [RegExpConstant, RegExpNormalChar] foo
5648

5749
# 15| [RegExpAlt] foo|bar
@@ -428,8 +420,6 @@ regexp.rb:
428420
# 62| [RegExpRange] \p{^Alnum}{2,3}
429421
#-----| 0 -> [RegExpNamedCharacterProperty] \p{^Alnum}
430422

431-
# 62| [RegExpNormalChar] 2,3}
432-
433423
# 63| [RegExpCharacterClass] [a-f\p{Digit}]
434424
#-----| 0 -> [RegExpCharacterRange] a-f
435425
#-----| 1 -> [RegExpNamedCharacterProperty] \p{Digit}

ruby/ql/test/library-tests/regexp/regexp.expected

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,181 @@ groupNumber
1111
| regexp.rb:53:2:53:12 | (?'foo'fo+) | 1 |
1212
| regexp.rb:56:2:56:5 | (a+) | 1 |
1313
| regexp.rb:57:2:57:11 | (?<qux>q+) | 1 |
14+
term
15+
| regexp.rb:5:2:5:4 | abc | RegExpConstant,RegExpNormalChar |
16+
| regexp.rb:8:2:8:2 | a | RegExpConstant,RegExpNormalChar |
17+
| regexp.rb:8:2:8:3 | a* | RegExpStar |
18+
| regexp.rb:8:2:8:8 | a*b+c?d | RegExpSequence |
19+
| regexp.rb:8:4:8:4 | b | RegExpConstant,RegExpNormalChar |
20+
| regexp.rb:8:4:8:5 | b+ | RegExpPlus |
21+
| regexp.rb:8:6:8:6 | c | RegExpConstant,RegExpNormalChar |
22+
| regexp.rb:8:6:8:7 | c? | RegExpOpt |
23+
| regexp.rb:8:8:8:8 | d | RegExpConstant,RegExpNormalChar |
24+
| regexp.rb:9:2:9:2 | a | RegExpConstant,RegExpNormalChar |
25+
| regexp.rb:9:2:9:7 | a{4,8} | RegExpRange |
26+
| regexp.rb:10:2:10:2 | a | RegExpConstant,RegExpNormalChar |
27+
| regexp.rb:10:2:10:6 | a{,8} | RegExpRange |
28+
| regexp.rb:11:2:11:2 | a | RegExpConstant,RegExpNormalChar |
29+
| regexp.rb:11:2:11:6 | a{3,} | InfiniteRepetitionQuantifier,RegExpRange |
30+
| regexp.rb:12:2:12:2 | a | RegExpConstant,RegExpNormalChar |
31+
| regexp.rb:12:2:12:5 | a{7} | RegExpRange |
32+
| regexp.rb:15:2:15:4 | foo | RegExpConstant,RegExpNormalChar |
33+
| regexp.rb:15:2:15:8 | foo\|bar | RegExpAlt |
34+
| regexp.rb:15:6:15:8 | bar | RegExpConstant,RegExpNormalChar |
35+
| regexp.rb:18:2:18:6 | [abc] | RegExpCharacterClass |
36+
| regexp.rb:18:3:18:3 | a | RegExpConstant,RegExpNormalChar |
37+
| regexp.rb:18:4:18:4 | b | RegExpConstant,RegExpNormalChar |
38+
| regexp.rb:18:5:18:5 | c | RegExpConstant,RegExpNormalChar |
39+
| regexp.rb:19:2:19:13 | [a-fA-F0-9_] | RegExpCharacterClass |
40+
| regexp.rb:19:3:19:3 | a | RegExpConstant,RegExpNormalChar |
41+
| regexp.rb:19:3:19:5 | a-f | RegExpCharacterRange |
42+
| regexp.rb:19:5:19:5 | f | RegExpConstant,RegExpNormalChar |
43+
| regexp.rb:19:6:19:6 | A | RegExpConstant,RegExpNormalChar |
44+
| regexp.rb:19:6:19:8 | A-F | RegExpCharacterRange |
45+
| regexp.rb:19:8:19:8 | F | RegExpConstant,RegExpNormalChar |
46+
| regexp.rb:19:9:19:9 | 0 | RegExpConstant,RegExpNormalChar |
47+
| regexp.rb:19:9:19:11 | 0-9 | RegExpCharacterRange |
48+
| regexp.rb:19:11:19:11 | 9 | RegExpConstant,RegExpNormalChar |
49+
| regexp.rb:19:12:19:12 | _ | RegExpConstant,RegExpNormalChar |
50+
| regexp.rb:20:2:20:3 | \\A | RegExpCaret |
51+
| regexp.rb:20:2:20:11 | \\A[+-]?\\d+ | RegExpSequence |
52+
| regexp.rb:20:4:20:7 | [+-] | RegExpCharacterClass |
53+
| regexp.rb:20:4:20:8 | [+-]? | RegExpOpt |
54+
| regexp.rb:20:5:20:5 | + | RegExpConstant,RegExpNormalChar |
55+
| regexp.rb:20:6:20:6 | - | RegExpConstant,RegExpNormalChar |
56+
| regexp.rb:20:9:20:10 | \\d | RegExpCharacterClassEscape |
57+
| regexp.rb:20:9:20:11 | \\d+ | RegExpPlus |
58+
| regexp.rb:21:2:21:5 | [\\w] | RegExpCharacterClass |
59+
| regexp.rb:21:2:21:6 | [\\w]+ | RegExpPlus |
60+
| regexp.rb:21:3:21:4 | \\w | RegExpCharacterClassEscape |
61+
| regexp.rb:22:2:22:3 | \\[ | RegExpConstant,RegExpEscape |
62+
| regexp.rb:22:2:22:10 | \\[\\][123] | RegExpSequence |
63+
| regexp.rb:22:4:22:5 | \\] | RegExpConstant,RegExpEscape |
64+
| regexp.rb:22:6:22:10 | [123] | RegExpCharacterClass |
65+
| regexp.rb:22:7:22:7 | 1 | RegExpConstant,RegExpNormalChar |
66+
| regexp.rb:22:8:22:8 | 2 | RegExpConstant,RegExpNormalChar |
67+
| regexp.rb:22:9:22:9 | 3 | RegExpConstant,RegExpNormalChar |
68+
| regexp.rb:23:2:23:7 | [^A-Z] | RegExpCharacterClass |
69+
| regexp.rb:23:4:23:4 | A | RegExpConstant,RegExpNormalChar |
70+
| regexp.rb:23:4:23:6 | A-Z | RegExpCharacterRange |
71+
| regexp.rb:23:6:23:6 | Z | RegExpConstant,RegExpNormalChar |
72+
| regexp.rb:24:2:24:4 | []] | RegExpCharacterClass |
73+
| regexp.rb:24:3:24:3 | ] | RegExpConstant,RegExpNormalChar |
74+
| regexp.rb:25:2:25:5 | [^]] | RegExpCharacterClass |
75+
| regexp.rb:25:4:25:4 | ] | RegExpConstant,RegExpNormalChar |
76+
| regexp.rb:26:2:26:5 | [^-] | RegExpCharacterClass |
77+
| regexp.rb:26:4:26:4 | - | RegExpConstant,RegExpNormalChar |
78+
| regexp.rb:27:2:27:4 | [\|] | RegExpCharacterClass |
79+
| regexp.rb:27:3:27:3 | \| | RegExpConstant,RegExpNormalChar |
80+
| regexp.rb:30:2:30:7 | [[a-f] | RegExpCharacterClass |
81+
| regexp.rb:30:2:30:11 | [[a-f]A-F] | RegExpSequence |
82+
| regexp.rb:30:3:30:3 | [ | RegExpConstant,RegExpNormalChar |
83+
| regexp.rb:30:4:30:4 | a | RegExpConstant,RegExpNormalChar |
84+
| regexp.rb:30:4:30:6 | a-f | RegExpCharacterRange |
85+
| regexp.rb:30:6:30:6 | f | RegExpConstant,RegExpNormalChar |
86+
| regexp.rb:30:8:30:11 | A-F] | RegExpConstant,RegExpNormalChar |
87+
| regexp.rb:33:2:33:2 | . | RegExpDot |
88+
| regexp.rb:33:2:33:3 | .* | RegExpStar |
89+
| regexp.rb:34:2:34:2 | . | RegExpDot |
90+
| regexp.rb:34:2:34:3 | .* | RegExpStar |
91+
| regexp.rb:35:2:35:3 | \\w | RegExpCharacterClassEscape |
92+
| regexp.rb:35:2:35:4 | \\w+ | RegExpPlus |
93+
| regexp.rb:35:2:35:6 | \\w+\\W | RegExpSequence |
94+
| regexp.rb:35:5:35:6 | \\W | RegExpCharacterClassEscape |
95+
| regexp.rb:36:2:36:3 | \\s | RegExpCharacterClassEscape |
96+
| regexp.rb:36:2:36:5 | \\s\\S | RegExpSequence |
97+
| regexp.rb:36:4:36:5 | \\S | RegExpCharacterClassEscape |
98+
| regexp.rb:37:2:37:3 | \\d | RegExpCharacterClassEscape |
99+
| regexp.rb:37:2:37:5 | \\d\\D | RegExpSequence |
100+
| regexp.rb:37:4:37:5 | \\D | RegExpCharacterClassEscape |
101+
| regexp.rb:38:2:38:3 | \\h | RegExpCharacterClassEscape |
102+
| regexp.rb:38:2:38:5 | \\h\\H | RegExpSequence |
103+
| regexp.rb:38:4:38:5 | \\H | RegExpCharacterClassEscape |
104+
| regexp.rb:39:2:39:3 | \\n | RegExpConstant,RegExpEscape |
105+
| regexp.rb:39:2:39:7 | \\n\\r\\t | RegExpSequence |
106+
| regexp.rb:39:4:39:5 | \\r | RegExpConstant,RegExpEscape |
107+
| regexp.rb:39:6:39:7 | \\t | RegExpConstant,RegExpEscape |
108+
| regexp.rb:42:2:42:3 | \\G | RegExpSpecialChar |
109+
| regexp.rb:42:2:42:6 | \\Gabc | RegExpSequence |
110+
| regexp.rb:42:4:42:6 | abc | RegExpConstant,RegExpNormalChar |
111+
| regexp.rb:43:2:43:3 | \\b | RegExpSpecialChar |
112+
| regexp.rb:43:2:43:7 | \\b!a\\B | RegExpSequence |
113+
| regexp.rb:43:4:43:5 | !a | RegExpConstant,RegExpNormalChar |
114+
| regexp.rb:43:6:43:7 | \\B | RegExpSpecialChar |
115+
| regexp.rb:46:2:46:6 | (foo) | RegExpGroup |
116+
| regexp.rb:46:2:46:7 | (foo)* | RegExpStar |
117+
| regexp.rb:46:2:46:10 | (foo)*bar | RegExpSequence |
118+
| regexp.rb:46:3:46:5 | foo | RegExpConstant,RegExpNormalChar |
119+
| regexp.rb:46:8:46:10 | bar | RegExpConstant,RegExpNormalChar |
120+
| regexp.rb:47:2:47:3 | fo | RegExpConstant,RegExpNormalChar |
121+
| regexp.rb:47:2:47:10 | fo(o\|b)ar | RegExpSequence |
122+
| regexp.rb:47:4:47:8 | (o\|b) | RegExpGroup |
123+
| regexp.rb:47:5:47:5 | o | RegExpConstant,RegExpNormalChar |
124+
| regexp.rb:47:5:47:7 | o\|b | RegExpAlt |
125+
| regexp.rb:47:7:47:7 | b | RegExpConstant,RegExpNormalChar |
126+
| regexp.rb:47:9:47:10 | ar | RegExpConstant,RegExpNormalChar |
127+
| regexp.rb:48:2:48:9 | (a\|b\|cd) | RegExpGroup |
128+
| regexp.rb:48:2:48:10 | (a\|b\|cd)e | RegExpSequence |
129+
| regexp.rb:48:3:48:3 | a | RegExpConstant,RegExpNormalChar |
130+
| regexp.rb:48:3:48:8 | a\|b\|cd | RegExpAlt |
131+
| regexp.rb:48:5:48:5 | b | RegExpConstant,RegExpNormalChar |
132+
| regexp.rb:48:7:48:8 | cd | RegExpConstant,RegExpNormalChar |
133+
| regexp.rb:48:10:48:10 | e | RegExpConstant,RegExpNormalChar |
134+
| regexp.rb:49:2:49:7 | (?::+) | RegExpGroup |
135+
| regexp.rb:49:2:49:9 | (?::+)\\w | RegExpSequence |
136+
| regexp.rb:49:5:49:5 | : | RegExpConstant,RegExpNormalChar |
137+
| regexp.rb:49:5:49:6 | :+ | RegExpPlus |
138+
| regexp.rb:49:8:49:9 | \\w | RegExpCharacterClassEscape |
139+
| regexp.rb:52:2:52:11 | (?<id>\\w+) | RegExpGroup |
140+
| regexp.rb:52:8:52:9 | \\w | RegExpCharacterClassEscape |
141+
| regexp.rb:52:8:52:10 | \\w+ | RegExpPlus |
142+
| regexp.rb:53:2:53:12 | (?'foo'fo+) | RegExpGroup |
143+
| regexp.rb:53:9:53:9 | f | RegExpConstant,RegExpNormalChar |
144+
| regexp.rb:53:9:53:11 | fo+ | RegExpSequence |
145+
| regexp.rb:53:10:53:10 | o | RegExpConstant,RegExpNormalChar |
146+
| regexp.rb:53:10:53:11 | o+ | RegExpPlus |
147+
| regexp.rb:56:2:56:5 | (a+) | RegExpGroup |
148+
| regexp.rb:56:2:56:9 | (a+)b+\\1 | RegExpSequence |
149+
| regexp.rb:56:3:56:3 | a | RegExpConstant,RegExpNormalChar |
150+
| regexp.rb:56:3:56:4 | a+ | RegExpPlus |
151+
| regexp.rb:56:6:56:6 | b | RegExpConstant,RegExpNormalChar |
152+
| regexp.rb:56:6:56:7 | b+ | RegExpPlus |
153+
| regexp.rb:56:8:56:9 | \\1 | RegExpBackRef |
154+
| regexp.rb:57:2:57:11 | (?<qux>q+) | RegExpGroup |
155+
| regexp.rb:57:2:57:22 | (?<qux>q+)\\s+\\k<qux>+ | RegExpSequence |
156+
| regexp.rb:57:9:57:9 | q | RegExpConstant,RegExpNormalChar |
157+
| regexp.rb:57:9:57:10 | q+ | RegExpPlus |
158+
| regexp.rb:57:12:57:13 | \\s | RegExpCharacterClassEscape |
159+
| regexp.rb:57:12:57:14 | \\s+ | RegExpPlus |
160+
| regexp.rb:57:15:57:21 | \\k<qux> | RegExpBackRef |
161+
| regexp.rb:57:15:57:22 | \\k<qux>+ | RegExpPlus |
162+
| regexp.rb:60:2:60:9 | \\p{Word} | RegExpNamedCharacterProperty |
163+
| regexp.rb:60:2:60:10 | \\p{Word}* | RegExpStar |
164+
| regexp.rb:61:2:61:10 | \\P{Digit} | RegExpNamedCharacterProperty |
165+
| regexp.rb:61:2:61:11 | \\P{Digit}+ | RegExpPlus |
166+
| regexp.rb:62:2:62:11 | \\p{^Alnum} | RegExpNamedCharacterProperty |
167+
| regexp.rb:62:2:62:16 | \\p{^Alnum}{2,3} | RegExpRange |
168+
| regexp.rb:63:2:63:15 | [a-f\\p{Digit}] | RegExpCharacterClass |
169+
| regexp.rb:63:2:63:16 | [a-f\\p{Digit}]+ | RegExpPlus |
170+
| regexp.rb:63:3:63:3 | a | RegExpConstant,RegExpNormalChar |
171+
| regexp.rb:63:3:63:5 | a-f | RegExpCharacterRange |
172+
| regexp.rb:63:5:63:5 | f | RegExpConstant,RegExpNormalChar |
173+
| regexp.rb:63:6:63:14 | \\p{Digit} | RegExpNamedCharacterProperty |
174+
| regexp.rb:66:2:66:12 | [[:alpha:]] | RegExpCharacterClass |
175+
| regexp.rb:66:2:66:23 | [[:alpha:]][[:digit:]] | RegExpSequence |
176+
| regexp.rb:66:3:66:11 | [:alpha:] | RegExpNamedCharacterProperty |
177+
| regexp.rb:66:13:66:23 | [[:digit:]] | RegExpCharacterClass |
178+
| regexp.rb:66:14:66:22 | [:digit:] | RegExpNamedCharacterProperty |
179+
| regexp.rb:69:2:69:21 | [[:alpha:][:digit:]] | RegExpCharacterClass |
180+
| regexp.rb:69:3:69:11 | [:alpha:] | RegExpNamedCharacterProperty |
181+
| regexp.rb:69:12:69:20 | [:digit:] | RegExpNamedCharacterProperty |
182+
| regexp.rb:72:2:72:18 | [A-F[:digit:]a-f] | RegExpCharacterClass |
183+
| regexp.rb:72:3:72:3 | A | RegExpConstant,RegExpNormalChar |
184+
| regexp.rb:72:3:72:5 | A-F | RegExpCharacterRange |
185+
| regexp.rb:72:5:72:5 | F | RegExpConstant,RegExpNormalChar |
186+
| regexp.rb:72:6:72:14 | [:digit:] | RegExpNamedCharacterProperty |
187+
| regexp.rb:72:15:72:15 | a | RegExpConstant,RegExpNormalChar |
188+
| regexp.rb:72:15:72:17 | a-f | RegExpCharacterRange |
189+
| regexp.rb:72:17:72:17 | f | RegExpConstant,RegExpNormalChar |
190+
| regexp.rb:75:2:75:10 | [:digit:] | RegExpNamedCharacterProperty |
191+
| regexp.rb:79:2:79:4 | abc | RegExpConstant,RegExpNormalChar |

ruby/ql/test/library-tests/regexp/regexp.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ import codeql.ruby.security.performance.RegExpTreeView
33
query predicate groupName(RegExpGroup g, string name) { name = g.getName() }
44

55
query predicate groupNumber(RegExpGroup g, int number) { number = g.getNumber() }
6+
7+
query predicate term(RegExpTerm term, string c) { c = term.getPrimaryQlClasses() }

0 commit comments

Comments
 (0)