9
9
* Theorem 3 from the paper describes the basic idea.
10
10
*
11
11
* The following explains the idea using variables and predicate names that are used in the implementation:
12
- * We consider a pair of repetitions, which we will call `pivot` and `succ `.
12
+ * We consider a pair of repetitions, which we will call `pivot` and `pumpEnd `.
13
13
*
14
14
* We create a product automaton of 3-tuples of states (see `StateTuple`).
15
15
* There exists a transition `(a,b,c) -> (d,e,f)` in the product automaton
16
16
* iff there exists three transitions in the NFA `a->d, b->e, c->f` where those three
17
17
* transitions all match a shared character `char`. (see `getAThreewayIntersect`)
18
18
*
19
- * We start a search in the product automaton at `(pivot, pivot, succ )`,
19
+ * We start a search in the product automaton at `(pivot, pivot, pumpEnd )`,
20
20
* and search for a series of transitions (a `Trace`), such that we end
21
- * at `(pivot, succ, succ )` (see `isReachableFromStartTuple`).
21
+ * at `(pivot, pumpEnd, pumpEnd )` (see `isReachableFromStartTuple`).
22
22
*
23
23
* For example, consider the regular expression `/^\d*5\w*$/`.
24
24
* The search will start at the tuple `(\d*, \d*, \w*)` and search
@@ -52,29 +52,29 @@ module Make<RegexTreeViewSig TreeImpl> {
52
52
53
53
private newtype TStateTuple =
54
54
/**
55
- * A tuple of states `(q1, q2, q3)` in the product automaton that is reachable from `(pivot, pivot, succ )`.
55
+ * A tuple of states `(q1, q2, q3)` in the product automaton that is reachable from `(pivot, pivot, pumpEnd )`.
56
56
*/
57
- MkStateTuple ( State pivot , State succ , State q1 , State q2 , State q3 ) {
58
- // starts at (pivot, pivot, succ )
57
+ MkStateTuple ( State pivot , State pumpEnd , State q1 , State q2 , State q3 ) {
58
+ // starts at (pivot, pivot, pumpEnd )
59
59
isStartLoops ( q1 , q3 ) and
60
60
q1 = q2 and
61
61
pivot = q1 and
62
- succ = q3
62
+ pumpEnd = q3
63
63
or
64
64
// recurse: any transition out where all 3 edges share a char (and the resulting tuple isn't obviously infeasible)
65
65
exists ( StateTuple prev |
66
- prev = MkStateTuple ( pivot , succ , _, _, _) and
66
+ prev = MkStateTuple ( pivot , pumpEnd , _, _, _) and
67
67
hasCommonStep ( prev , _, _, _, q1 , q2 , q3 ) and
68
- FeasibleTuple:: isFeasibleTuple ( pivot , succ , q1 , q2 , q3 )
68
+ FeasibleTuple:: isFeasibleTuple ( pivot , pumpEnd , q1 , q2 , q3 )
69
69
)
70
70
}
71
71
72
72
/**
73
- * A state `(q1, q2, q3)` in the product automaton, that is reachable from `(pivot, pivot, succ )`.
73
+ * A state `(q1, q2, q3)` in the product automaton, that is reachable from `(pivot, pivot, pumpEnd )`.
74
74
*
75
75
* We lazily only construct those states that we are actually
76
76
* going to need.
77
- * Either a start state `(pivot, pivot, succ )`, or a state
77
+ * Either a start state `(pivot, pivot, pumpEnd )`, or a state
78
78
* where there exists a transition from an already existing state.
79
79
*
80
80
* The exponential variant of this query (`js/redos`) uses an optimization
@@ -83,12 +83,12 @@ module Make<RegexTreeViewSig TreeImpl> {
83
83
*/
84
84
class StateTuple extends TStateTuple {
85
85
State pivot ;
86
- State succ ;
86
+ State pumpEnd ;
87
87
State q1 ;
88
88
State q2 ;
89
89
State q3 ;
90
90
91
- StateTuple ( ) { this = MkStateTuple ( pivot , succ , q1 , q2 , q3 ) }
91
+ StateTuple ( ) { this = MkStateTuple ( pivot , pumpEnd , q1 , q2 , q3 ) }
92
92
93
93
/**
94
94
* Gest a string representation of this tuple.
@@ -122,9 +122,9 @@ module Make<RegexTreeViewSig TreeImpl> {
122
122
State getPivot ( ) { result = pivot }
123
123
124
124
/**
125
- * Gets the succ state.
125
+ * Gets the pumpEnd state.
126
126
*/
127
- State getSucc ( ) { result = succ }
127
+ State getPumpEnd ( ) { result = pumpEnd }
128
128
129
129
/**
130
130
* Holds if the pivot state has the specified location.
@@ -142,17 +142,17 @@ module Make<RegexTreeViewSig TreeImpl> {
142
142
*/
143
143
private module FeasibleTuple {
144
144
/**
145
- * Holds if the tuple `(r1, r2, r3)` might be on path from a start-state `(pivot, pivot, succ )` to an end-state `(pivot, succ, succ )` in the product automaton.
145
+ * Holds if the tuple `(r1, r2, r3)` might be on path from a start-state `(pivot, pivot, pumpEnd )` to an end-state `(pivot, pumpEnd, pumpEnd )` in the product automaton.
146
146
*/
147
- bindingset [ pivot, succ , r1, r2, r3]
147
+ bindingset [ pivot, pumpEnd , r1, r2, r3]
148
148
pragma [ inline_late]
149
- predicate isFeasibleTuple ( State pivot , State succ , State r1 , State r2 , State r3 ) {
150
- isStartLoops ( pivot , succ ) and
149
+ predicate isFeasibleTuple ( State pivot , State pumpEnd , State r1 , State r2 , State r3 ) {
150
+ isStartLoops ( pivot , pumpEnd ) and
151
151
// r1 can reach the pivot state
152
152
reachesBeginning ( r1 , pivot ) and
153
- // r2 and r3 can reach the succ state
154
- reachesEnd ( r2 , succ ) and
155
- reachesEnd ( r3 , succ ) and
153
+ // r2 and r3 can reach the pumpEnd state
154
+ reachesEnd ( r2 , pumpEnd ) and
155
+ reachesEnd ( r3 , pumpEnd ) and
156
156
// The first element is either inside a repetition (or the start state itself)
157
157
isRepetitionOrStart ( r1 ) and
158
158
// The last element is inside a repetition
@@ -169,9 +169,9 @@ module Make<RegexTreeViewSig TreeImpl> {
169
169
}
170
170
171
171
pragma [ noinline]
172
- private predicate reachesEnd ( State s , State succ ) {
173
- isStartLoops ( _, succ ) and
174
- delta + ( s ) = succ
172
+ private predicate reachesEnd ( State s , State pumpEnd ) {
173
+ isStartLoops ( _, pumpEnd ) and
174
+ delta + ( s ) = pumpEnd
175
175
}
176
176
177
177
/**
@@ -192,15 +192,15 @@ module Make<RegexTreeViewSig TreeImpl> {
192
192
}
193
193
194
194
/**
195
- * Holds if `pivot` and `succ ` are a pair of loops that could be the beginning of a quadratic blowup.
195
+ * Holds if `pivot` and `pumpEnd ` are a pair of loops that could be the beginning of a quadratic blowup.
196
196
*
197
- * There is a slight implementation difference compared to the paper: this predicate requires that `pivot != succ `.
198
- * The case where `pivot = succ ` causes exponential backtracking and is handled by the `js/redos` query.
197
+ * There is a slight implementation difference compared to the paper: this predicate requires that `pivot != pumpEnd `.
198
+ * The case where `pivot = pumpEnd ` causes exponential backtracking and is handled by the `js/redos` query.
199
199
*/
200
- predicate isStartLoops ( State pivot , State succ ) {
201
- pivot != succ and
202
- succ .getRepr ( ) instanceof InfiniteRepetitionQuantifier and
203
- delta + ( pivot ) = succ and
200
+ predicate isStartLoops ( State pivot , State pumpEnd ) {
201
+ pivot != pumpEnd and
202
+ pumpEnd .getRepr ( ) instanceof InfiniteRepetitionQuantifier and
203
+ delta + ( pivot ) = pumpEnd and
204
204
(
205
205
pivot .getRepr ( ) instanceof InfiniteRepetitionQuantifier
206
206
or
@@ -223,7 +223,7 @@ module Make<RegexTreeViewSig TreeImpl> {
223
223
exists ( State r1 , State r2 , State r3 |
224
224
hasCommonStep ( q , s1 , s2 , s3 , r1 , r2 , r3 ) and
225
225
r =
226
- MkStateTuple ( pragma [ only_bind_out ] ( q .getPivot ( ) ) , pragma [ only_bind_out ] ( q .getSucc ( ) ) ,
226
+ MkStateTuple ( pragma [ only_bind_out ] ( q .getPivot ( ) ) , pragma [ only_bind_out ] ( q .getPumpEnd ( ) ) ,
227
227
pragma [ only_bind_out ] ( r1 ) , pragma [ only_bind_out ] ( r2 ) , pragma [ only_bind_out ] ( r3 ) )
228
228
)
229
229
}
@@ -270,34 +270,34 @@ module Make<RegexTreeViewSig TreeImpl> {
270
270
}
271
271
272
272
/** Gets a tuple reachable in a forwards exploratory search from the start state `(pivot, pivot, pivot)`. */
273
- private StateTuple getReachableFromStartStateForwards ( State pivot , State succ ) {
273
+ private StateTuple getReachableFromStartStateForwards ( State pivot , State pumpEnd ) {
274
274
// base case.
275
- isStartLoops ( pivot , succ ) and
276
- result = MkStateTuple ( pivot , succ , pivot , pivot , succ )
275
+ isStartLoops ( pivot , pumpEnd ) and
276
+ result = MkStateTuple ( pivot , pumpEnd , pivot , pivot , pumpEnd )
277
277
or
278
278
// recursive case
279
279
exists ( StateTuple p |
280
- p = getReachableFromStartStateForwards ( pivot , succ ) and
280
+ p = getReachableFromStartStateForwards ( pivot , pumpEnd ) and
281
281
step ( p , _, _, _, result )
282
282
)
283
283
}
284
284
285
285
/**
286
- * Gets a state tuple that can reach the end state `(succ, succ, succ )`, found via a backwards exploratory search.
287
- * Where the end state was reachable from a forwards search from the start state `(pivot, pivot, pivot )`.
286
+ * Gets a state tuple that can reach the end state `(pivot, pumpEnd, pumpEnd )`, found via a backwards exploratory search.
287
+ * Where the end state was reachable from a forwards search from the start state `(pivot, pivot, pumpEnd )`.
288
288
* The resulting tuples are exactly those that are on a path from the start state to the end state.
289
289
*/
290
- private StateTuple getARelevantStateTuple ( State pivot , State succ ) {
290
+ private StateTuple getARelevantStateTuple ( State pivot , State pumpEnd ) {
291
291
// base case.
292
- isStartLoops ( pivot , succ ) and
293
- result = MkStateTuple ( pivot , succ , pivot , succ , succ ) and
294
- result = getReachableFromStartStateForwards ( pivot , succ )
292
+ isStartLoops ( pivot , pumpEnd ) and
293
+ result = MkStateTuple ( pivot , pumpEnd , pivot , pumpEnd , pumpEnd ) and
294
+ result = getReachableFromStartStateForwards ( pivot , pumpEnd )
295
295
or
296
296
// recursive case
297
297
exists ( StateTuple p |
298
- p = getARelevantStateTuple ( pivot , succ ) and
298
+ p = getARelevantStateTuple ( pivot , pumpEnd ) and
299
299
step ( result , _, _, _, p ) and
300
- pragma [ only_bind_out ] ( result ) = getReachableFromStartStateForwards ( pivot , succ ) // was reachable in the forwards pass.
300
+ pragma [ only_bind_out ] ( result ) = getReachableFromStartStateForwards ( pivot , pumpEnd ) // was reachable in the forwards pass.
301
301
)
302
302
}
303
303
@@ -309,14 +309,14 @@ module Make<RegexTreeViewSig TreeImpl> {
309
309
pragma [ noinline]
310
310
predicate tupleDeltaBackwards ( StateTuple dst , StateTuple src ) {
311
311
step ( src , _, _, _, dst ) and
312
- // `step` ensures that `src` and `dst` have the same pivot and succ .
312
+ // `step` ensures that `src` and `dst` have the same pivot and pumpEnd .
313
313
src = getARelevantStateTuple ( _, _) and
314
314
dst = getARelevantStateTuple ( _, _)
315
315
}
316
316
317
317
/**
318
318
* Holds if `tuple` is an end state in our search, and `tuple` is on a path from a start state to an end state.
319
- * That means there exists a pair of loops `(pivot, succ )` such that `tuple = (pivot, succ, succ )`.
319
+ * That means there exists a pair of loops `(pivot, pumpEnd )` such that `tuple = (pivot, pumpEnd, pumpEnd )`.
320
320
*/
321
321
predicate isEndTuple ( StateTuple tuple ) {
322
322
tuple = getEndTuple ( _, _) and
@@ -341,8 +341,8 @@ module Make<RegexTreeViewSig TreeImpl> {
341
341
StateTuple q , InputSymbol s1 , InputSymbol s2 , InputSymbol s3 , StateTuple r
342
342
) {
343
343
step ( q , s1 , s2 , s3 , r ) and
344
- exists ( State pivot , State succ , StateTuple end |
345
- end = MkStateTuple ( pivot , succ , pivot , succ , succ ) and
344
+ exists ( State pivot , State pumpEnd , StateTuple end |
345
+ end = MkStateTuple ( pivot , pumpEnd , pivot , pumpEnd , pumpEnd ) and
346
346
pragma [ only_bind_out ] ( distBackFromEnd ( q , end ) ) =
347
347
pragma [ only_bind_out ] ( distBackFromEnd ( r , end ) ) + 1
348
348
)
@@ -385,15 +385,15 @@ module Make<RegexTreeViewSig TreeImpl> {
385
385
}
386
386
387
387
private newtype TTrace =
388
- Nil ( State pivot , State succ ) {
389
- isStartLoops ( pivot , succ ) and
390
- getStartTuple ( pivot , succ ) = getARelevantStateTuple ( pivot , succ )
388
+ Nil ( State pivot , State pumpEnd ) {
389
+ isStartLoops ( pivot , pumpEnd ) and
390
+ getStartTuple ( pivot , pumpEnd ) = getARelevantStateTuple ( pivot , pumpEnd )
391
391
} or
392
392
Step ( TTrace prev , StateTuple nextTuple ) {
393
393
exists ( StateTuple prevTuple |
394
- exists ( State pivot , State succ |
395
- prev = Nil ( pivot , succ ) and
396
- prevTuple = getStartTuple ( pivot , succ )
394
+ exists ( State pivot , State pumpEnd |
395
+ prev = Nil ( pivot , pumpEnd ) and
396
+ prevTuple = getStartTuple ( pivot , pumpEnd )
397
397
)
398
398
or
399
399
prev = Step ( _, prevTuple )
@@ -404,7 +404,7 @@ module Make<RegexTreeViewSig TreeImpl> {
404
404
405
405
/**
406
406
* A list of tuples of input symbols that describe a path in the product automaton
407
- * starting from a start state `(pivot, pivot, succ )`.
407
+ * starting from a start state `(pivot, pivot, pumpEnd )`.
408
408
*/
409
409
class Trace extends TTrace {
410
410
/**
@@ -419,27 +419,27 @@ module Make<RegexTreeViewSig TreeImpl> {
419
419
StateTuple getTuple ( ) {
420
420
this = Step ( _, result )
421
421
or
422
- exists ( State prev , State succ |
423
- this = Nil ( prev , succ ) and
424
- result = getStartTuple ( prev , succ )
422
+ exists ( State prev , State pumpEnd |
423
+ this = Nil ( prev , pumpEnd ) and
424
+ result = getStartTuple ( prev , pumpEnd )
425
425
)
426
426
}
427
427
}
428
428
429
429
/**
430
- * Gets the tuple `(pivot, succ, succ )` from the product automaton.
430
+ * Gets the tuple `(pivot, pumpEnd, pumpEnd )` from the product automaton.
431
431
*/
432
- StateTuple getEndTuple ( State pivot , State succ ) {
433
- isStartLoops ( pivot , succ ) and
434
- result = MkStateTuple ( pivot , succ , pivot , succ , succ )
432
+ StateTuple getEndTuple ( State pivot , State pumpEnd ) {
433
+ isStartLoops ( pivot , pumpEnd ) and
434
+ result = MkStateTuple ( pivot , pumpEnd , pivot , pumpEnd , pumpEnd )
435
435
}
436
436
437
437
/**
438
- * Gets the tuple `(pivot, pivot, succ )` from the product automaton.
438
+ * Gets the tuple `(pivot, pivot, pumpEnd )` from the product automaton.
439
439
*/
440
- StateTuple getStartTuple ( State pivot , State succ ) {
441
- isStartLoops ( pivot , succ ) and
442
- result = MkStateTuple ( pivot , succ , pivot , pivot , succ )
440
+ StateTuple getStartTuple ( State pivot , State pumpEnd ) {
441
+ isStartLoops ( pivot , pumpEnd ) and
442
+ result = MkStateTuple ( pivot , pumpEnd , pivot , pivot , pumpEnd )
443
443
}
444
444
445
445
/** An implementation of a chain containing chars for use by `Concretizer`. */
@@ -464,18 +464,18 @@ module Make<RegexTreeViewSig TreeImpl> {
464
464
/**
465
465
* Holds if matching repetitions of `pump` can:
466
466
* 1) Transition from `pivot` back to `pivot`.
467
- * 2) Transition from `pivot` to `succ `.
468
- * 3) Transition from `succ ` to `succ `.
467
+ * 2) Transition from `pivot` to `pumpEnd `.
468
+ * 3) Transition from `pumpEnd ` to `pumpEnd `.
469
469
*
470
470
* From theorem 3 in the paper linked in the top of this file we can therefore conclude that
471
471
* the regular expression has polynomial backtracking - if a rejecting suffix exists.
472
472
*
473
473
* This predicate is used by `SuperLinearReDoSConfiguration`, and the final results are
474
474
* available in the `hasReDoSResult` predicate.
475
475
*/
476
- predicate isPumpable ( State pivot , State succ , string pump ) {
476
+ predicate isPumpable ( State pivot , State pumpEnd , string pump ) {
477
477
exists ( StateTuple q , Trace t |
478
- q = getEndTuple ( pivot , succ ) and
478
+ q = getEndTuple ( pivot , pumpEnd ) and
479
479
q = t .getTuple ( ) and
480
480
pump = Concretizer< CharTreeImpl > :: concretize ( t )
481
481
)
0 commit comments