-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Data flow: Prevent quadratic blowup in Stage6Param::localStep
#17739
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -2596,31 +2596,27 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> { | |||
callEdgeReturn(call, c, _, _, _, _, _) | ||||
} | ||||
|
||||
/** Provides the input to `LocalFlowBigStep`. */ | ||||
signature module LocalFlowBigStepInputSig { | ||||
bindingset[node1, state1] | ||||
bindingset[node2, state2] | ||||
predicate localStep( | ||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, | ||||
DataFlowType t, LocalCallContext lcc, string label | ||||
); | ||||
} | ||||
/** Holds if `node1` can step to `node2` in one or more local steps. */ | ||||
bindingset[node1, state1] | ||||
bindingset[node2, state2] | ||||
signature predicate localStepSig( | ||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, | ||||
DataFlowType t, LocalCallContext lcc, string label | ||||
); | ||||
|
||||
/** | ||||
* Provides a big-step relation for local flow steps. | ||||
* | ||||
* The big-step releation is based on the `localStep` relation from the | ||||
* input module, restricted to nodes that are forwards and backwards | ||||
* reachable in this stage. | ||||
* The big-step releation is based on the `localStepInput` relation, | ||||
* restricted to nodes that are forwards and backwards reachable in | ||||
* this stage. | ||||
*/ | ||||
additional module LocalFlowBigStep<LocalFlowBigStepInputSig Input> { | ||||
final private class NodeExFinal = NodeEx; | ||||
|
||||
additional module LocalFlowBigStep<localStepSig/8 localStepInput> { | ||||
/** | ||||
* A node where some checking is required, and hence the big-step relation | ||||
* is not allowed to step over. | ||||
*/ | ||||
private class FlowCheckNode extends NodeExFinal { | ||||
private class FlowCheckNode extends NodeEx { | ||||
FlowCheckNode() { | ||||
revFlow(this, _, _) and | ||||
( | ||||
|
@@ -2640,7 +2636,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> { | |||
exists(ApNil nil | | ||||
revFlow(node1, state1, pragma[only_bind_into](nil)) and | ||||
revFlow(node2, state2, pragma[only_bind_into](nil)) and | ||||
Input::localStep(node1, state1, node2, state2, false, t, lcc, label) and | ||||
localStepInput(node1, state1, node2, state2, false, t, lcc, label) and | ||||
state1 != state2 | ||||
) | ||||
} | ||||
|
@@ -2734,7 +2730,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> { | |||
not inBarrier(node2, state) and | ||||
not outBarrier(node1, state) and | ||||
exists(NodeEx mid, boolean preservesValue2, DataFlowType t2, string label2, Ap ap | | ||||
Input::localStep(mid, state, node2, state, preservesValue2, t2, cc, label2) and | ||||
localStepInput(mid, state, node2, state, preservesValue2, t2, cc, label2) and | ||||
revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](ap)) and | ||||
not outBarrier(mid, state) and | ||||
(preservesValue = true or ap instanceof ApNil) | ||||
|
@@ -2769,6 +2765,33 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> { | |||
exists(Ap ap | | ||||
localFlowStepPlus(node1, state1, node2, preservesValue, t, callContext, label) and | ||||
localFlowExit(node2, state1, ap) and | ||||
state1 = state2 and | ||||
node1 != node2 | ||||
geoffw0 marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While the addition here might well preserve semantics relative to main, then I don't think it matches what we want and the semantics prior to the introduction of the big-step recomputation. It's an obscure corner-case, but there might be a sequence of steps around a loop that returns to the origin including a taint step that affects the tracked type. In the first application of big-step TC then such a loop is preserved as a step, but a second application removes it, which seems wrong. So I think we should drop this constraint here.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Quite possibly. It's certainly corner-case, though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #17877 shows the effect of allowing reflexive big steps; I'm not convinced that we want to add it, DCA on this PR also showed no alert changes (the ones for C# are wobble). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, let's go with the PR as-is, then. |
||||
| | ||||
preservesValue = true or ap instanceof ApNil | ||||
) | ||||
or | ||||
additionalLocalStateStep(node1, state1, node2, state2, t, callContext, label) and | ||||
preservesValue = false | ||||
} | ||||
|
||||
/** | ||||
* Holds if `node1` can step to `node2` in one or more local steps and this | ||||
* path can occur as a maximal subsequence of local steps in a dataflow path. | ||||
* | ||||
* This predicate should be used when `localStepInput` is already a big-step | ||||
* relation, which will do the same as `localFlowBigStep`, but avoids potential | ||||
* worst-case quadratic complexity. | ||||
*/ | ||||
pragma[nomagic] | ||||
predicate localFlowBigStepTc( | ||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, | ||||
DataFlowType t, LocalCallContext callContext, string label | ||||
) { | ||||
exists(Ap ap | | ||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](ap)) and | ||||
localStepInput(node1, state1, node2, state2, preservesValue, t, callContext, label) and | ||||
localFlowExit(node2, pragma[only_bind_into](state2), pragma[only_bind_into](ap)) and | ||||
geoffw0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
state1 = state2 | ||||
| | ||||
preservesValue = true or ap instanceof ApNil | ||||
|
@@ -3790,27 +3813,25 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> { | |||
import CallContextSensitivity<CallContextSensitivityInput> | ||||
import NoLocalCallContext | ||||
|
||||
private module BigStepInput implements PrevStage::LocalFlowBigStepInputSig { | ||||
bindingset[node1, state1] | ||||
bindingset[node2, state2] | ||||
predicate localStep( | ||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, | ||||
DataFlowType t, LocalCallContext lcc, string label | ||||
) { | ||||
localStepNodeCand1(node1, node2, preservesValue, t, lcc, label) and | ||||
state1 = state2 | ||||
or | ||||
localStateStepNodeCand1(node1, state1, node2, state2, t, lcc, label) and | ||||
preservesValue = false | ||||
} | ||||
bindingset[node1, state1] | ||||
bindingset[node2, state2] | ||||
private predicate localStepInput( | ||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, | ||||
DataFlowType t, LocalCallContext lcc, string label | ||||
) { | ||||
localStepNodeCand1(node1, node2, preservesValue, t, lcc, label) and | ||||
state1 = state2 | ||||
or | ||||
localStateStepNodeCand1(node1, state1, node2, state2, t, lcc, label) and | ||||
preservesValue = false | ||||
} | ||||
|
||||
additional predicate localFlowBigStep( | ||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, | ||||
DataFlowType t, LocalCallContext lcc, string label | ||||
) { | ||||
PrevStage::LocalFlowBigStep<BigStepInput>::localFlowBigStep(node1, state1, node2, state2, | ||||
preservesValue, t, lcc, label) | ||||
PrevStage::LocalFlowBigStep<localStepInput/8>::localFlowBigStep(node1, state1, node2, | ||||
state2, preservesValue, t, lcc, label) | ||||
} | ||||
|
||||
bindingset[node1, state1] | ||||
|
@@ -4205,14 +4226,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> { | |||
import CallContextSensitivity<CallContextSensitivityInput> | ||||
import LocalCallContext | ||||
|
||||
predicate localStep( | ||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, | ||||
Typ t, LocalCc lcc, string label | ||||
) { | ||||
Stage3Param::localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc, label) and | ||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and | ||||
PrevStage::revFlow(node2, pragma[only_bind_into](state2), _) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not lost, since it's part of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll take your word for it! |
||||
} | ||||
predicate localStep = | ||||
PrevStage::LocalFlowBigStep<Stage3Param::localFlowBigStep/8>::localFlowBigStepTc/8; | ||||
|
||||
bindingset[node, state, t0, ap] | ||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { | ||||
|
@@ -4410,18 +4425,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> { | |||
import CallContextSensitivity<CallContextSensitivityInput> | ||||
import LocalCallContext | ||||
|
||||
private module BigStepInput implements PrevStage::LocalFlowBigStepInputSig { | ||||
predicate localStep( | ||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, | ||||
DataFlowType t, LocalCallContext lcc, string label | ||||
) { | ||||
Stage3Param::localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc, label) and | ||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and | ||||
PrevStage::revFlow(node2, pragma[only_bind_into](state2), _) | ||||
} | ||||
} | ||||
|
||||
predicate localStep = PrevStage::LocalFlowBigStep<BigStepInput>::localFlowBigStep/8; | ||||
predicate localStep = | ||||
PrevStage::LocalFlowBigStep<Stage5Param::localStep/8>::localFlowBigStepTc/8; | ||||
|
||||
bindingset[node, state, t0, ap] | ||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.