Skip to content

Commit d723cb4

Browse files
committed
Python: attempt at instantiating MakeSsa
- part of the ESSA adapter layer still refers to the raw SSA (now called Impl)
1 parent 1b55291 commit d723cb4

1 file changed

Lines changed: 93 additions & 35 deletions

File tree

  • python/ql/lib/semmle/python/dataflow/new/internal

python/ql/lib/semmle/python/dataflow/new/internal/SsaImpl.qll

Lines changed: 93 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -252,23 +252,92 @@ private module SsaImplInput implements SsaImplCommon::InputSig<Py::Location, Cfg
252252
}
253253
}
254254

255-
/**
256-
* The shared SSA instantiation for Python.
257-
*
258-
* Members:
259-
* - `Definition` — the union of explicit, uncertain, and phi definitions
260-
* - `WriteDefinition`, `UncertainWriteDefinition`, `PhiNode`
261-
* - the standard SSA predicates (`getAUse`, `getAnUltimateDefinition`, ...).
262-
*/
263-
module Ssa = SsaImplCommon::Make<Py::Location, CfgImpl::Cfg, SsaImplInput>;
255+
import SsaImplCommon::Make<Py::Location, CfgImpl::Cfg, SsaImplInput> as Impl
256+
257+
// Matching the cases in `SsaImplInput.variableWrite` above
258+
newtype TVariableWrite =
259+
TName(CfgImpl::Ast::Expr name, SsaSourceVariable v) {
260+
exists(Py::Name n | name.asExpr() = n and n.getVariable() = v.getVariable() |
261+
n.isDefinition() or
262+
n.isDeletion()
263+
)
264+
} or
265+
TImportStar(CfgImpl::Ast::Expr i, SsaSourceVariable v) {
266+
exists(Py::ImportStar imp | i.asExpr() = imp.getModuleExpr() |
267+
v.getScope() = imp.getScope()
268+
or
269+
exists(Py::Name other |
270+
other.uses(v.getVariable()) and
271+
imp.getScope() = other.getScope()
272+
)
273+
)
274+
}
264275

265-
final class Definition = Ssa::Definition;
276+
private module SsaInput implements Impl::SsaInputSig {
277+
// private import java as J
278+
// class Expr = Py::Expr;
279+
class Expr extends CfgImpl::Ast::Expr {
280+
CfgImpl::Cfg::ControlFlowNode getControlFlowNode() { result.injects(this) }
281+
}
282+
283+
class Parameter = CfgImpl::Ast::Parameter;
284+
285+
class VariableWrite extends TVariableWrite {
286+
Expr asExpr() {
287+
this = TName(result, _)
288+
or
289+
this = TImportStar(result, _)
290+
}
291+
292+
Expr getValue() {
293+
exists(CfgImpl::Ast::Expr name, Py::Name n, Cfg::DefinitionNode def |
294+
this = TName(name, _) and name.asExpr() = n and def.getNode() = n
295+
|
296+
result.asExpr() = def.getValue().getNode()
297+
)
298+
}
266299

267-
final class WriteDefinition = Ssa::WriteDefinition;
300+
predicate isParameterInit(CfgImpl::Ast::Parameter p) { this = TName(p, _) }
268301

269-
final class UncertainWriteDefinition = Ssa::UncertainWriteDefinition;
302+
string toString() {
303+
exists(CfgImpl::Ast::Expr n | this = TName(n, _) | result = n.toString())
304+
or
305+
exists(CfgImpl::Ast::Expr imp | this = TImportStar(imp, _) | result = imp.toString())
306+
}
270307

271-
final class PhiNode = Ssa::PhiNode;
308+
Py::Location getLocation() {
309+
exists(CfgImpl::Ast::Expr n | this = TName(n, _) | result = n.getLocation())
310+
or
311+
exists(CfgImpl::Ast::Expr imp | this = TImportStar(imp, _) | result = imp.getLocation())
312+
}
313+
314+
predicate writesAt(CfgImpl::BasicBlock bb, int i, SsaSourceVariable v) {
315+
exists(CfgImpl::Ast::Expr n |
316+
this = TName(n, v) and
317+
bb.getNode(i).getAstNode() = n
318+
)
319+
or
320+
exists(CfgImpl::Ast::Expr imp |
321+
this = TImportStar(imp, v) and
322+
bb.getNode(i).getAstNode() = imp
323+
)
324+
}
325+
}
326+
327+
predicate explicitWrite(VariableWrite def, CfgImpl::Cfg::BasicBlock bb, int i, SsaSourceVariable v) {
328+
def.writesAt(bb, i, v)
329+
}
330+
}
331+
332+
module Ssa = Impl::MakeSsa<SsaInput>;
333+
334+
final class Definition = Impl::Definition;
335+
336+
final class WriteDefinition = Impl::WriteDefinition;
337+
338+
final class UncertainWriteDefinition = Impl::UncertainWriteDefinition;
339+
340+
final class PhiNode = Impl::PhiNode;
272341

273342
// ===========================================================================
274343
// ESSA-shaped adapter layer
@@ -294,7 +363,7 @@ final class PhiNode = Ssa::PhiNode;
294363
* (synthesised at position `-1` of a scope's entry BB) this is the
295364
* scope's entry node.
296365
*/
297-
private Cfg::ControlFlowNode writeDefNode(Ssa::WriteDefinition def) {
366+
private Cfg::ControlFlowNode writeDefNode(Ssa::SsaWriteDefinition def) {
298367
exists(CfgImpl::BasicBlock bb, int i | def.definesAt(_, bb, i) |
299368
i >= 0 and result = bb.getNode(i)
300369
or
@@ -307,7 +376,7 @@ private Cfg::ControlFlowNode writeDefNode(Ssa::WriteDefinition def) {
307376
* everything that's not a phi node. Mirrors legacy ESSA's
308377
* `EssaNodeDefinition`.
309378
*/
310-
class EssaNodeDefinition extends Ssa::WriteDefinition {
379+
class EssaNodeDefinition extends Ssa::SsaWriteDefinition {
311380
/** Gets the CFG node where this definition's binding takes place. */
312381
Cfg::ControlFlowNode getDefiningNode() { result = writeDefNode(this) }
313382

@@ -451,19 +520,19 @@ class PhiFunction extends PhiNode {
451520
* the phi from one of its predecessor blocks). Mirrors legacy
452521
* ESSA's `PhiFunction.getAnInput()`.
453522
*/
454-
Ssa::Definition getAnInput() { Ssa::phiHasInputFromBlock(this, result, _) }
523+
Ssa::SsaDefinition getAnInput() { Impl::phiHasInputFromBlock(this, result, _) }
455524
}
456525

457526
/** Base class for all ESSA definitions (legacy-shaped). */
458-
class EssaDefinition = Ssa::Definition;
527+
class EssaDefinition = Ssa::SsaDefinition;
459528

460529
/**
461530
* An adapter representing a single SSA-defined "variable" — wrapping
462531
* one `Ssa::Definition`. Mirrors legacy `EssaVariable` API.
463532
*/
464-
class EssaVariable extends Ssa::Definition {
533+
class EssaVariable extends Ssa::SsaDefinition {
465534
/** Gets the underlying SSA definition (legacy name). */
466-
Ssa::Definition getDefinition() { result = this }
535+
Ssa::SsaDefinition getDefinition() { result = this }
467536

468537
/**
469538
* Gets a CFG node where this definition is used. Includes regular
@@ -474,7 +543,7 @@ class EssaVariable extends Ssa::Definition {
474543
*/
475544
Cfg::ControlFlowNode getAUse() {
476545
exists(CfgImpl::BasicBlock bb, int i |
477-
Ssa::ssaDefReachesRead(this.getSourceVariable(), this, bb, i) and
546+
Impl::ssaDefReachesRead(this.getSourceVariable(), this.(Ssa::SsaWriteDefinition), bb, i) and
478547
bb.getNode(i) = result
479548
)
480549
}
@@ -484,17 +553,6 @@ class EssaVariable extends Ssa::Definition {
484553

485554
/** Gets the scope in which this variable lives. */
486555
Py::Scope getScope() { result = this.getSourceVariable().getVariable().getScope() }
487-
488-
/** Gets an ultimate non-phi ancestor of this definition. */
489-
EssaVariable getAnUltimateDefinition() {
490-
if this instanceof PhiNode
491-
then
492-
exists(Ssa::Definition input |
493-
Ssa::phiHasInputFromBlock(this, input, _) and
494-
result = input.(EssaVariable).getAnUltimateDefinition()
495-
)
496-
else result = this
497-
}
498556
}
499557

500558
/**
@@ -506,16 +564,16 @@ module AdjacentUses {
506564
/** Holds if `nodeFrom` and `nodeTo` are adjacent uses of the same SSA variable. */
507565
predicate adjacentUseUse(Cfg::NameNode nodeFrom, Cfg::NameNode nodeTo) {
508566
exists(SsaSourceVariable v, CfgImpl::BasicBlock bb1, int i1, CfgImpl::BasicBlock bb2, int i2 |
509-
Ssa::adjacentUseUse(bb1, i1, bb2, i2, v, _) and
567+
Impl::adjacentUseUse(bb1, i1, bb2, i2, v, _) and
510568
nodeFrom = bb1.getNode(i1) and
511569
nodeTo = bb2.getNode(i2)
512570
)
513571
}
514572

515573
/** Holds if `use` is a first use of definition `def`. */
516-
predicate firstUse(Ssa::Definition def, Cfg::NameNode use) {
574+
predicate firstUse(Ssa::SsaDefinition def, Cfg::NameNode use) {
517575
exists(CfgImpl::BasicBlock bb, int i |
518-
Ssa::firstUse(def, bb, i, _) and
576+
Impl::firstUse(def, bb, i, _) and
519577
use = bb.getNode(i)
520578
)
521579
}
@@ -524,7 +582,7 @@ module AdjacentUses {
524582
* Holds if `use` is any reachable use of definition `def`. Combines
525583
* `firstUse` with transitive use-use adjacency.
526584
*/
527-
predicate useOfDef(Ssa::Definition def, Cfg::NameNode use) {
585+
predicate useOfDef(Ssa::SsaDefinition def, Cfg::NameNode use) {
528586
firstUse(def, use)
529587
or
530588
exists(Cfg::NameNode mid | useOfDef(def, mid) and adjacentUseUse(mid, use))

0 commit comments

Comments
 (0)