cached stages iteration 2

This commit is contained in:
Erik Krogh Kristensen
2021-12-07 11:16:25 +01:00
parent 71eacea90b
commit 60b5af215f
8 changed files with 81 additions and 6 deletions

View File

@@ -9,6 +9,7 @@
// Importing python under the `py` namespace to avoid importing `CallNode` from `Flow.qll` and thereby having a naming conflict with `API::CallNode`. // Importing python under the `py` namespace to avoid importing `CallNode` from `Flow.qll` and thereby having a naming conflict with `API::CallNode`.
private import python as py private import python as py
import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.DataFlow
private import semmle.python.internal.CachedStages
/** /**
* Provides classes and predicates for working with APIs used in a database. * Provides classes and predicates for working with APIs used in a database.
@@ -683,6 +684,7 @@ module API {
*/ */
cached cached
DataFlow::LocalSourceNode trackUseNode(DataFlow::LocalSourceNode src) { DataFlow::LocalSourceNode trackUseNode(DataFlow::LocalSourceNode src) {
Stages::TypeTracking::ref() and
result = trackUseNode(src, DataFlow::TypeTracker::end()) and result = trackUseNode(src, DataFlow::TypeTracker::end()) and
not result instanceof DataFlow::ModuleVariableNode not result instanceof DataFlow::ModuleVariableNode
} }

View File

@@ -1,4 +1,5 @@
import python import python
private import semmle.python.internal.CachedStages
/** A syntactic node (Class, Function, Module, Expr, Stmt or Comprehension) corresponding to a flow node */ /** A syntactic node (Class, Function, Module, Expr, Stmt or Comprehension) corresponding to a flow node */
abstract class AstNode extends AstNode_ { abstract class AstNode extends AstNode_ {
@@ -20,6 +21,7 @@ abstract class AstNode extends AstNode_ {
ControlFlowNode getAFlowNode() { py_flow_bb_node(result, this, _, _) } ControlFlowNode getAFlowNode() { py_flow_bb_node(result, this, _, _) }
/** Gets the location for this AST node */ /** Gets the location for this AST node */
cached
Location getLocation() { none() } Location getLocation() { none() }
/** /**
@@ -106,7 +108,10 @@ class Comprehension extends Comprehension_, AstNode {
override string toString() { result = "Comprehension" } override string toString() { result = "Comprehension" }
override Location getLocation() { result = Comprehension_.super.getLocation() } override Location getLocation() {
Stages::SSA::ref() and
result = Comprehension_.super.getLocation()
}
override AstNode getAChildNode() { result = this.getASubExpression() } override AstNode getAChildNode() { result = this.getASubExpression() }

View File

@@ -1,6 +1,7 @@
import python import python
private import semmle.python.pointsto.PointsTo private import semmle.python.pointsto.PointsTo
private import semmle.python.objects.ObjectInternal private import semmle.python.objects.ObjectInternal
private import semmle.python.internal.CachedStages
/** An expression */ /** An expression */
class Expr extends Expr_, AstNode { class Expr extends Expr_, AstNode {
@@ -8,7 +9,11 @@ class Expr extends Expr_, AstNode {
override Scope getScope() { py_scopes(this, result) } override Scope getScope() { py_scopes(this, result) }
/** Gets a textual representation of this element. */ /** Gets a textual representation of this element. */
override string toString() { result = "Expression" } cached
override string toString() {
Stages::SSA::ref() and
result = "Expression"
}
/** Gets the module in which this expression occurs */ /** Gets the module in which this expression occurs */
Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } Module getEnclosingModule() { result = this.getScope().getEnclosingModule() }

View File

@@ -1001,12 +1001,16 @@ class BasicBlock extends @py_flow_node {
string toString() { result = "BasicBlock" } string toString() { result = "BasicBlock" }
/** Whether this basic block strictly dominates the other */ /** Whether this basic block strictly dominates the other */
pragma[nomagic] cached
predicate strictlyDominates(BasicBlock other) { other.getImmediateDominator+() = this } predicate strictlyDominates(BasicBlock other) {
Stages::SSA::ref() and
other.getImmediateDominator+() = this
}
/** Whether this basic block dominates the other */ /** Whether this basic block dominates the other */
pragma[nomagic] cached
predicate dominates(BasicBlock other) { predicate dominates(BasicBlock other) {
Stages::SSA::ref() and
this = other this = other
or or
this.strictlyDominates(other) this.strictlyDominates(other)

View File

@@ -1,6 +1,7 @@
import python import python
private import semmle.python.objects.ObjectAPI private import semmle.python.objects.ObjectAPI
private import semmle.python.objects.Modules private import semmle.python.objects.Modules
private import semmle.python.internal.CachedStages
/** /**
* A module. This is the top level element in an AST, corresponding to a source file. * A module. This is the top level element in an AST, corresponding to a source file.
@@ -221,7 +222,9 @@ private predicate transitively_imported_from_entry_point(File file) {
) )
} }
cached
string moduleNameFromFile(Container file) { string moduleNameFromFile(Container file) {
Stages::SSA::ref() and
exists(string basename | exists(string basename |
basename = moduleNameFromBase(file) and basename = moduleNameFromBase(file) and
legalShortName(basename) legalShortName(basename)

View File

@@ -1,6 +1,7 @@
/** Step Summaries and Type Tracking */ /** Step Summaries and Type Tracking */
private import TypeTrackerSpecific private import TypeTrackerSpecific
private import semmle.python.internal.CachedStages
/** /**
* A string that may appear as the name of a piece of content. This will usually include things like: * A string that may appear as the name of a piece of content. This will usually include things like:
@@ -40,6 +41,7 @@ private module Cached {
/** Gets the summary resulting from appending `step` to type-tracking summary `tt`. */ /** Gets the summary resulting from appending `step` to type-tracking summary `tt`. */
cached cached
TypeTracker append(TypeTracker tt, StepSummary step) { TypeTracker append(TypeTracker tt, StepSummary step) {
Stages::TypeTracking::ref() and
exists(Boolean hasCall, OptionalContentName content | tt = MkTypeTracker(hasCall, content) | exists(Boolean hasCall, OptionalContentName content | tt = MkTypeTracker(hasCall, content) |
step = LevelStep() and result = tt step = LevelStep() and result = tt
or or

View File

@@ -37,6 +37,7 @@ module Stages {
*/ */
cached cached
module SSA { module SSA {
// TODO: This is more a "basic AST", not a "SSA" stage.
/** /**
* Always holds. * Always holds.
* Ensures that a predicate is evaluated as part of the Ast stage. * Ensures that a predicate is evaluated as part of the Ast stage.
@@ -47,6 +48,10 @@ module Stages {
private import semmle.python.essa.SsaDefinitions as SsaDefinitions private import semmle.python.essa.SsaDefinitions as SsaDefinitions
private import semmle.python.essa.SsaCompute as SsaCompute private import semmle.python.essa.SsaCompute as SsaCompute
private import semmle.python.essa.Essa as Essa private import semmle.python.essa.Essa as Essa
private import semmle.python.Module as PyModule
private import semmle.python.Exprs as Exprs
private import semmle.python.AstExtended as AstExtended
private import semmle.python.Flow as PyFlow
/** /**
* DONT USE! * DONT USE!
@@ -61,6 +66,47 @@ module Stages {
SsaCompute::SsaDefinitions::reachesEndOfBlock(_, _, _, _) SsaCompute::SsaDefinitions::reachesEndOfBlock(_, _, _, _)
or or
exists(any(Essa::PhiFunction p).getInput(_)) exists(any(Essa::PhiFunction p).getInput(_))
or
exists(PyModule::moduleNameFromFile(_))
or
exists(any(Exprs::Expr e).toString())
or
exists(any(AstExtended::AstNode n).getLocation())
or
exists(any(PyFlow::BasicBlock b).getImmediateDominator())
or
any(PyFlow::BasicBlock b).strictlyDominates(_)
or
any(PyFlow::BasicBlock b).dominates(_)
}
}
/**
* The `TypeTracking` stage.
*/
cached
module TypeTracking {
/**
* Always holds.
* Ensures that a predicate is evaluated as part of the Ast stage.
*/
cached
predicate ref() { 1 = 1 }
private import semmle.python.dataflow.new.DataFlow::DataFlow as NewDataFlow
private import semmle.python.ApiGraphs::API as API
/**
* DONT USE!
* Contains references to each predicate that use the above `ref` predicate.
*/
cached
predicate backref() {
1 = 1
or
exists(any(NewDataFlow::TypeTracker t).append(_))
or
exists(any(API::Node n).getAMember().getAUse())
} }
} }
@@ -83,6 +129,7 @@ module Stages {
private import semmle.python.types.Object as TypeObject private import semmle.python.types.Object as TypeObject
private import semmle.python.objects.TObject as TObject private import semmle.python.objects.TObject as TObject
private import semmle.python.Flow as Flow private import semmle.python.Flow as Flow
private import semmle.python.objects.ObjectInternal as ObjectInternal
/** /**
* DONT USE! * DONT USE!
@@ -107,6 +154,8 @@ module Stages {
exists(TObject::TObject f) exists(TObject::TObject f)
or or
exists(any(Flow::ControlFlowNode c).toString()) exists(any(Flow::ControlFlowNode c).toString())
or
exists(any(ObjectInternal::ObjectInternal o).toString())
} }
} }

View File

@@ -15,9 +15,11 @@ import semmle.python.objects.Callables
import semmle.python.objects.Constants import semmle.python.objects.Constants
import semmle.python.objects.Sequences import semmle.python.objects.Sequences
import semmle.python.objects.Descriptors import semmle.python.objects.Descriptors
private import semmle.python.internal.CachedStages
class ObjectInternal extends TObject { class ObjectInternal extends TObject {
/** Gets a textual representation of this element. */ /** Gets a textual representation of this element. */
cached
abstract string toString(); abstract string toString();
/** /**
@@ -213,7 +215,10 @@ class ObjectInternal extends TObject {
class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject { class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject {
override Builtin getBuiltin() { this = TBuiltinOpaqueObject(result) } override Builtin getBuiltin() { this = TBuiltinOpaqueObject(result) }
override string toString() { result = this.getBuiltin().getClass().getName() + " object" } override string toString() {
Stages::DataFlow::ref() and
result = this.getBuiltin().getClass().getName() + " object"
}
override boolean booleanValue() { override boolean booleanValue() {
// TO DO ... Depends on class. `result = this.getClass().instancesBooleanValue()` // TO DO ... Depends on class. `result = this.getClass().instancesBooleanValue()`