JavaScript: Refactor type tracking to avoid computing very large relations.

This commit is contained in:
Max Schaefer
2019-03-21 16:12:14 +00:00
parent 084159dcfd
commit c50067b597
2 changed files with 46 additions and 60 deletions

View File

@@ -162,11 +162,11 @@ class SourceNode extends DataFlow::Node {
*
* See `TypeTracker` for more details about how to use this.
*/
cached
pragma[inline]
DataFlow::SourceNode track(TypeTracker t2, TypeTracker t) {
exists(StepSummary summary |
StepSummary::step(this, result, summary) and
t = StepSummary::append(t2, summary)
t = t2.append(summary)
)
}
@@ -177,11 +177,11 @@ class SourceNode extends DataFlow::Node {
*
* See `TypeBackTracker` for more details about how to use this.
*/
cached
pragma[inline]
DataFlow::SourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) {
exists(StepSummary summary |
StepSummary::step(result, this, summary) and
t = StepSummary::prepend(summary, t2)
t = t2.prepend(summary)
)
}
}

View File

@@ -13,6 +13,10 @@ private class PropertyName extends string {
PropertyName() { this = any(DataFlow::PropRef pr).getPropertyName() }
}
private class OptionalPropertyName extends string {
OptionalPropertyName() { this instanceof PropertyName or this = "" }
}
/**
* A description of a step on an inter-procedural data flow path.
*/
@@ -29,12 +33,6 @@ private newtype TStepSummary =
* A description of a step on an inter-procedural data flow path.
*/
class StepSummary extends TStepSummary {
/** Indicates whether the step represented by this summary is a return. */
boolean hasReturn() { if this instanceof ReturnStep then result = true else result = false }
/** Indicates whether the step represented by this summary is a call. */
boolean hasCall() { if this instanceof CallStep then result = true else result = false }
/** Gets a textual representation of this step summary. */
string toString() {
this instanceof LevelStep and result = "level"
@@ -42,6 +40,14 @@ class StepSummary extends TStepSummary {
this instanceof CallStep and result = "call"
or
this instanceof ReturnStep and result = "return"
or
exists(string prop | this = StoreStep(prop) |
result = "store " + prop
)
or
exists(string prop | this = LoadStep(prop) |
result = "load" + prop
)
}
}
@@ -80,58 +86,10 @@ module StepSummary {
)
)
}
/**
* INTERNAL. Do not use.
*
* Appends a step summary onto a type-tracking summary.
*/
TypeTracker append(TypeTracker type, StepSummary summary) {
exists(boolean hadCall, boolean hasCall, string oldProp, string newProp |
hadCall = type.hasCall() and
oldProp = type.getProp()
|
not (hadCall = true and summary.hasReturn() = true) and
hasCall = hadCall.booleanOr(summary.hasCall()) and
(
if summary instanceof StoreStep
then oldProp = "" and summary = StoreStep(newProp)
else
if summary instanceof LoadStep
then summary = LoadStep(oldProp) and newProp = ""
else newProp = oldProp
) and
result = MkTypeTracker(hasCall, newProp)
)
}
/**
* INTERNAL. Do not use.
*
* Prepends a step summary before a backwards type-tracking summary.
*/
TypeBackTracker prepend(StepSummary summary, TypeBackTracker type) {
exists(boolean hadReturn, boolean hasReturn, string oldProp, string newProp |
hadReturn = type.hasReturn() and
oldProp = type.getProp()
|
not (hadReturn = true and summary.hasCall() = true) and
hasReturn = hadReturn.booleanOr(summary.hasReturn()) and
(
if summary instanceof StoreStep
then summary = StoreStep(oldProp) and newProp = ""
else
if summary instanceof LoadStep
then oldProp = "" and summary = LoadStep(newProp)
else newProp = oldProp
) and
result = MkTypeBackTracker(hasReturn, newProp)
)
}
}
private newtype TTypeTracker =
MkTypeTracker(Boolean hasCall, string prop) { prop = "" or prop instanceof PropertyName }
MkTypeTracker(Boolean hasCall, OptionalPropertyName prop)
/**
* EXPERIMENTAL.
@@ -168,6 +126,20 @@ class TypeTracker extends TTypeTracker {
TypeTracker() { this = MkTypeTracker(hasCall, prop) }
TypeTracker append(StepSummary step) {
step = LevelStep() and result = this
or
step = CallStep() and result = MkTypeTracker(true, prop)
or
step = ReturnStep() and hasCall = false and result = this
or
step = LoadStep(prop) and result = MkTypeTracker(hasCall, "")
or
exists(string p |
step = StoreStep(p) and prop = "" and result = MkTypeTracker(hasCall, p)
)
}
string toString() {
exists(string withCall, string withProp |
(if hasCall = true then withCall = "with" else withCall = "without") and
@@ -198,7 +170,7 @@ module TypeTracker {
}
private newtype TTypeBackTracker =
MkTypeBackTracker(Boolean hasReturn, string prop) { prop = "" or prop instanceof PropertyName }
MkTypeBackTracker(Boolean hasReturn, OptionalPropertyName prop)
/**
* EXPERIMENTAL.
@@ -234,6 +206,20 @@ class TypeBackTracker extends TTypeBackTracker {
TypeBackTracker() { this = MkTypeBackTracker(hasReturn, prop) }
TypeBackTracker prepend(StepSummary step) {
step = LevelStep() and result = this
or
step = CallStep() and hasReturn = false and result = this
or
step = ReturnStep() and result = MkTypeBackTracker(true, prop)
or
exists(string p |
step = LoadStep(p) and prop = "" and result = MkTypeBackTracker(hasReturn, p)
)
or
step = StoreStep(prop) and result = MkTypeBackTracker(hasReturn, "")
}
string toString() {
exists(string withReturn, string withProp |
(if hasReturn = true then withReturn = "with" else withReturn = "without") and