Skip to content

Commit c193d9f

Browse files
authored
Merge pull request #4823 from erik-krogh/furtherReDoS
Approved by esbena
2 parents 13a67c9 + 7e21081 commit c193d9f

File tree

5 files changed

+180
-17
lines changed

5 files changed

+180
-17
lines changed

javascript/ql/src/Performance/ReDoS.ql

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,23 @@ newtype TStatePair =
118118
MkStatePair(State q1, State q2) {
119119
isFork(q1, _, _, _, _) and q2 = q1
120120
or
121-
step(_, _, _, q1, q2) and
122-
q1.toString() <= q2.toString()
121+
(step(_, _, _, q1, q2) or step(_, _, _, q2, q1)) and
122+
rankState(q1) <= rankState(q2)
123123
}
124124

125+
/**
126+
* Gets a unique number for a `state`.
127+
* Is used to create an ordering of states, where states with the same `toString()` will be ordered differently.
128+
*/
129+
int rankState(State state) {
130+
state =
131+
rank[result](State s, Location l |
132+
l = s.getRepr().getLocation()
133+
|
134+
s order by l.getStartLine(), l.getStartColumn(), s.toString()
135+
)
136+
}
137+
125138
class StatePair extends TStatePair {
126139
State q1;
127140
State q2;
@@ -135,14 +148,6 @@ class StatePair extends TStatePair {
135148
State getRight() { result = q2 }
136149
}
137150

138-
/**
139-
* Gets the state pair `(q1, q2)` or `(q2, q1)`; note that only
140-
* one or the other is defined.
141-
*/
142-
StatePair mkStatePair(State q1, State q2) {
143-
result = MkStatePair(q1, q2) or result = MkStatePair(q2, q1)
144-
}
145-
146151
predicate isStatePair(StatePair p) { any() }
147152

148153
predicate delta2(StatePair q, StatePair r) { step(q, _, _, r) }
@@ -181,11 +186,43 @@ predicate isFork(State q, InputSymbol s1, InputSymbol s2, State r1, State r2) {
181186
r1 != r2
182187
or
183188
r1 = r2 and q1 != q2
189+
or
190+
// If q can reach itself by epsilon transitions, then there are two distinct paths to the q1/q2 state:
191+
// one that uses the loop and one that doesn't. The engine will separately attempt to match with each path,
192+
// despite ending in the same state. The "fork" thus arises from the choice of whether to use the loop or not.
193+
// To avoid every state in the loop becoming a fork state,
194+
// we arbitrarily pick the InfiniteRepetitionQuantifier state as the canonical fork state for the loop
195+
// (every epsilon-loop must contain such a state).
196+
//
197+
// We additionally require that the there exists another InfiniteRepetitionQuantifier `mid` on the path from `q` to itself.
198+
// This is done to avoid flagging regular expressions such as `/(a?)*b/` - that only has polynomial runtime, and is detected by `js/polynomial-redos`.
199+
// The below code is therefore a heuritic, that only flags regular expressions such as `/(a*)*b/`,
200+
// and does not flag regular expressions such as `/(a?b?)c/`, but the latter pattern is not used frequently.
201+
r1 = r2 and
202+
q1 = q2 and
203+
epsilonSucc+(q) = q and
204+
exists(RegExpTerm term | term = q.getRepr() | term instanceof InfiniteRepetitionQuantifier) and
205+
// One of the mid states is an infinite quantifier itself
206+
exists(State mid, RegExpTerm term |
207+
mid = epsilonSucc+(q) and
208+
term = mid.getRepr() and
209+
term instanceof InfiniteRepetitionQuantifier and
210+
q = epsilonSucc+(mid) and
211+
not mid = q
212+
)
184213
) and
185214
stateInsideBacktracking(r1) and
186215
stateInsideBacktracking(r2)
187216
}
188217

218+
/**
219+
* Gets the state pair `(q1, q2)` or `(q2, q1)`; note that only
220+
* one or the other is defined.
221+
*/
222+
StatePair mkStatePair(State q1, State q2) {
223+
result = MkStatePair(q1, q2) or result = MkStatePair(q2, q1)
224+
}
225+
189226
/**
190227
* Holds if there are transitions from the components of `q` to the corresponding
191228
* components of `r` labelled with `s1` and `s2`, respectively.

javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
| highlight.js:2:26:2:979 | ((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firewall\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+ | Strings starting with '/' and with many repetitions of 'ip ' can start matching anywhere after the start of the preceeding (\\.\\.\\/\|\\/\|\\s)((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firewall\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+X |
2+
| highlight.js:3:27:3:971 | ((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+ | Strings starting with '/' and with many repetitions of 'ip ' can start matching anywhere after the start of the preceeding (\\.\\.\\/\|\\/\|\\s)((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+X |
3+
| highlight.js:6:12:6:695 | (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|New\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+ | Strings with many repetitions of 'Add' can start matching anywhere after the start of the preceeding (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|New\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+(-)[\\w\\d]+ |
4+
| highlight.js:7:13:7:692 | (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+ | Strings with many repetitions of 'Add' can start matching anywhere after the start of the preceeding (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+(-)[\\w\\d]+ |
5+
| highlight.js:14:17:14:52 | [a-z0-9&#*=?@\\\\><:,()$[\\]_.{}!+%^-]+ | Strings with many repetitions of '!' can start matching anywhere after the start of the preceeding ([ ]*[a-z0-9&#*=?@\\\\><:,()$[\\]_.{}!+%^-]+)+ |
6+
| highlight.js:18:14:18:16 | .*? | Strings starting with ''' and with many repetitions of ''' can start matching anywhere after the start of the preceeding ('.*?'\|".*?"\|\\[.*?\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+\|\\.\|\\/)+ |
7+
| highlight.js:18:20:18:22 | .*? | Strings starting with '"' and with many repetitions of '"' can start matching anywhere after the start of the preceeding ('.*?'\|".*?"\|\\[.*?\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+\|\\.\|\\/)+ |
8+
| highlight.js:18:27:18:29 | .*? | Strings starting with '[' and with many repetitions of '[' can start matching anywhere after the start of the preceeding ('.*?'\|".*?"\|\\[.*?\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+\|\\.\|\\/)+ |
9+
| highlight.js:18:33:18:69 | [^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+ | Strings with many repetitions of '$' can start matching anywhere after the start of the preceeding ('.*?'\|".*?"\|\\[.*?\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+\|\\.\|\\/)+ |
10+
| highlight.js:19:56:19:61 | [^\\]]+ | Strings starting with '[' and with many repetitions of '[' can start matching anywhere after the start of the preceeding (\\.\|\\.\\/\|\\/)?(""\|"[^"]+"\|''\|'[^']+'\|\\[\\]\|\\[[^\\]]+\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+)((\\.\|\\/)(""\|"[^"]+"\|''\|'[^']+'\|\\[\\]\|\\[[^\\]]+\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+))* |
11+
| highlight.js:19:141:19:146 | [^\\]]+ | Strings starting with '"".[' and with many repetitions of '$.[' can start matching anywhere after the start of the preceeding (\\.\|\\.\\/\|\\/)?(""\|"[^"]+"\|''\|'[^']+'\|\\[\\]\|\\[[^\\]]+\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+)((\\.\|\\/)(""\|"[^"]+"\|''\|'[^']+'\|\\[\\]\|\\[[^\\]]+\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+))* |
12+
| highlight.js:22:12:22:82 | ((decltype\\(auto\\)\|(?:[a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(?:<.*?>)?)[\\*&\\s]+)+ | Strings with many repetitions of 'A\\t' can start matching anywhere after the start of the preceeding ((decltype\\(auto\\)\|(?:[a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(?:<.*?>)?)[\\*&\\s]+)+(?:[a-zA-Z_]\\w*::)?[a-zA-Z]\\w*\\s*\\( |
13+
| highlight.js:22:43:22:45 | \\w* | Strings starting with 'A' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding ((decltype\\(auto\\)\|(?:[a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(?:<.*?>)?)[\\*&\\s]+)+(?:[a-zA-Z_]\\w*::)?[a-zA-Z]\\w*\\s*\\( |
14+
| highlight.js:22:66:22:68 | .*? | Strings starting with 'A<' and with many repetitions of 'A<' can start matching anywhere after the start of the preceeding ((decltype\\(auto\\)\|(?:[a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(?:<.*?>)?)[\\*&\\s]+)+ |
15+
| highlight.js:22:73:22:80 | [\\*&\\s]+ | Strings starting with 'A' and with many repetitions of '\\tA\\t' can start matching anywhere after the start of the preceeding ((decltype\\(auto\\)\|(?:[a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(?:<.*?>)?)[\\*&\\s]+)+(?:[a-zA-Z_]\\w*::)?[a-zA-Z]\\w*\\s*\\( |
16+
| highlight.js:23:13:23:82 | ((decltype\\(auto\\)\|([a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(<[^<>]+>)?)[\\*&\\s]+)+ | Strings with many repetitions of 'A\\t' can start matching anywhere after the start of the preceeding ((decltype\\(auto\\)\|([a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(<[^<>]+>)?)[\\*&\\s]+)+([a-zA-Z_]\\w*::)?[a-zA-Z]\\w*\\s*\\( |
17+
| highlight.js:23:42:23:44 | \\w* | Strings starting with 'A' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding ((decltype\\(auto\\)\|([a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(<[^<>]+>)?)[\\*&\\s]+)+([a-zA-Z_]\\w*::)?[a-zA-Z]\\w*\\s*\\( |
18+
| highlight.js:23:63:23:68 | [^<>]+ | Strings starting with 'A<' and with many repetitions of ';>\\tA<' can start matching anywhere after the start of the preceeding ((decltype\\(auto\\)\|([a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(<[^<>]+>)?)[\\*&\\s]+)+([a-zA-Z_]\\w*::)?[a-zA-Z]\\w*\\s*\\( |
19+
| highlight.js:23:73:23:80 | [\\*&\\s]+ | Strings starting with 'A' and with many repetitions of '\\tA\\t' can start matching anywhere after the start of the preceeding ((decltype\\(auto\\)\|([a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(<[^<>]+>)?)[\\*&\\s]+)+([a-zA-Z_]\\w*::)?[a-zA-Z]\\w*\\s*\\( |
20+
| highlight.js:26:14:26:34 | (([\\/.])[\\w\\-.\\/=]+)+ | Strings with many repetitions of '.-' can start matching anywhere after the start of the preceeding [\\w\\-.\\/=]+ |
21+
| highlight.js:26:22:26:32 | [\\w\\-.\\/=]+ | Strings with many repetitions of '.-' can start matching anywhere after the start of the preceeding (([\\/.])[\\w\\-.\\/=]+)+ |
22+
| highlight.js:31:14:31:28 | (?:\\\\.\|[^`\\\\])+ | Strings starting with '`' and with many repetitions of '\\\\`' can start matching anywhere after the start of the preceeding `(?:\\\\.\|[^`\\\\])+` |
23+
| highlight.js:38:21:38:23 | \\w* | Strings starting with 'A' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding [a-zA-Z_]\\w*\\([^()]*(\\([^()]*(\\([^()]*\\))*[^()]*\\))*[^()]*\\)\\s*\\{ |
24+
| highlight.js:38:54:38:59 | [^()]* | Strings starting with 'A((' and with many repetitions of ''' can start matching anywhere after the start of the preceeding [^()]* |
25+
| highlight.js:38:64:38:69 | [^()]* | Strings starting with 'A(' and with many repetitions of ''' can start matching anywhere after the start of the preceeding [^()]* |
26+
| highlight.js:39:22:39:24 | \\w* | Strings starting with 'A' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding [a-zA-Z_]\\w*\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{ |
127
| polynomial-redos.js:7:24:7:26 | \\s+ | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s+$ |
228
| polynomial-redos.js:8:17:8:18 | * | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding *, * |
329
| polynomial-redos.js:9:19:9:21 | \\s* | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s*\\n\\s* |
@@ -453,3 +479,10 @@
453479
| tst.js:329:14:329:20 | (c?a?)* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (c?a?)*b |
454480
| tst.js:332:14:332:22 | (?:a\|a?)+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (?:a\|a?)+b |
455481
| tst.js:335:14:335:20 | (a?b?)* | Strings with many repetitions of 'b' can start matching anywhere after the start of the preceeding (a?b?)*$ |
482+
| tst.js:341:16:341:19 | (a)+ | Strings with many repetitions of 'aa' can start matching anywhere after the start of the preceeding ((a)+\\w)+ |
483+
| tst.js:344:16:344:17 | b+ | Strings with many repetitions of 'bb' can start matching anywhere after the start of the preceeding (b+.)+ |
484+
| tst.js:347:15:347:16 | a* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding a*b |
485+
| tst.js:350:15:350:16 | a* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a*)*b |
486+
| tst.js:351:15:351:16 | a+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a+)* |
487+
| tst.js:352:15:352:16 | a* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a*)+b |
488+
| tst.js:353:15:353:16 | a+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a+)+ |

0 commit comments

Comments
 (0)