Languages: Adapt to api changes.

This commit is contained in:
Anders Schack-Mulligen
2025-08-19 10:34:06 +02:00
parent e53b22dfa7
commit f459ddc40a
34 changed files with 454 additions and 368 deletions

View File

@@ -4,7 +4,7 @@ private import semmle.javascript.dataflow.internal.VariableOrThis
private import codeql.dataflow.VariableCapture
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
module VariableCaptureConfig implements InputSig<js::Location> {
module VariableCaptureConfig implements InputSig<js::Location, js::Cfg::BasicBlock> {
private js::Function getLambdaFromVariable(js::LocalVariable variable) {
result.getVariable() = variable
or
@@ -106,20 +106,8 @@ module VariableCaptureConfig implements InputSig<js::Location> {
)
}
class ControlFlowNode = js::ControlFlowNode;
final private class JsBasicBlock = js::BasicBlock;
class BasicBlock extends JsBasicBlock {
Callable getEnclosingCallable() { result = this.getContainer().getFunctionBoundary() }
BasicBlock getASuccessor() { result = super.getASuccessor() }
BasicBlock getImmediateDominator() { result = super.getImmediateDominator() }
predicate inDominanceFrontier(BasicBlock df) {
df.(js::ReachableJoinBlock).inDominanceFrontierOf(this)
}
Callable basicBlockGetEnclosingCallable(js::Cfg::BasicBlock bb) {
result = bb.getContainer().getFunctionBoundary()
}
class Callable extends js::StmtContainer {
@@ -135,7 +123,7 @@ module VariableCaptureConfig implements InputSig<js::Location> {
class Expr extends js::AST::ValueNode {
/** Holds if the `i`th node of basic block `bb` evaluates this expression. */
predicate hasCfgNode(BasicBlock bb, int i) {
predicate hasCfgNode(js::Cfg::BasicBlock bb, int i) {
// Note: this is overridden for FunctionDeclStmt
bb.getNode(i) = this
}
@@ -180,7 +168,7 @@ module VariableCaptureConfig implements InputSig<js::Location> {
js::Location getLocation() { none() } // Overridden in subclass
predicate hasCfgNode(BasicBlock bb, int i) { none() } // Overridden in subclass
predicate hasCfgNode(js::Cfg::BasicBlock bb, int i) { none() } // Overridden in subclass
// note: langauge-specific
js::DataFlow::Node getSource() { none() } // Overridden in subclass
@@ -217,7 +205,7 @@ module VariableCaptureConfig implements InputSig<js::Location> {
}
/** Holds if the `i`th node of basic block `bb` evaluates this expression. */
override predicate hasCfgNode(BasicBlock bb, int i) {
override predicate hasCfgNode(js::Cfg::BasicBlock bb, int i) {
bb.getNode(i) = this.getCfgNodeOverride()
or
not exists(this.getCfgNodeOverride()) and
@@ -236,7 +224,7 @@ module VariableCaptureConfig implements InputSig<js::Location> {
override CapturedVariable getVariable() { result = variable }
override predicate hasCfgNode(BasicBlock bb, int i) {
override predicate hasCfgNode(js::Cfg::BasicBlock bb, int i) {
// 'i' would normally be bound to 0, but we lower it to -1 so FunctionDeclStmts can be evaluated
// at index 0.
any(js::SsaImplicitInit def).definesAt(bb, _, variable.asLocalVariable()) and i = -1
@@ -244,11 +232,9 @@ module VariableCaptureConfig implements InputSig<js::Location> {
bb.(js::EntryBasicBlock).getContainer() = variable.asThisContainer() and i = -1
}
}
predicate entryBlock(BasicBlock bb) { bb instanceof js::EntryBasicBlock }
}
module VariableCaptureOutput = Flow<js::Location, VariableCaptureConfig>;
module VariableCaptureOutput = Flow<js::Location, js::Cfg, VariableCaptureConfig>;
js::DataFlow::Node getNodeFromClosureNode(VariableCaptureOutput::ClosureNode node) {
result = TValueNode(node.(VariableCaptureOutput::ExprNode).getExpr())
@@ -294,9 +280,9 @@ private module Debug {
relevantContainer(node1.getContainer())
}
predicate readBB(VariableRead read, BasicBlock bb, int i) { read.hasCfgNode(bb, i) }
predicate readBB(VariableRead read, js::Cfg::BasicBlock bb, int i) { read.hasCfgNode(bb, i) }
predicate writeBB(VariableWrite write, BasicBlock bb, int i) { write.hasCfgNode(bb, i) }
predicate writeBB(VariableWrite write, js::Cfg::BasicBlock bb, int i) { write.hasCfgNode(bb, i) }
int captureDegree(js::Function fun) {
result = strictcount(CapturedVariable v | captures(fun, v))

View File

@@ -9,21 +9,7 @@ private import codeql.ssa.Ssa
private import semmle.javascript.internal.BasicBlockInternal as BasicBlockInternal
private import semmle.javascript.dataflow.internal.VariableOrThis
module SsaConfig implements InputSig<js::Location> {
class ControlFlowNode = js::ControlFlowNode;
final private class JsBasicBlock = js::BasicBlock;
class BasicBlock extends JsBasicBlock {
BasicBlock getASuccessor() { result = super.getASuccessor() }
BasicBlock getImmediateDominator() { result = super.getImmediateDominator() }
predicate inDominanceFrontier(BasicBlock df) {
df.(js::ReachableJoinBlock).inDominanceFrontierOf(this)
}
}
module SsaConfig implements InputSig<js::Location, js::Cfg::BasicBlock> {
class SourceVariable extends LocalVariableOrThis {
SourceVariable() { not this.isCaptured() }
}
@@ -33,7 +19,7 @@ module SsaConfig implements InputSig<js::Location> {
result.getContainer() = container
}
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
predicate variableWrite(js::Cfg::BasicBlock bb, int i, SourceVariable v, boolean certain) {
certain = true and
(
bb.defAt(i, v.asLocalVariable(), _)
@@ -44,7 +30,7 @@ module SsaConfig implements InputSig<js::Location> {
)
}
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
predicate variableRead(js::Cfg::BasicBlock bb, int i, SourceVariable v, boolean certain) {
bb.useAt(i, v.asLocalVariable(), _) and certain = true
or
certain = true and
@@ -52,7 +38,7 @@ module SsaConfig implements InputSig<js::Location> {
}
}
import Make<js::Location, SsaConfig>
import Make<js::Location, js::Cfg, SsaConfig>
module SsaDataflowInput implements DataFlowIntegrationInputSig {
private import codeql.util.Boolean
@@ -60,7 +46,7 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig {
class Expr extends js::ControlFlowNode {
Expr() { this = any(SsaConfig::SourceVariable v).getAUse() }
predicate hasCfgNode(SsaConfig::BasicBlock bb, int i) { this = bb.getNode(i) }
predicate hasCfgNode(js::Cfg::BasicBlock bb, int i) { this = bb.getNode(i) }
}
predicate ssaDefHasSource(WriteDefinition def) {
@@ -87,9 +73,7 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig {
* Holds if the evaluation of this guard to `branch` corresponds to the edge
* from `bb1` to `bb2`.
*/
predicate hasValueBranchEdge(
SsaConfig::BasicBlock bb1, SsaConfig::BasicBlock bb2, GuardValue branch
) {
predicate hasValueBranchEdge(js::Cfg::BasicBlock bb1, js::Cfg::BasicBlock bb2, GuardValue branch) {
exists(js::ConditionGuardNode g |
g.getTest() = this and
bb1 = this.getBasicBlock() and
@@ -104,14 +88,14 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig {
* `bb1` to `bb2` implies that this guard evaluated to `branch`.
*/
predicate valueControlsBranchEdge(
SsaConfig::BasicBlock bb1, SsaConfig::BasicBlock bb2, GuardValue branch
js::Cfg::BasicBlock bb1, js::Cfg::BasicBlock bb2, GuardValue branch
) {
this.hasValueBranchEdge(bb1, bb2, branch)
}
}
pragma[inline]
predicate guardDirectlyControlsBlock(Guard guard, SsaConfig::BasicBlock bb, GuardValue branch) {
predicate guardDirectlyControlsBlock(Guard guard, js::Cfg::BasicBlock bb, GuardValue branch) {
exists(js::ConditionGuardNode g |
g.getTest() = guard and
g.dominates(bb) and

View File

@@ -6,6 +6,7 @@
import javascript
private import semmle.javascript.internal.StmtContainers
private import semmle.javascript.internal.CachedStages
private import codeql.controlflow.BasicBlock as BB
/**
* Holds if `nd` starts a new basic block.
@@ -366,4 +367,48 @@ module Public {
)
}
}
final private class FinalBasicBlock = BasicBlock;
module Cfg implements BB::CfgSig<Location> {
private import javascript as Js
private import codeql.util.Unit
class ControlFlowNode = Js::ControlFlowNode;
class SuccessorType = Unit;
class BasicBlock extends FinalBasicBlock {
BasicBlock getASuccessor() { result = super.getASuccessor() }
BasicBlock getASuccessor(SuccessorType t) { result = super.getASuccessor() and exists(t) }
predicate strictlyDominates(BasicBlock bb) {
this.(ReachableBasicBlock).strictlyDominates(bb)
}
predicate dominates(BasicBlock bb) { this.(ReachableBasicBlock).dominates(bb) }
predicate inDominanceFrontier(BasicBlock df) {
df.(ReachableJoinBlock).inDominanceFrontierOf(this)
}
BasicBlock getImmediateDominator() { result = super.getImmediateDominator() }
predicate strictlyPostDominates(BasicBlock bb) {
this.(ReachableBasicBlock).strictlyPostDominates(bb)
}
predicate postDominates(BasicBlock bb) { this.(ReachableBasicBlock).postDominates(bb) }
}
pragma[nomagic]
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
bb1.getASuccessor() = bb2 and
bb1 = bb2.getImmediateDominator() and
forall(BasicBlock pred | pred = bb2.getAPredecessor() and pred != bb1 | bb2.dominates(pred))
}
predicate entryBlock(BasicBlock bb) { entryBB(bb) }
}
}