VariableCapture: Replace phi-read reference with SSA data flow integration module.

This commit is contained in:
Anders Schack-Mulligen
2025-03-27 11:02:46 +01:00
parent e8e9403b4c
commit ca6444ce98

View File

@@ -699,6 +699,7 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
class SourceVariable = CaptureContainer;
predicate variableWrite(BasicBlock bb, int i, SourceVariable cc, boolean certain) {
Cached::ref() and
(
exists(CapturedVariable v | cc = TVariable(v) and captureWrite(v, bb, i, true, _))
or
@@ -721,23 +722,55 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
private module CaptureSsa = Ssa::Make<Location, CaptureSsaInput>;
private newtype TClosureNode =
TSynthRead(CapturedVariable v, BasicBlock bb, int i, Boolean isPost) {
synthRead(v, bb, i, _, _)
} or
TSynthThisQualifier(BasicBlock bb, int i, Boolean isPost) { synthThisQualifier(bb, i) } or
TSynthPhi(CaptureSsa::DefinitionExt phi) {
phi instanceof CaptureSsa::PhiNode or phi instanceof CaptureSsa::PhiReadNode
} or
TExprNode(Expr expr, Boolean isPost) {
expr instanceof VariableRead
or
synthRead(_, _, _, _, expr)
} or
TParamNode(CapturedParameter p) or
TThisParamNode(Callable c) { captureAccess(_, c) } or
TMallocNode(ClosureExpr ce) { hasConstructorCapture(ce, _) } or
TVariableWriteSourceNode(VariableWrite write)
private module DataFlowIntegrationInput implements CaptureSsa::DataFlowIntegrationInputSig {
private import codeql.util.Void
class Expr instanceof Input::ControlFlowNode {
string toString() { result = super.toString() }
predicate hasCfgNode(BasicBlock bb, int i) { bb.getNode(i) = this }
}
class Guard extends Void {
predicate controlsBranchEdge(BasicBlock bb1, BasicBlock bb2, boolean branch) { none() }
}
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock bb, boolean branch) { none() }
predicate includeWriteDefsInFlowStep() { none() }
predicate supportBarrierGuardsOnPhiEdges() { none() }
}
private module SsaFlow = CaptureSsa::DataFlowIntegration<DataFlowIntegrationInput>;
cached
private module Cached {
cached
predicate ref() { any() }
cached
predicate backref() { localFlowStep(_, _) implies any() }
cached
newtype TClosureNode =
TSynthRead(CapturedVariable v, BasicBlock bb, int i, Boolean isPost) {
synthRead(v, bb, i, _, _)
} or
TSynthThisQualifier(BasicBlock bb, int i, Boolean isPost) { synthThisQualifier(bb, i) } or
TSynthSsa(SsaFlow::SsaNode n) or
TExprNode(Expr expr, Boolean isPost) {
expr instanceof VariableRead
or
synthRead(_, _, _, _, expr)
} or
TParamNode(CapturedParameter p) or
TThisParamNode(Callable c) { captureAccess(_, c) } or
TMallocNode(ClosureExpr ce) { hasConstructorCapture(ce, _) } or
TVariableWriteSourceNode(VariableWrite write)
}
private import Cached
class ClosureNode extends TClosureNode {
/** Gets a textual representation of this node. */
@@ -746,11 +779,7 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
or
result = "this" and this = TSynthThisQualifier(_, _, _)
or
exists(CaptureSsa::DefinitionExt phi, CaptureContainer cc |
this = TSynthPhi(phi) and
phi.definesAt(cc, _, _, _) and
result = "phi(" + cc.toString() + ")"
)
exists(SsaFlow::SsaNode n | this = TSynthSsa(n) and result = n.toString())
or
exists(Expr expr, boolean isPost | this = TExprNode(expr, isPost) |
isPost = false and result = expr.toString()
@@ -784,9 +813,7 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
captureWrite(_, bb, i, false, any(VariableWrite vw | result = vw.getLocation()))
)
or
exists(CaptureSsa::DefinitionExt phi, BasicBlock bb |
this = TSynthPhi(phi) and phi.definesAt(_, bb, _, _) and result = bb.getLocation()
)
exists(SsaFlow::SsaNode n | this = TSynthSsa(n) and result = n.getLocation())
or
exists(Expr expr | this = TExprNode(expr, _) and result = expr.getLocation())
or
@@ -802,7 +829,7 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
}
}
private class TSynthesizedCaptureNode = TSynthRead or TSynthThisQualifier or TSynthPhi;
private class TSynthesizedCaptureNode = TSynthRead or TSynthThisQualifier or TSynthSsa;
class SynthesizedCaptureNode extends ClosureNode, TSynthesizedCaptureNode {
BasicBlock getBasicBlock() {
@@ -810,9 +837,7 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
or
this = TSynthThisQualifier(result, _, _)
or
exists(CaptureSsa::DefinitionExt phi |
this = TSynthPhi(phi) and phi.definesAt(_, result, _, _)
)
exists(SsaFlow::SsaNode n | this = TSynthSsa(n) and n.getBasicBlock() = result)
}
Callable getEnclosingCallable() { result = this.getBasicBlock().getEnclosingCallable() }
@@ -820,17 +845,13 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
predicate isVariableAccess(CapturedVariable v) {
this = TSynthRead(v, _, _, _)
or
exists(CaptureSsa::DefinitionExt phi |
this = TSynthPhi(phi) and phi.definesAt(TVariable(v), _, _, _)
)
exists(SsaFlow::SsaNode n | this = TSynthSsa(n) and n.getSourceVariable() = TVariable(v))
}
predicate isInstanceAccess() {
this instanceof TSynthThisQualifier
or
exists(CaptureSsa::DefinitionExt phi |
this = TSynthPhi(phi) and phi.definesAt(TThis(_), _, _, _)
)
exists(SsaFlow::SsaNode n | this = TSynthSsa(n) and n.getSourceVariable() = TThis(_))
}
}
@@ -872,18 +893,7 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
)
}
private predicate step(CaptureContainer cc, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
CaptureSsa::adjacentDefReadExt(_, cc, bb1, i1, bb2, i2)
}
private predicate stepToPhi(CaptureContainer cc, BasicBlock bb, int i, TSynthPhi phi) {
exists(CaptureSsa::DefinitionExt next |
CaptureSsa::lastRefRedefExt(_, cc, bb, i, next) and
phi = TSynthPhi(next)
)
}
private predicate ssaAccessAt(
private predicate ssaReadAt(
ClosureNode n, CaptureContainer cc, boolean isPost, BasicBlock bb, int i
) {
exists(CapturedVariable v |
@@ -894,49 +904,57 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
or
n = TSynthThisQualifier(bb, i, isPost) and cc = TThis(bb.getEnclosingCallable())
or
exists(CaptureSsa::DefinitionExt phi |
n = TSynthPhi(phi) and phi.definesAt(cc, bb, i, _) and isPost = false
)
or
exists(VariableRead vr, CapturedVariable v |
captureRead(v, bb, i, true, vr) and
n = TExprNode(vr, isPost) and
cc = TVariable(v)
)
or
}
private predicate ssaWriteAt(ClosureNode n, CaptureContainer cc, BasicBlock bb, int i) {
exists(VariableWrite vw, CapturedVariable v |
captureWrite(v, bb, i, true, vw) and
n = TVariableWriteSourceNode(vw) and
isPost = false and
cc = TVariable(v)
)
or
exists(CapturedParameter p |
entryDef(cc, bb, i) and
cc = TVariable(p) and
n = TParamNode(p) and
isPost = false
n = TParamNode(p)
)
or
exists(Callable c |
entryDef(cc, bb, i) and
cc = TThis(c) and
n = TThisParamNode(c) and
isPost = false
n = TThisParamNode(c)
)
}
predicate localFlowStep(ClosureNode node1, ClosureNode node2) {
exists(CaptureContainer cc, BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
step(cc, bb1, i1, bb2, i2) and
ssaAccessAt(node1, pragma[only_bind_into](cc), _, bb1, i1) and
ssaAccessAt(node2, pragma[only_bind_into](cc), false, bb2, i2)
bindingset[result, cc]
pragma[inline_late]
private SsaFlow::Node asNode(CaptureContainer cc, ClosureNode n) {
n = TSynthSsa(result)
or
exists(BasicBlock bb, int i |
result.(SsaFlow::ExprNode).getExpr().hasCfgNode(bb, i) and
ssaReadAt(n, cc, false, bb, i)
)
or
exists(CaptureContainer cc, BasicBlock bb, int i |
stepToPhi(cc, bb, i, node2) and
ssaAccessAt(node1, cc, _, bb, i)
exists(BasicBlock bb, int i |
result.(SsaFlow::ExprPostUpdateNode).getExpr().hasCfgNode(bb, i) and
ssaReadAt(n, cc, true, bb, i)
)
or
exists(BasicBlock bb, int i |
result.(SsaFlow::WriteDefSourceNode).getDefinition().definesAt(cc, bb, i) and
ssaWriteAt(n, cc, bb, i)
)
}
cached
predicate localFlowStep(ClosureNode n1, ClosureNode n2) {
exists(CaptureContainer cc | SsaFlow::localFlowStep(cc, asNode(cc, n1), asNode(cc, n2), _))
}
private predicate storeStepClosure(