Skip to content

ExponentialBackTracking: Speedup concretise #8589

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -279,17 +279,6 @@ private class Trace extends TTrace {
}
}

/**
* Gets a string corresponding to the trace `t`.
*/
private string concretise(Trace t) {
t = Nil() and result = ""
or
exists(InputSymbol s1, InputSymbol s2, Trace rest | t = Step(s1, s2, rest) |
result = concretise(rest) + intersect(s1, s2)
)
}

/**
* Holds if `r` is reachable from `(fork, fork)` under input `w`, and there is
* a path from `r` back to `(fork, fork)` with `rem` steps.
Expand Down Expand Up @@ -321,14 +310,54 @@ private StatePair getAForkPair(State fork) {
result = MkStatePair(epsilonPred*(fork), epsilonPred*(fork))
}

private predicate hasSuffix(Trace suffix, Trace t, int i) {
// Declaring `t` to be a `RelevantTrace` currently causes a redundant check in the
// recursive case, so instead we check it explicitly here.
t instanceof RelevantTrace and
i = 0 and
suffix = t
or
hasSuffix(Step(_, _, suffix), t, i - 1)
}

pragma[noinline]
private predicate hasTuple(InputSymbol s1, InputSymbol s2, Trace t, int i) {
hasSuffix(Step(s1, s2, _), t, i)
}

private class RelevantTrace extends Trace, Step {
RelevantTrace() {
exists(State fork, StatePair q |
isReachableFromFork(fork, q, this, _) and
q = getAForkPair(fork)
)
}

pragma[noinline]
private string intersect(int i) {
exists(InputSymbol s1, InputSymbol s2 |
hasTuple(s1, s2, this, i) and
result = intersect(s1, s2)
)
}

/** Gets a string corresponding to this trace. */
// the pragma is needed for the case where `intersect(s1, s2)` has multiple values,
// not for recursion
language[monotonicAggregates]
string concretise() {
result = strictconcat(int i | hasTuple(_, _, this, i) | this.intersect(i) order by i desc)
}
}

/**
* Holds if `fork` is a pumpable fork with word `w`.
*/
private predicate isPumpable(State fork, string w) {
exists(StatePair q, Trace t |
exists(StatePair q, RelevantTrace t |
isReachableFromFork(fork, q, t, _) and
q = getAForkPair(fork) and
w = concretise(t)
w = t.concretise()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ abstract class ReDoSConfiguration extends string {
}

/**
* Holds if repeating `pump' starting at `state` is a candidate for causing backtracking.
* Holds if repeating `pump` starting at `state` is a candidate for causing backtracking.
* No check whether a rejected suffix exists has been made.
*/
private predicate isReDoSCandidate(State state, string pump) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,17 +254,6 @@ class Trace extends TTrace {
}
}

/**
* Gets a string corresponding to the trace `t`.
*/
string concretise(Trace t) {
t = Nil() and result = ""
or
exists(InputSymbol s1, InputSymbol s2, InputSymbol s3, Trace rest | t = Step(s1, s2, s3, rest) |
result = concretise(rest) + getAThreewayIntersect(s1, s2, s3)
)
}

/**
* Holds if there exists a transition from `r` to `q` in the product automaton.
* Notice that the arguments are flipped, and thus the direction is backwards.
Expand Down Expand Up @@ -332,6 +321,51 @@ StateTuple getAnEndTuple(State pivot, State succ) {
result = MkStateTuple(pivot, succ, succ)
}

private predicate hasSuffix(Trace suffix, Trace t, int i) {
// Declaring `t` to be a `RelevantTrace` currently causes a redundant check in the
// recursive case, so instead we check it explicitly here.
t instanceof RelevantTrace and
i = 0 and
suffix = t
or
hasSuffix(Step(_, _, _, suffix), t, i - 1)
}

pragma[noinline]
private predicate hasTuple(InputSymbol s1, InputSymbol s2, InputSymbol s3, Trace t, int i) {
hasSuffix(Step(s1, s2, s3, _), t, i)
}

private class RelevantTrace extends Trace, Step {
RelevantTrace() {
exists(State pivot, State succ, StateTuple q |
isReachableFromStartTuple(pivot, succ, q, this, _) and
q = getAnEndTuple(pivot, succ)
)
}

pragma[noinline]
private string getAThreewayIntersect(int i) {
exists(InputSymbol s1, InputSymbol s2, InputSymbol s3 |
hasTuple(s1, s2, s3, this, i) and
result = getAThreewayIntersect(s1, s2, s3)
)
}

/** Gets a string corresponding to this trace. */
// the pragma is needed for the case where `getAThreewayIntersect(s1, s2, s3)` has multiple values,
// not for recursion
language[monotonicAggregates]
string concretise() {
result =
strictconcat(int i |
hasTuple(_, _, _, this, i)
|
this.getAThreewayIntersect(i) order by i desc
)
}
}

/**
* Holds if matching repetitions of `pump` can:
* 1) Transition from `pivot` back to `pivot`.
Expand All @@ -345,10 +379,10 @@ StateTuple getAnEndTuple(State pivot, State succ) {
* available in the `hasReDoSResult` predicate.
*/
predicate isPumpable(State pivot, State succ, string pump) {
exists(StateTuple q, Trace t |
exists(StateTuple q, RelevantTrace t |
isReachableFromStartTuple(pivot, succ, q, t, _) and
q = getAnEndTuple(pivot, succ) and
pump = concretise(t)
pump = t.concretise()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,17 +279,6 @@ private class Trace extends TTrace {
}
}

/**
* Gets a string corresponding to the trace `t`.
*/
private string concretise(Trace t) {
t = Nil() and result = ""
or
exists(InputSymbol s1, InputSymbol s2, Trace rest | t = Step(s1, s2, rest) |
result = concretise(rest) + intersect(s1, s2)
)
}

/**
* Holds if `r` is reachable from `(fork, fork)` under input `w`, and there is
* a path from `r` back to `(fork, fork)` with `rem` steps.
Expand Down Expand Up @@ -321,14 +310,54 @@ private StatePair getAForkPair(State fork) {
result = MkStatePair(epsilonPred*(fork), epsilonPred*(fork))
}

private predicate hasSuffix(Trace suffix, Trace t, int i) {
// Declaring `t` to be a `RelevantTrace` currently causes a redundant check in the
// recursive case, so instead we check it explicitly here.
t instanceof RelevantTrace and
i = 0 and
suffix = t
or
hasSuffix(Step(_, _, suffix), t, i - 1)
}

pragma[noinline]
private predicate hasTuple(InputSymbol s1, InputSymbol s2, Trace t, int i) {
hasSuffix(Step(s1, s2, _), t, i)
}

private class RelevantTrace extends Trace, Step {
RelevantTrace() {
exists(State fork, StatePair q |
isReachableFromFork(fork, q, this, _) and
q = getAForkPair(fork)
)
}

pragma[noinline]
private string intersect(int i) {
exists(InputSymbol s1, InputSymbol s2 |
hasTuple(s1, s2, this, i) and
result = intersect(s1, s2)
)
}

/** Gets a string corresponding to this trace. */
// the pragma is needed for the case where `intersect(s1, s2)` has multiple values,
// not for recursion
language[monotonicAggregates]
string concretise() {
result = strictconcat(int i | hasTuple(_, _, this, i) | this.intersect(i) order by i desc)
}
}

/**
* Holds if `fork` is a pumpable fork with word `w`.
*/
private predicate isPumpable(State fork, string w) {
exists(StatePair q, Trace t |
exists(StatePair q, RelevantTrace t |
isReachableFromFork(fork, q, t, _) and
q = getAForkPair(fork) and
w = concretise(t)
w = t.concretise()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ abstract class ReDoSConfiguration extends string {
}

/**
* Holds if repeating `pump' starting at `state` is a candidate for causing backtracking.
* Holds if repeating `pump` starting at `state` is a candidate for causing backtracking.
* No check whether a rejected suffix exists has been made.
*/
private predicate isReDoSCandidate(State state, string pump) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,17 +254,6 @@ class Trace extends TTrace {
}
}

/**
* Gets a string corresponding to the trace `t`.
*/
string concretise(Trace t) {
t = Nil() and result = ""
or
exists(InputSymbol s1, InputSymbol s2, InputSymbol s3, Trace rest | t = Step(s1, s2, s3, rest) |
result = concretise(rest) + getAThreewayIntersect(s1, s2, s3)
)
}

/**
* Holds if there exists a transition from `r` to `q` in the product automaton.
* Notice that the arguments are flipped, and thus the direction is backwards.
Expand Down Expand Up @@ -332,6 +321,51 @@ StateTuple getAnEndTuple(State pivot, State succ) {
result = MkStateTuple(pivot, succ, succ)
}

private predicate hasSuffix(Trace suffix, Trace t, int i) {
// Declaring `t` to be a `RelevantTrace` currently causes a redundant check in the
// recursive case, so instead we check it explicitly here.
t instanceof RelevantTrace and
i = 0 and
suffix = t
or
hasSuffix(Step(_, _, _, suffix), t, i - 1)
}

pragma[noinline]
private predicate hasTuple(InputSymbol s1, InputSymbol s2, InputSymbol s3, Trace t, int i) {
hasSuffix(Step(s1, s2, s3, _), t, i)
}

private class RelevantTrace extends Trace, Step {
RelevantTrace() {
exists(State pivot, State succ, StateTuple q |
isReachableFromStartTuple(pivot, succ, q, this, _) and
q = getAnEndTuple(pivot, succ)
)
}

pragma[noinline]
private string getAThreewayIntersect(int i) {
exists(InputSymbol s1, InputSymbol s2, InputSymbol s3 |
hasTuple(s1, s2, s3, this, i) and
result = getAThreewayIntersect(s1, s2, s3)
)
}

/** Gets a string corresponding to this trace. */
// the pragma is needed for the case where `getAThreewayIntersect(s1, s2, s3)` has multiple values,
// not for recursion
language[monotonicAggregates]
string concretise() {
result =
strictconcat(int i |
hasTuple(_, _, _, this, i)
|
this.getAThreewayIntersect(i) order by i desc
)
}
}

/**
* Holds if matching repetitions of `pump` can:
* 1) Transition from `pivot` back to `pivot`.
Expand All @@ -345,10 +379,10 @@ StateTuple getAnEndTuple(State pivot, State succ) {
* available in the `hasReDoSResult` predicate.
*/
predicate isPumpable(State pivot, State succ, string pump) {
exists(StateTuple q, Trace t |
exists(StateTuple q, RelevantTrace t |
isReachableFromStartTuple(pivot, succ, q, t, _) and
q = getAnEndTuple(pivot, succ) and
pump = concretise(t)
pump = t.concretise()
)
}

Expand Down
Loading