mirror of
https://github.com/github/codeql.git
synced 2025-12-18 09:43:15 +01:00
Merge pull request #10814 from aschackmull/dataflow/synth-global
Dataflow: Add support for synthetic global fields in MaD.
This commit is contained in:
@@ -1672,6 +1672,8 @@ predicate jumpStep(Node pred, Node succ) {
|
|||||||
jrk.getTarget() = call.getATarget(_) and
|
jrk.getTarget() = call.getATarget(_) and
|
||||||
succ = getAnOutNode(call, jrk.getTargetReturnKind())
|
succ = getAnOutNode(call, jrk.getTargetReturnKind())
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
FlowSummaryImpl::Private::Steps::summaryJumpStep(pred, succ)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StoreStepConfiguration extends ControlFlowReachabilityConfiguration {
|
private class StoreStepConfiguration extends ControlFlowReachabilityConfiguration {
|
||||||
|
|||||||
@@ -61,6 +61,20 @@ module Public {
|
|||||||
|
|
||||||
/** Gets a summary component for a return of kind `rk`. */
|
/** Gets a summary component for a return of kind `rk`. */
|
||||||
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
||||||
|
|
||||||
|
/** Gets a summary component for synthetic global `sg`. */
|
||||||
|
SummaryComponent syntheticGlobal(SyntheticGlobal sg) {
|
||||||
|
result = TSyntheticGlobalSummaryComponent(sg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A synthetic global. This represents some form of global state, which
|
||||||
|
* summaries can read and write individually.
|
||||||
|
*/
|
||||||
|
abstract class SyntheticGlobal extends string {
|
||||||
|
bindingset[this]
|
||||||
|
SyntheticGlobal() { any() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -256,6 +270,7 @@ module Private {
|
|||||||
TParameterSummaryComponent(ArgumentPosition pos) or
|
TParameterSummaryComponent(ArgumentPosition pos) or
|
||||||
TArgumentSummaryComponent(ParameterPosition pos) or
|
TArgumentSummaryComponent(ParameterPosition pos) or
|
||||||
TReturnSummaryComponent(ReturnKind rk) or
|
TReturnSummaryComponent(ReturnKind rk) or
|
||||||
|
TSyntheticGlobalSummaryComponent(SummaryComponent::SyntheticGlobal sg) or
|
||||||
TWithoutContentSummaryComponent(ContentSet c) or
|
TWithoutContentSummaryComponent(ContentSet c) or
|
||||||
TWithContentSummaryComponent(ContentSet c)
|
TWithContentSummaryComponent(ContentSet c)
|
||||||
|
|
||||||
@@ -563,6 +578,11 @@ module Private {
|
|||||||
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.tail())), rk)
|
s.tail())), rk)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(SummaryComponent::SyntheticGlobal sg |
|
||||||
|
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||||
|
result = getSyntheticGlobalType(sg)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
n = summaryNodeOutputState(c, s) and
|
n = summaryNodeOutputState(c, s) and
|
||||||
@@ -582,6 +602,11 @@ module Private {
|
|||||||
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.tail())), pos)
|
s.tail())), pos)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(SummaryComponent::SyntheticGlobal sg |
|
||||||
|
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||||
|
result = getSyntheticGlobalType(sg)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -692,6 +717,18 @@ module Private {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if there is a jump step from `pred` to `succ`, which is synthesized
|
||||||
|
* from a flow summary.
|
||||||
|
*/
|
||||||
|
predicate summaryJumpStep(Node pred, Node succ) {
|
||||||
|
exists(SummaryComponentStack s |
|
||||||
|
s = SummaryComponentStack::singleton(SummaryComponent::syntheticGlobal(_)) and
|
||||||
|
pred = summaryNodeOutputState(_, s) and
|
||||||
|
succ = summaryNodeInputState(_, s)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
||||||
* synthesized summary node, so in order for values to be cleared at calls
|
* synthesized summary node, so in order for values to be cleared at calls
|
||||||
@@ -871,18 +908,28 @@ module Private {
|
|||||||
AccessPathRange() { relevantSpec(this) }
|
AccessPathRange() { relevantSpec(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if specification component `c` parses as parameter `n`. */
|
/** Holds if specification component `token` parses as parameter `pos`. */
|
||||||
predicate parseParam(AccessPathToken token, ArgumentPosition pos) {
|
predicate parseParam(AccessPathToken token, ArgumentPosition pos) {
|
||||||
token.getName() = "Parameter" and
|
token.getName() = "Parameter" and
|
||||||
pos = parseParamBody(token.getAnArgument())
|
pos = parseParamBody(token.getAnArgument())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if specification component `c` parses as argument `n`. */
|
/** Holds if specification component `token` parses as argument `pos`. */
|
||||||
predicate parseArg(AccessPathToken token, ParameterPosition pos) {
|
predicate parseArg(AccessPathToken token, ParameterPosition pos) {
|
||||||
token.getName() = "Argument" and
|
token.getName() = "Argument" and
|
||||||
pos = parseArgBody(token.getAnArgument())
|
pos = parseArgBody(token.getAnArgument())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Holds if specification component `token` parses as synthetic global `sg`. */
|
||||||
|
predicate parseSynthGlobal(AccessPathToken token, string sg) {
|
||||||
|
token.getName() = "SyntheticGlobal" and
|
||||||
|
sg = token.getAnArgument()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SyntheticGlobalFromAccessPath extends SummaryComponent::SyntheticGlobal {
|
||||||
|
SyntheticGlobalFromAccessPath() { parseSynthGlobal(_, this) }
|
||||||
|
}
|
||||||
|
|
||||||
private SummaryComponent interpretComponent(AccessPathToken token) {
|
private SummaryComponent interpretComponent(AccessPathToken token) {
|
||||||
exists(ParameterPosition pos |
|
exists(ParameterPosition pos |
|
||||||
parseArg(token, pos) and result = SummaryComponent::argument(pos)
|
parseArg(token, pos) and result = SummaryComponent::argument(pos)
|
||||||
@@ -894,6 +941,10 @@ module Private {
|
|||||||
or
|
or
|
||||||
token = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
token = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
||||||
or
|
or
|
||||||
|
exists(string sg |
|
||||||
|
parseSynthGlobal(token, sg) and result = SummaryComponent::syntheticGlobal(sg)
|
||||||
|
)
|
||||||
|
or
|
||||||
result = interpretComponentSpecific(token)
|
result = interpretComponentSpecific(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,12 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the type of synthetic global `sg`. */
|
||||||
|
DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) {
|
||||||
|
exists(sg) and
|
||||||
|
result = Gvn::getGlobalValueNumber(any(ObjectType t))
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[provenance]
|
bindingset[provenance]
|
||||||
private boolean isGenerated(string provenance) {
|
private boolean isGenerated(string provenance) {
|
||||||
provenance = "generated" and result = true
|
provenance = "generated" and result = true
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ predicate jumpStep(Node node1, Node node2) {
|
|||||||
or
|
or
|
||||||
any(AdditionalValueStep a).step(node1, node2) and
|
any(AdditionalValueStep a).step(node1, node2) and
|
||||||
node1.getEnclosingCallable() != node2.getEnclosingCallable()
|
node1.getEnclosingCallable() != node2.getEnclosingCallable()
|
||||||
|
or
|
||||||
|
FlowSummaryImpl::Private::Steps::summaryJumpStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -61,6 +61,20 @@ module Public {
|
|||||||
|
|
||||||
/** Gets a summary component for a return of kind `rk`. */
|
/** Gets a summary component for a return of kind `rk`. */
|
||||||
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
||||||
|
|
||||||
|
/** Gets a summary component for synthetic global `sg`. */
|
||||||
|
SummaryComponent syntheticGlobal(SyntheticGlobal sg) {
|
||||||
|
result = TSyntheticGlobalSummaryComponent(sg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A synthetic global. This represents some form of global state, which
|
||||||
|
* summaries can read and write individually.
|
||||||
|
*/
|
||||||
|
abstract class SyntheticGlobal extends string {
|
||||||
|
bindingset[this]
|
||||||
|
SyntheticGlobal() { any() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -256,6 +270,7 @@ module Private {
|
|||||||
TParameterSummaryComponent(ArgumentPosition pos) or
|
TParameterSummaryComponent(ArgumentPosition pos) or
|
||||||
TArgumentSummaryComponent(ParameterPosition pos) or
|
TArgumentSummaryComponent(ParameterPosition pos) or
|
||||||
TReturnSummaryComponent(ReturnKind rk) or
|
TReturnSummaryComponent(ReturnKind rk) or
|
||||||
|
TSyntheticGlobalSummaryComponent(SummaryComponent::SyntheticGlobal sg) or
|
||||||
TWithoutContentSummaryComponent(ContentSet c) or
|
TWithoutContentSummaryComponent(ContentSet c) or
|
||||||
TWithContentSummaryComponent(ContentSet c)
|
TWithContentSummaryComponent(ContentSet c)
|
||||||
|
|
||||||
@@ -563,6 +578,11 @@ module Private {
|
|||||||
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.tail())), rk)
|
s.tail())), rk)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(SummaryComponent::SyntheticGlobal sg |
|
||||||
|
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||||
|
result = getSyntheticGlobalType(sg)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
n = summaryNodeOutputState(c, s) and
|
n = summaryNodeOutputState(c, s) and
|
||||||
@@ -582,6 +602,11 @@ module Private {
|
|||||||
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.tail())), pos)
|
s.tail())), pos)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(SummaryComponent::SyntheticGlobal sg |
|
||||||
|
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||||
|
result = getSyntheticGlobalType(sg)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -692,6 +717,18 @@ module Private {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if there is a jump step from `pred` to `succ`, which is synthesized
|
||||||
|
* from a flow summary.
|
||||||
|
*/
|
||||||
|
predicate summaryJumpStep(Node pred, Node succ) {
|
||||||
|
exists(SummaryComponentStack s |
|
||||||
|
s = SummaryComponentStack::singleton(SummaryComponent::syntheticGlobal(_)) and
|
||||||
|
pred = summaryNodeOutputState(_, s) and
|
||||||
|
succ = summaryNodeInputState(_, s)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
||||||
* synthesized summary node, so in order for values to be cleared at calls
|
* synthesized summary node, so in order for values to be cleared at calls
|
||||||
@@ -871,18 +908,28 @@ module Private {
|
|||||||
AccessPathRange() { relevantSpec(this) }
|
AccessPathRange() { relevantSpec(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if specification component `c` parses as parameter `n`. */
|
/** Holds if specification component `token` parses as parameter `pos`. */
|
||||||
predicate parseParam(AccessPathToken token, ArgumentPosition pos) {
|
predicate parseParam(AccessPathToken token, ArgumentPosition pos) {
|
||||||
token.getName() = "Parameter" and
|
token.getName() = "Parameter" and
|
||||||
pos = parseParamBody(token.getAnArgument())
|
pos = parseParamBody(token.getAnArgument())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if specification component `c` parses as argument `n`. */
|
/** Holds if specification component `token` parses as argument `pos`. */
|
||||||
predicate parseArg(AccessPathToken token, ParameterPosition pos) {
|
predicate parseArg(AccessPathToken token, ParameterPosition pos) {
|
||||||
token.getName() = "Argument" and
|
token.getName() = "Argument" and
|
||||||
pos = parseArgBody(token.getAnArgument())
|
pos = parseArgBody(token.getAnArgument())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Holds if specification component `token` parses as synthetic global `sg`. */
|
||||||
|
predicate parseSynthGlobal(AccessPathToken token, string sg) {
|
||||||
|
token.getName() = "SyntheticGlobal" and
|
||||||
|
sg = token.getAnArgument()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SyntheticGlobalFromAccessPath extends SummaryComponent::SyntheticGlobal {
|
||||||
|
SyntheticGlobalFromAccessPath() { parseSynthGlobal(_, this) }
|
||||||
|
}
|
||||||
|
|
||||||
private SummaryComponent interpretComponent(AccessPathToken token) {
|
private SummaryComponent interpretComponent(AccessPathToken token) {
|
||||||
exists(ParameterPosition pos |
|
exists(ParameterPosition pos |
|
||||||
parseArg(token, pos) and result = SummaryComponent::argument(pos)
|
parseArg(token, pos) and result = SummaryComponent::argument(pos)
|
||||||
@@ -894,6 +941,10 @@ module Private {
|
|||||||
or
|
or
|
||||||
token = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
token = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
||||||
or
|
or
|
||||||
|
exists(string sg |
|
||||||
|
parseSynthGlobal(token, sg) and result = SummaryComponent::syntheticGlobal(sg)
|
||||||
|
)
|
||||||
|
or
|
||||||
result = interpretComponentSpecific(token)
|
result = interpretComponentSpecific(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
|
|||||||
exists(rk)
|
exists(rk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the type of synthetic global `sg`. */
|
||||||
|
DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) {
|
||||||
|
exists(sg) and
|
||||||
|
result instanceof TypeObject
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[provenance]
|
bindingset[provenance]
|
||||||
private boolean isGenerated(string provenance) {
|
private boolean isGenerated(string provenance) {
|
||||||
provenance = "generated" and result = true
|
provenance = "generated" and result = true
|
||||||
|
|||||||
25
java/ql/test/library-tests/dataflow/synth-global/A.java
Normal file
25
java/ql/test/library-tests/dataflow/synth-global/A.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package my.qltest.synth;
|
||||||
|
|
||||||
|
public class A {
|
||||||
|
void storeInArray(String x) { }
|
||||||
|
void storeTaintInArray(String x) { }
|
||||||
|
void storeValue(String x) { }
|
||||||
|
|
||||||
|
String readValue() { return null; }
|
||||||
|
String readArray() { return null; }
|
||||||
|
|
||||||
|
String source(String tag) { return "tainted"; }
|
||||||
|
|
||||||
|
void sink(Object o) { }
|
||||||
|
|
||||||
|
void stores() {
|
||||||
|
storeInArray(source("A"));
|
||||||
|
storeTaintInArray(source("B"));
|
||||||
|
storeValue(source("C"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void reads() {
|
||||||
|
sink(readValue()); // $ hasValueFlow=C
|
||||||
|
sink(readArray()); // $ hasValueFlow=A hasTaintFlow=B hasTaintFlow=C
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
failures
|
||||||
|
invalidModelRow
|
||||||
16
java/ql/test/library-tests/dataflow/synth-global/test.ql
Normal file
16
java/ql/test/library-tests/dataflow/synth-global/test.ql
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import java
|
||||||
|
import TestUtilities.InlineFlowTest
|
||||||
|
import CsvValidation
|
||||||
|
|
||||||
|
class SummaryModelTest extends SummaryModelCsv {
|
||||||
|
override predicate row(string row) {
|
||||||
|
row =
|
||||||
|
[
|
||||||
|
"my.qltest.synth;A;false;storeInArray;(String);;Argument[0];SyntheticGlobal[db1].ArrayElement;value;manual",
|
||||||
|
"my.qltest.synth;A;false;storeTaintInArray;(String);;Argument[0];SyntheticGlobal[db1].ArrayElement;taint;manual",
|
||||||
|
"my.qltest.synth;A;false;storeValue;(String);;Argument[0];SyntheticGlobal[db1];value;manual",
|
||||||
|
"my.qltest.synth;A;false;readValue;();;SyntheticGlobal[db1];ReturnValue;value;manual",
|
||||||
|
"my.qltest.synth;A;false;readArray;();;SyntheticGlobal[db1].ArrayElement;ReturnValue;value;manual",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -453,6 +453,8 @@ predicate jumpStep(Node nodeFrom, Node nodeTo) {
|
|||||||
jumpStepSharedWithTypeTracker(nodeFrom, nodeTo)
|
jumpStepSharedWithTypeTracker(nodeFrom, nodeTo)
|
||||||
or
|
or
|
||||||
jumpStepNotSharedWithTypeTracker(nodeFrom, nodeTo)
|
jumpStepNotSharedWithTypeTracker(nodeFrom, nodeTo)
|
||||||
|
or
|
||||||
|
FlowSummaryImpl::Private::Steps::summaryJumpStep(nodeFrom, nodeTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -61,6 +61,20 @@ module Public {
|
|||||||
|
|
||||||
/** Gets a summary component for a return of kind `rk`. */
|
/** Gets a summary component for a return of kind `rk`. */
|
||||||
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
||||||
|
|
||||||
|
/** Gets a summary component for synthetic global `sg`. */
|
||||||
|
SummaryComponent syntheticGlobal(SyntheticGlobal sg) {
|
||||||
|
result = TSyntheticGlobalSummaryComponent(sg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A synthetic global. This represents some form of global state, which
|
||||||
|
* summaries can read and write individually.
|
||||||
|
*/
|
||||||
|
abstract class SyntheticGlobal extends string {
|
||||||
|
bindingset[this]
|
||||||
|
SyntheticGlobal() { any() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -256,6 +270,7 @@ module Private {
|
|||||||
TParameterSummaryComponent(ArgumentPosition pos) or
|
TParameterSummaryComponent(ArgumentPosition pos) or
|
||||||
TArgumentSummaryComponent(ParameterPosition pos) or
|
TArgumentSummaryComponent(ParameterPosition pos) or
|
||||||
TReturnSummaryComponent(ReturnKind rk) or
|
TReturnSummaryComponent(ReturnKind rk) or
|
||||||
|
TSyntheticGlobalSummaryComponent(SummaryComponent::SyntheticGlobal sg) or
|
||||||
TWithoutContentSummaryComponent(ContentSet c) or
|
TWithoutContentSummaryComponent(ContentSet c) or
|
||||||
TWithContentSummaryComponent(ContentSet c)
|
TWithContentSummaryComponent(ContentSet c)
|
||||||
|
|
||||||
@@ -563,6 +578,11 @@ module Private {
|
|||||||
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.tail())), rk)
|
s.tail())), rk)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(SummaryComponent::SyntheticGlobal sg |
|
||||||
|
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||||
|
result = getSyntheticGlobalType(sg)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
n = summaryNodeOutputState(c, s) and
|
n = summaryNodeOutputState(c, s) and
|
||||||
@@ -582,6 +602,11 @@ module Private {
|
|||||||
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.tail())), pos)
|
s.tail())), pos)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(SummaryComponent::SyntheticGlobal sg |
|
||||||
|
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||||
|
result = getSyntheticGlobalType(sg)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -692,6 +717,18 @@ module Private {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if there is a jump step from `pred` to `succ`, which is synthesized
|
||||||
|
* from a flow summary.
|
||||||
|
*/
|
||||||
|
predicate summaryJumpStep(Node pred, Node succ) {
|
||||||
|
exists(SummaryComponentStack s |
|
||||||
|
s = SummaryComponentStack::singleton(SummaryComponent::syntheticGlobal(_)) and
|
||||||
|
pred = summaryNodeOutputState(_, s) and
|
||||||
|
succ = summaryNodeInputState(_, s)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
||||||
* synthesized summary node, so in order for values to be cleared at calls
|
* synthesized summary node, so in order for values to be cleared at calls
|
||||||
@@ -871,18 +908,28 @@ module Private {
|
|||||||
AccessPathRange() { relevantSpec(this) }
|
AccessPathRange() { relevantSpec(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if specification component `c` parses as parameter `n`. */
|
/** Holds if specification component `token` parses as parameter `pos`. */
|
||||||
predicate parseParam(AccessPathToken token, ArgumentPosition pos) {
|
predicate parseParam(AccessPathToken token, ArgumentPosition pos) {
|
||||||
token.getName() = "Parameter" and
|
token.getName() = "Parameter" and
|
||||||
pos = parseParamBody(token.getAnArgument())
|
pos = parseParamBody(token.getAnArgument())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if specification component `c` parses as argument `n`. */
|
/** Holds if specification component `token` parses as argument `pos`. */
|
||||||
predicate parseArg(AccessPathToken token, ParameterPosition pos) {
|
predicate parseArg(AccessPathToken token, ParameterPosition pos) {
|
||||||
token.getName() = "Argument" and
|
token.getName() = "Argument" and
|
||||||
pos = parseArgBody(token.getAnArgument())
|
pos = parseArgBody(token.getAnArgument())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Holds if specification component `token` parses as synthetic global `sg`. */
|
||||||
|
predicate parseSynthGlobal(AccessPathToken token, string sg) {
|
||||||
|
token.getName() = "SyntheticGlobal" and
|
||||||
|
sg = token.getAnArgument()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SyntheticGlobalFromAccessPath extends SummaryComponent::SyntheticGlobal {
|
||||||
|
SyntheticGlobalFromAccessPath() { parseSynthGlobal(_, this) }
|
||||||
|
}
|
||||||
|
|
||||||
private SummaryComponent interpretComponent(AccessPathToken token) {
|
private SummaryComponent interpretComponent(AccessPathToken token) {
|
||||||
exists(ParameterPosition pos |
|
exists(ParameterPosition pos |
|
||||||
parseArg(token, pos) and result = SummaryComponent::argument(pos)
|
parseArg(token, pos) and result = SummaryComponent::argument(pos)
|
||||||
@@ -894,6 +941,10 @@ module Private {
|
|||||||
or
|
or
|
||||||
token = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
token = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
||||||
or
|
or
|
||||||
|
exists(string sg |
|
||||||
|
parseSynthGlobal(token, sg) and result = SummaryComponent::syntheticGlobal(sg)
|
||||||
|
)
|
||||||
|
or
|
||||||
result = interpretComponentSpecific(token)
|
result = interpretComponentSpecific(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ DataFlowType getCallbackParameterType(DataFlowType t, int i) { any() }
|
|||||||
*/
|
*/
|
||||||
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) { any() }
|
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) { any() }
|
||||||
|
|
||||||
|
/** Gets the type of synthetic global `sg`. */
|
||||||
|
DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) { any() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if an external flow summary exists for `c` with input specification
|
* Holds if an external flow summary exists for `c` with input specification
|
||||||
* `input`, output specification `output`, kind `kind`, and a flag `generated`
|
* `input`, output specification `output`, kind `kind`, and a flag `generated`
|
||||||
|
|||||||
@@ -1003,6 +1003,8 @@ predicate jumpStep(Node pred, Node succ) {
|
|||||||
succ.(SsaDefinitionNode).getDefinition())
|
succ.(SsaDefinitionNode).getDefinition())
|
||||||
or
|
or
|
||||||
succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr()
|
succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr()
|
||||||
|
or
|
||||||
|
FlowSummaryImpl::Private::Steps::summaryJumpStep(pred, succ)
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContentSet getKeywordContent(string name) {
|
private ContentSet getKeywordContent(string name) {
|
||||||
|
|||||||
@@ -61,6 +61,20 @@ module Public {
|
|||||||
|
|
||||||
/** Gets a summary component for a return of kind `rk`. */
|
/** Gets a summary component for a return of kind `rk`. */
|
||||||
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
||||||
|
|
||||||
|
/** Gets a summary component for synthetic global `sg`. */
|
||||||
|
SummaryComponent syntheticGlobal(SyntheticGlobal sg) {
|
||||||
|
result = TSyntheticGlobalSummaryComponent(sg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A synthetic global. This represents some form of global state, which
|
||||||
|
* summaries can read and write individually.
|
||||||
|
*/
|
||||||
|
abstract class SyntheticGlobal extends string {
|
||||||
|
bindingset[this]
|
||||||
|
SyntheticGlobal() { any() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -256,6 +270,7 @@ module Private {
|
|||||||
TParameterSummaryComponent(ArgumentPosition pos) or
|
TParameterSummaryComponent(ArgumentPosition pos) or
|
||||||
TArgumentSummaryComponent(ParameterPosition pos) or
|
TArgumentSummaryComponent(ParameterPosition pos) or
|
||||||
TReturnSummaryComponent(ReturnKind rk) or
|
TReturnSummaryComponent(ReturnKind rk) or
|
||||||
|
TSyntheticGlobalSummaryComponent(SummaryComponent::SyntheticGlobal sg) or
|
||||||
TWithoutContentSummaryComponent(ContentSet c) or
|
TWithoutContentSummaryComponent(ContentSet c) or
|
||||||
TWithContentSummaryComponent(ContentSet c)
|
TWithContentSummaryComponent(ContentSet c)
|
||||||
|
|
||||||
@@ -563,6 +578,11 @@ module Private {
|
|||||||
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.tail())), rk)
|
s.tail())), rk)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(SummaryComponent::SyntheticGlobal sg |
|
||||||
|
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||||
|
result = getSyntheticGlobalType(sg)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
n = summaryNodeOutputState(c, s) and
|
n = summaryNodeOutputState(c, s) and
|
||||||
@@ -582,6 +602,11 @@ module Private {
|
|||||||
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.tail())), pos)
|
s.tail())), pos)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(SummaryComponent::SyntheticGlobal sg |
|
||||||
|
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||||
|
result = getSyntheticGlobalType(sg)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -692,6 +717,18 @@ module Private {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if there is a jump step from `pred` to `succ`, which is synthesized
|
||||||
|
* from a flow summary.
|
||||||
|
*/
|
||||||
|
predicate summaryJumpStep(Node pred, Node succ) {
|
||||||
|
exists(SummaryComponentStack s |
|
||||||
|
s = SummaryComponentStack::singleton(SummaryComponent::syntheticGlobal(_)) and
|
||||||
|
pred = summaryNodeOutputState(_, s) and
|
||||||
|
succ = summaryNodeInputState(_, s)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
||||||
* synthesized summary node, so in order for values to be cleared at calls
|
* synthesized summary node, so in order for values to be cleared at calls
|
||||||
@@ -871,18 +908,28 @@ module Private {
|
|||||||
AccessPathRange() { relevantSpec(this) }
|
AccessPathRange() { relevantSpec(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if specification component `c` parses as parameter `n`. */
|
/** Holds if specification component `token` parses as parameter `pos`. */
|
||||||
predicate parseParam(AccessPathToken token, ArgumentPosition pos) {
|
predicate parseParam(AccessPathToken token, ArgumentPosition pos) {
|
||||||
token.getName() = "Parameter" and
|
token.getName() = "Parameter" and
|
||||||
pos = parseParamBody(token.getAnArgument())
|
pos = parseParamBody(token.getAnArgument())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if specification component `c` parses as argument `n`. */
|
/** Holds if specification component `token` parses as argument `pos`. */
|
||||||
predicate parseArg(AccessPathToken token, ParameterPosition pos) {
|
predicate parseArg(AccessPathToken token, ParameterPosition pos) {
|
||||||
token.getName() = "Argument" and
|
token.getName() = "Argument" and
|
||||||
pos = parseArgBody(token.getAnArgument())
|
pos = parseArgBody(token.getAnArgument())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Holds if specification component `token` parses as synthetic global `sg`. */
|
||||||
|
predicate parseSynthGlobal(AccessPathToken token, string sg) {
|
||||||
|
token.getName() = "SyntheticGlobal" and
|
||||||
|
sg = token.getAnArgument()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SyntheticGlobalFromAccessPath extends SummaryComponent::SyntheticGlobal {
|
||||||
|
SyntheticGlobalFromAccessPath() { parseSynthGlobal(_, this) }
|
||||||
|
}
|
||||||
|
|
||||||
private SummaryComponent interpretComponent(AccessPathToken token) {
|
private SummaryComponent interpretComponent(AccessPathToken token) {
|
||||||
exists(ParameterPosition pos |
|
exists(ParameterPosition pos |
|
||||||
parseArg(token, pos) and result = SummaryComponent::argument(pos)
|
parseArg(token, pos) and result = SummaryComponent::argument(pos)
|
||||||
@@ -894,6 +941,10 @@ module Private {
|
|||||||
or
|
or
|
||||||
token = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
token = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
||||||
or
|
or
|
||||||
|
exists(string sg |
|
||||||
|
parseSynthGlobal(token, sg) and result = SummaryComponent::syntheticGlobal(sg)
|
||||||
|
)
|
||||||
|
or
|
||||||
result = interpretComponentSpecific(token)
|
result = interpretComponentSpecific(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) { an
|
|||||||
*/
|
*/
|
||||||
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) { any() }
|
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) { any() }
|
||||||
|
|
||||||
|
/** Gets the type of synthetic global `sg`. */
|
||||||
|
DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) { any() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if an external flow summary exists for `c` with input specification
|
* Holds if an external flow summary exists for `c` with input specification
|
||||||
* `input`, output specification `output`, kind `kind`, and a flag `generated`
|
* `input`, output specification `output`, kind `kind`, and a flag `generated`
|
||||||
|
|||||||
@@ -486,7 +486,9 @@ private module OutNodes {
|
|||||||
|
|
||||||
import OutNodes
|
import OutNodes
|
||||||
|
|
||||||
predicate jumpStep(Node pred, Node succ) { none() }
|
predicate jumpStep(Node pred, Node succ) {
|
||||||
|
FlowSummaryImpl::Private::Steps::summaryJumpStep(pred, succ)
|
||||||
|
}
|
||||||
|
|
||||||
predicate storeStep(Node node1, ContentSet c, Node node2) {
|
predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||||
exists(MemberRefExpr ref, AssignExpr assign |
|
exists(MemberRefExpr ref, AssignExpr assign |
|
||||||
|
|||||||
@@ -61,6 +61,20 @@ module Public {
|
|||||||
|
|
||||||
/** Gets a summary component for a return of kind `rk`. */
|
/** Gets a summary component for a return of kind `rk`. */
|
||||||
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
||||||
|
|
||||||
|
/** Gets a summary component for synthetic global `sg`. */
|
||||||
|
SummaryComponent syntheticGlobal(SyntheticGlobal sg) {
|
||||||
|
result = TSyntheticGlobalSummaryComponent(sg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A synthetic global. This represents some form of global state, which
|
||||||
|
* summaries can read and write individually.
|
||||||
|
*/
|
||||||
|
abstract class SyntheticGlobal extends string {
|
||||||
|
bindingset[this]
|
||||||
|
SyntheticGlobal() { any() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -256,6 +270,7 @@ module Private {
|
|||||||
TParameterSummaryComponent(ArgumentPosition pos) or
|
TParameterSummaryComponent(ArgumentPosition pos) or
|
||||||
TArgumentSummaryComponent(ParameterPosition pos) or
|
TArgumentSummaryComponent(ParameterPosition pos) or
|
||||||
TReturnSummaryComponent(ReturnKind rk) or
|
TReturnSummaryComponent(ReturnKind rk) or
|
||||||
|
TSyntheticGlobalSummaryComponent(SummaryComponent::SyntheticGlobal sg) or
|
||||||
TWithoutContentSummaryComponent(ContentSet c) or
|
TWithoutContentSummaryComponent(ContentSet c) or
|
||||||
TWithContentSummaryComponent(ContentSet c)
|
TWithContentSummaryComponent(ContentSet c)
|
||||||
|
|
||||||
@@ -563,6 +578,11 @@ module Private {
|
|||||||
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.tail())), rk)
|
s.tail())), rk)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(SummaryComponent::SyntheticGlobal sg |
|
||||||
|
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||||
|
result = getSyntheticGlobalType(sg)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
n = summaryNodeOutputState(c, s) and
|
n = summaryNodeOutputState(c, s) and
|
||||||
@@ -582,6 +602,11 @@ module Private {
|
|||||||
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.tail())), pos)
|
s.tail())), pos)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(SummaryComponent::SyntheticGlobal sg |
|
||||||
|
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||||
|
result = getSyntheticGlobalType(sg)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -692,6 +717,18 @@ module Private {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if there is a jump step from `pred` to `succ`, which is synthesized
|
||||||
|
* from a flow summary.
|
||||||
|
*/
|
||||||
|
predicate summaryJumpStep(Node pred, Node succ) {
|
||||||
|
exists(SummaryComponentStack s |
|
||||||
|
s = SummaryComponentStack::singleton(SummaryComponent::syntheticGlobal(_)) and
|
||||||
|
pred = summaryNodeOutputState(_, s) and
|
||||||
|
succ = summaryNodeInputState(_, s)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
* Holds if values stored inside content `c` are cleared at `n`. `n` is a
|
||||||
* synthesized summary node, so in order for values to be cleared at calls
|
* synthesized summary node, so in order for values to be cleared at calls
|
||||||
@@ -871,18 +908,28 @@ module Private {
|
|||||||
AccessPathRange() { relevantSpec(this) }
|
AccessPathRange() { relevantSpec(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if specification component `c` parses as parameter `n`. */
|
/** Holds if specification component `token` parses as parameter `pos`. */
|
||||||
predicate parseParam(AccessPathToken token, ArgumentPosition pos) {
|
predicate parseParam(AccessPathToken token, ArgumentPosition pos) {
|
||||||
token.getName() = "Parameter" and
|
token.getName() = "Parameter" and
|
||||||
pos = parseParamBody(token.getAnArgument())
|
pos = parseParamBody(token.getAnArgument())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if specification component `c` parses as argument `n`. */
|
/** Holds if specification component `token` parses as argument `pos`. */
|
||||||
predicate parseArg(AccessPathToken token, ParameterPosition pos) {
|
predicate parseArg(AccessPathToken token, ParameterPosition pos) {
|
||||||
token.getName() = "Argument" and
|
token.getName() = "Argument" and
|
||||||
pos = parseArgBody(token.getAnArgument())
|
pos = parseArgBody(token.getAnArgument())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Holds if specification component `token` parses as synthetic global `sg`. */
|
||||||
|
predicate parseSynthGlobal(AccessPathToken token, string sg) {
|
||||||
|
token.getName() = "SyntheticGlobal" and
|
||||||
|
sg = token.getAnArgument()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SyntheticGlobalFromAccessPath extends SummaryComponent::SyntheticGlobal {
|
||||||
|
SyntheticGlobalFromAccessPath() { parseSynthGlobal(_, this) }
|
||||||
|
}
|
||||||
|
|
||||||
private SummaryComponent interpretComponent(AccessPathToken token) {
|
private SummaryComponent interpretComponent(AccessPathToken token) {
|
||||||
exists(ParameterPosition pos |
|
exists(ParameterPosition pos |
|
||||||
parseArg(token, pos) and result = SummaryComponent::argument(pos)
|
parseArg(token, pos) and result = SummaryComponent::argument(pos)
|
||||||
@@ -894,6 +941,10 @@ module Private {
|
|||||||
or
|
or
|
||||||
token = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
token = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
||||||
or
|
or
|
||||||
|
exists(string sg |
|
||||||
|
parseSynthGlobal(token, sg) and result = SummaryComponent::syntheticGlobal(sg)
|
||||||
|
)
|
||||||
|
or
|
||||||
result = interpretComponentSpecific(token)
|
result = interpretComponentSpecific(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
|
|||||||
any() // TODO once we have type pruning
|
any() // TODO once we have type pruning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the type of synthetic global `sg`. */
|
||||||
|
DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) { any() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if an external flow summary exists for `c` with input specification
|
* Holds if an external flow summary exists for `c` with input specification
|
||||||
* `input`, output specification `output`, kind `kind`, and a flag `generated`
|
* `input`, output specification `output`, kind `kind`, and a flag `generated`
|
||||||
|
|||||||
Reference in New Issue
Block a user