mirror of
https://github.com/github/codeql.git
synced 2026-04-28 18:25:24 +02:00
Python: Remove points-to to from ControlFlowNode
Moves the existing points-to predicates to the newly added class `ControlFlowNodeWithPointsTo` which resides in the `LegacyPointsTo` module. (Existing code that uses these predicates should import this module, and references to `ControlFlowNode` should be changed to `ControlFlowNodeWithPointsTo`.) Also updates all existing points-to based code to do just this.
This commit is contained in:
121
python/ql/lib/LegacyPointsTo.qll
Normal file
121
python/ql/lib/LegacyPointsTo.qll
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* DEPRECATED: Using the methods in this module may lead to a degradation of performance. Use at
|
||||
* your own peril.
|
||||
*
|
||||
* This module contains legacy points-to predicates and methods for various classes in the
|
||||
* points-to analysis.
|
||||
*
|
||||
* Existing code that depends on, say, points-to predicates on `ControlFlowNode` should be modified
|
||||
* to use `ControlFlowNodeWithPointsTo` instead. In particular, if inside a method call chain such
|
||||
* as
|
||||
*
|
||||
* `someCallNode.getFunction().pointsTo(...)`
|
||||
*
|
||||
* an explicit cast should be added as follows
|
||||
*
|
||||
* `someCallNode.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(...)`
|
||||
*
|
||||
* Similarly, if a bound variable has type `ControlFlowNode`, and a points-to method is called on
|
||||
* it, the type should be changed to `ControlFlowNodeWithPointsTo`.
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
|
||||
/**
|
||||
* An extension of `ControlFlowNode` that provides points-to predicates.
|
||||
*/
|
||||
class ControlFlowNodeWithPointsTo extends ControlFlowNode {
|
||||
/** Gets the value that this ControlFlowNode points-to. */
|
||||
predicate pointsTo(Value value) { this.pointsTo(_, value, _) }
|
||||
|
||||
/** Gets the value that this ControlFlowNode points-to. */
|
||||
Value pointsTo() { this.pointsTo(_, result, _) }
|
||||
|
||||
/** Gets a value that this ControlFlowNode may points-to. */
|
||||
Value inferredValue() { this.pointsTo(_, result, _) }
|
||||
|
||||
/** Gets the value and origin that this ControlFlowNode points-to. */
|
||||
predicate pointsTo(Value value, ControlFlowNode origin) { this.pointsTo(_, value, origin) }
|
||||
|
||||
/** Gets the value and origin that this ControlFlowNode points-to, given the context. */
|
||||
predicate pointsTo(Context context, Value value, ControlFlowNode origin) {
|
||||
PointsTo::pointsTo(this, context, value, origin)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets what this flow node might "refer-to". Performs a combination of localized (intra-procedural) points-to
|
||||
* analysis and global module-level analysis. This points-to analysis favours precision over recall. It is highly
|
||||
* precise, but may not provide information for a significant number of flow-nodes.
|
||||
* If the class is unimportant then use `refersTo(value)` or `refersTo(value, origin)` instead.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate refersTo(Object obj, ClassObject cls, ControlFlowNode origin) {
|
||||
this.refersTo(_, obj, cls, origin)
|
||||
}
|
||||
|
||||
/** Gets what this expression might "refer-to" in the given `context`. */
|
||||
pragma[nomagic]
|
||||
predicate refersTo(Context context, Object obj, ClassObject cls, ControlFlowNode origin) {
|
||||
not obj = unknownValue() and
|
||||
not cls = theUnknownType() and
|
||||
PointsTo::points_to(this, context, obj, cls, origin)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this flow node might "refer-to" to `value` which is from `origin`
|
||||
* Unlike `this.refersTo(value, _, origin)` this predicate includes results
|
||||
* where the class cannot be inferred.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate refersTo(Object obj, ControlFlowNode origin) {
|
||||
not obj = unknownValue() and
|
||||
PointsTo::points_to(this, _, obj, _, origin)
|
||||
}
|
||||
|
||||
/** Equivalent to `this.refersTo(value, _)` */
|
||||
predicate refersTo(Object obj) { this.refersTo(obj, _) }
|
||||
|
||||
/**
|
||||
* Check whether this control-flow node has complete points-to information.
|
||||
* This would mean that the analysis managed to infer an over approximation
|
||||
* of possible values at runtime.
|
||||
*/
|
||||
predicate hasCompletePointsToSet() {
|
||||
// If the tracking failed, then `this` will be its own "origin". In that
|
||||
// case, we want to exclude nodes for which there is also a different
|
||||
// origin, as that would indicate that some paths failed and some did not.
|
||||
this.refersTo(_, _, this) and
|
||||
not exists(ControlFlowNode other | other != this and this.refersTo(_, _, other))
|
||||
or
|
||||
// If `this` is a use of a variable, then we must have complete points-to
|
||||
// for that variable.
|
||||
exists(SsaVariable v | v.getAUse() = this | varHasCompletePointsToSet(v))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a SSA variable has complete points-to information.
|
||||
* This would mean that the analysis managed to infer an overapproximation
|
||||
* of possible values at runtime.
|
||||
*/
|
||||
private predicate varHasCompletePointsToSet(SsaVariable var) {
|
||||
// Global variables may be modified non-locally or concurrently.
|
||||
not var.getVariable() instanceof GlobalVariable and
|
||||
(
|
||||
// If we have complete points-to information on the definition of
|
||||
// this variable, then the variable has complete information.
|
||||
var.getDefinition()
|
||||
.(DefinitionNode)
|
||||
.getValue()
|
||||
.(ControlFlowNodeWithPointsTo)
|
||||
.hasCompletePointsToSet()
|
||||
or
|
||||
// If this variable is a phi output, then we have complete
|
||||
// points-to information about it if all phi inputs had complete
|
||||
// information.
|
||||
forex(SsaVariable phiInput | phiInput = var.getAPhiInput() |
|
||||
varHasCompletePointsToSet(phiInput)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
import semmle.python.pointsto.PointsTo
|
||||
import IDEContextual
|
||||
|
||||
@@ -36,22 +37,22 @@ private predicate jump_to_defn(ControlFlowNode use, Definition defn) {
|
||||
)
|
||||
or
|
||||
exists(PythonModuleObject mod |
|
||||
use.(ImportExprNode).refersTo(mod) and
|
||||
use.(ImportExprNode).(ControlFlowNodeWithPointsTo).refersTo(mod) and
|
||||
defn.getAstNode() = mod.getModule()
|
||||
)
|
||||
or
|
||||
exists(PythonModuleObject mod, string name |
|
||||
use.(ImportMemberNode).getModule(name).refersTo(mod) and
|
||||
use.(ImportMemberNode).getModule(name).(ControlFlowNodeWithPointsTo).refersTo(mod) and
|
||||
scope_jump_to_defn_attribute(mod.getModule(), name, defn)
|
||||
)
|
||||
or
|
||||
exists(PackageObject package |
|
||||
use.(ImportExprNode).refersTo(package) and
|
||||
use.(ImportExprNode).(ControlFlowNodeWithPointsTo).refersTo(package) and
|
||||
defn.getAstNode() = package.getInitModule().getModule()
|
||||
)
|
||||
or
|
||||
exists(PackageObject package, string name |
|
||||
use.(ImportMemberNode).getModule(name).refersTo(package) and
|
||||
use.(ImportMemberNode).getModule(name).(ControlFlowNodeWithPointsTo).refersTo(package) and
|
||||
scope_jump_to_defn_attribute(package.getInitModule().getModule(), name, defn)
|
||||
)
|
||||
or
|
||||
@@ -230,7 +231,7 @@ private predicate module_and_name_for_import_star_helper(
|
||||
ModuleObject mod, string name, ImportStarNode im_star, ImportStarRefinement def
|
||||
) {
|
||||
im_star = def.getDefiningNode() and
|
||||
im_star.getModule().refersTo(mod) and
|
||||
im_star.getModule().(ControlFlowNodeWithPointsTo).refersTo(mod) and
|
||||
name = def.getSourceVariable().getName()
|
||||
}
|
||||
|
||||
@@ -239,7 +240,7 @@ pragma[noinline]
|
||||
private predicate variable_not_redefined_by_import_star(EssaVariable var, ImportStarRefinement def) {
|
||||
var = def.getInput() and
|
||||
exists(ModuleObject mod |
|
||||
def.getDefiningNode().(ImportStarNode).getModule().refersTo(mod) and
|
||||
def.getDefiningNode().(ImportStarNode).getModule().(ControlFlowNodeWithPointsTo).refersTo(mod) and
|
||||
not mod.exports(var.getSourceVariable().getName())
|
||||
)
|
||||
}
|
||||
@@ -352,7 +353,9 @@ private predicate scope_jump_to_defn_attribute(ImportTimeScope s, string name, D
|
||||
)
|
||||
}
|
||||
|
||||
private predicate jump_to_defn_attribute(ControlFlowNode use, string name, Definition defn) {
|
||||
private predicate jump_to_defn_attribute(
|
||||
ControlFlowNodeWithPointsTo use, string name, Definition defn
|
||||
) {
|
||||
/* Local attribute */
|
||||
exists(EssaVariable var |
|
||||
use = var.getASourceUse() and
|
||||
@@ -367,7 +370,7 @@ private predicate jump_to_defn_attribute(ControlFlowNode use, string name, Defin
|
||||
/* Super attributes */
|
||||
exists(AttrNode f, SuperBoundMethod sbm, Object function |
|
||||
use = f.getObject(name) and
|
||||
f.refersTo(sbm) and
|
||||
f.(ControlFlowNodeWithPointsTo).refersTo(sbm) and
|
||||
function = sbm.getFunction(_) and
|
||||
function.getOrigin() = defn.getAstNode()
|
||||
)
|
||||
@@ -408,7 +411,7 @@ private predicate attribute_assignment_jump_to_defn_attribute(
|
||||
private predicate sets_attribute(ArgumentRefinement def, string name) {
|
||||
exists(CallNode call |
|
||||
call = def.getDefiningNode() and
|
||||
call.getFunction().refersTo(Object::builtin("setattr")) and
|
||||
call.getFunction().(ControlFlowNodeWithPointsTo).refersTo(Object::builtin("setattr")) and
|
||||
def.getInput().getAUse() = call.getArg(0) and
|
||||
call.getArg(1).getNode().(StringLiteral).getText() = name
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.internal.CachedStages
|
||||
@@ -71,7 +72,9 @@ class Expr extends Expr_, AstNode {
|
||||
* Gets what this expression might "refer-to" in the given `context`.
|
||||
*/
|
||||
predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) {
|
||||
this.getAFlowNode().refersTo(context, obj, cls, origin.getAFlowNode())
|
||||
this.getAFlowNode()
|
||||
.(ControlFlowNodeWithPointsTo)
|
||||
.refersTo(context, obj, cls, origin.getAFlowNode())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +85,7 @@ class Expr extends Expr_, AstNode {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate refersTo(Object obj, AstNode origin) {
|
||||
this.getAFlowNode().refersTo(obj, origin.getAFlowNode())
|
||||
this.getAFlowNode().(ControlFlowNodeWithPointsTo).refersTo(obj, origin.getAFlowNode())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,14 +99,16 @@ class Expr extends Expr_, AstNode {
|
||||
* in the given `context`.
|
||||
*/
|
||||
predicate pointsTo(Context context, Value value, AstNode origin) {
|
||||
this.getAFlowNode().pointsTo(context, value, origin.getAFlowNode())
|
||||
this.getAFlowNode()
|
||||
.(ControlFlowNodeWithPointsTo)
|
||||
.pointsTo(context, value, origin.getAFlowNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression might "point-to" to `value` which is from `origin`.
|
||||
*/
|
||||
predicate pointsTo(Value value, AstNode origin) {
|
||||
this.getAFlowNode().pointsTo(value, origin.getAFlowNode())
|
||||
this.getAFlowNode().(ControlFlowNodeWithPointsTo).pointsTo(value, origin.getAFlowNode())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import python
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.internal.CachedStages
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
@@ -144,56 +143,6 @@ class ControlFlowNode extends @py_flow_node {
|
||||
/** Whether this flow node is the first in its scope */
|
||||
predicate isEntryNode() { py_scope_flow(this, _, -1) }
|
||||
|
||||
/** Gets the value that this ControlFlowNode points-to. */
|
||||
predicate pointsTo(Value value) { this.pointsTo(_, value, _) }
|
||||
|
||||
/** Gets the value that this ControlFlowNode points-to. */
|
||||
Value pointsTo() { this.pointsTo(_, result, _) }
|
||||
|
||||
/** Gets a value that this ControlFlowNode may points-to. */
|
||||
Value inferredValue() { this.pointsTo(_, result, _) }
|
||||
|
||||
/** Gets the value and origin that this ControlFlowNode points-to. */
|
||||
predicate pointsTo(Value value, ControlFlowNode origin) { this.pointsTo(_, value, origin) }
|
||||
|
||||
/** Gets the value and origin that this ControlFlowNode points-to, given the context. */
|
||||
predicate pointsTo(Context context, Value value, ControlFlowNode origin) {
|
||||
PointsTo::pointsTo(this, context, value, origin)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets what this flow node might "refer-to". Performs a combination of localized (intra-procedural) points-to
|
||||
* analysis and global module-level analysis. This points-to analysis favours precision over recall. It is highly
|
||||
* precise, but may not provide information for a significant number of flow-nodes.
|
||||
* If the class is unimportant then use `refersTo(value)` or `refersTo(value, origin)` instead.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate refersTo(Object obj, ClassObject cls, ControlFlowNode origin) {
|
||||
this.refersTo(_, obj, cls, origin)
|
||||
}
|
||||
|
||||
/** Gets what this expression might "refer-to" in the given `context`. */
|
||||
pragma[nomagic]
|
||||
predicate refersTo(Context context, Object obj, ClassObject cls, ControlFlowNode origin) {
|
||||
not obj = unknownValue() and
|
||||
not cls = theUnknownType() and
|
||||
PointsTo::points_to(this, context, obj, cls, origin)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this flow node might "refer-to" to `value` which is from `origin`
|
||||
* Unlike `this.refersTo(value, _, origin)` this predicate includes results
|
||||
* where the class cannot be inferred.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate refersTo(Object obj, ControlFlowNode origin) {
|
||||
not obj = unknownValue() and
|
||||
PointsTo::points_to(this, _, obj, _, origin)
|
||||
}
|
||||
|
||||
/** Equivalent to `this.refersTo(value, _)` */
|
||||
predicate refersTo(Object obj) { this.refersTo(obj, _) }
|
||||
|
||||
/** Gets the basic block containing this flow node */
|
||||
BasicBlock getBasicBlock() { result.contains(this) }
|
||||
|
||||
@@ -259,23 +208,6 @@ class ControlFlowNode extends @py_flow_node {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this control-flow node has complete points-to information.
|
||||
* This would mean that the analysis managed to infer an over approximation
|
||||
* of possible values at runtime.
|
||||
*/
|
||||
predicate hasCompletePointsToSet() {
|
||||
// If the tracking failed, then `this` will be its own "origin". In that
|
||||
// case, we want to exclude nodes for which there is also a different
|
||||
// origin, as that would indicate that some paths failed and some did not.
|
||||
this.refersTo(_, _, this) and
|
||||
not exists(ControlFlowNode other | other != this and this.refersTo(_, _, other))
|
||||
or
|
||||
// If `this` is a use of a variable, then we must have complete points-to
|
||||
// for that variable.
|
||||
exists(SsaVariable v | v.getAUse() = this | varHasCompletePointsToSet(v))
|
||||
}
|
||||
|
||||
/** Whether this strictly dominates other. */
|
||||
pragma[inline]
|
||||
predicate strictlyDominates(ControlFlowNode other) {
|
||||
@@ -332,28 +264,6 @@ private class AnyNode extends ControlFlowNode {
|
||||
override AstNode getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a SSA variable has complete points-to information.
|
||||
* This would mean that the analysis managed to infer an overapproximation
|
||||
* of possible values at runtime.
|
||||
*/
|
||||
private predicate varHasCompletePointsToSet(SsaVariable var) {
|
||||
// Global variables may be modified non-locally or concurrently.
|
||||
not var.getVariable() instanceof GlobalVariable and
|
||||
(
|
||||
// If we have complete points-to information on the definition of
|
||||
// this variable, then the variable has complete information.
|
||||
var.getDefinition().(DefinitionNode).getValue().hasCompletePointsToSet()
|
||||
or
|
||||
// If this variable is a phi output, then we have complete
|
||||
// points-to information about it if all phi inputs had complete
|
||||
// information.
|
||||
forex(SsaVariable phiInput | phiInput = var.getAPhiInput() |
|
||||
varHasCompletePointsToSet(phiInput)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to a call expression, such as `func(...)` */
|
||||
class CallNode extends ControlFlowNode {
|
||||
CallNode() { toAst(this) instanceof Call }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
/** The metrics for a function */
|
||||
class FunctionMetrics extends Function {
|
||||
@@ -59,7 +60,7 @@ class FunctionMetrics extends Function {
|
||||
not non_coupling_method(result) and
|
||||
exists(Call call | call.getScope() = this |
|
||||
exists(FunctionObject callee | callee.getFunction() = result |
|
||||
call.getAFlowNode().getFunction().refersTo(callee)
|
||||
call.getAFlowNode().getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee)
|
||||
)
|
||||
or
|
||||
exists(Attribute a | call.getFunc() = a |
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
/** A control flow node which might correspond to a special method call. */
|
||||
class PotentialSpecialMethodCallNode extends ControlFlowNode instanceof SpecialMethod::Potential { }
|
||||
@@ -106,7 +107,11 @@ class SpecialMethodCallNode extends PotentialSpecialMethodCallNode {
|
||||
SpecialMethodCallNode() {
|
||||
exists(SpecialMethod::Potential pot |
|
||||
this = pot and
|
||||
pot.getSelf().pointsTo().getClass().lookup(pot.getSpecialMethodName()) = resolvedSpecialMethod
|
||||
pot.getSelf()
|
||||
.(ControlFlowNodeWithPointsTo)
|
||||
.pointsTo()
|
||||
.getClass()
|
||||
.lookup(pot.getSpecialMethodName()) = resolvedSpecialMethod
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.Filters as Filters
|
||||
@@ -374,7 +375,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
|
||||
exists(ModuleValue m, string name |
|
||||
src = TTaintTrackingNode_(_, context, path, kind, this) and
|
||||
this.moduleAttributeTainted(m, name, src) and
|
||||
node.asCfgNode().(ImportMemberNode).getModule(name).pointsTo(m)
|
||||
node.asCfgNode().(ImportMemberNode).getModule(name).(ControlFlowNodeWithPointsTo).pointsTo(m)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -408,7 +409,9 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
|
||||
src = TTaintTrackingNode_(srcnode, context, srcpath, srckind, this) and
|
||||
exists(CallNode call, ControlFlowNode arg |
|
||||
call = node.asCfgNode() and
|
||||
call.getFunction().pointsTo(ObjectInternal::builtin("getattr")) and
|
||||
call.getFunction()
|
||||
.(ControlFlowNodeWithPointsTo)
|
||||
.pointsTo(ObjectInternal::builtin("getattr")) and
|
||||
arg = call.getArg(0) and
|
||||
attrname = call.getArg(1).getNode().(StringLiteral).getText() and
|
||||
arg = srcnode.asCfgNode()
|
||||
@@ -515,7 +518,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
|
||||
TaintTrackingContext caller, TaintTrackingContext callee
|
||||
) {
|
||||
exists(ClassValue cls |
|
||||
call.getFunction().pointsTo(cls) and
|
||||
call.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(cls) and
|
||||
cls.lookup("__init__") = init
|
||||
|
|
||||
exists(int arg, TaintKind callerKind, AttributePath callerPath, DataFlow::Node argument |
|
||||
@@ -878,7 +881,7 @@ private class EssaTaintTracking extends string instanceof TaintTracking::Configu
|
||||
const.getNode() instanceof ImmutableLiteral
|
||||
)
|
||||
or
|
||||
exists(ControlFlowNode c, ClassValue cls |
|
||||
exists(ControlFlowNodeWithPointsTo c, ClassValue cls |
|
||||
Filters::isinstance(test, c, use) and
|
||||
c.pointsTo(cls)
|
||||
|
|
||||
@@ -978,7 +981,7 @@ module Implementation {
|
||||
tonode.getArg(0) = fromnode
|
||||
)
|
||||
or
|
||||
tonode.getFunction().pointsTo(ObjectInternal::builtin("reversed")) and
|
||||
tonode.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(ObjectInternal::builtin("reversed")) and
|
||||
tonode.getArg(0) = fromnode
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.pointsto.Filters as Filters
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.dataflow.Implementation
|
||||
@@ -267,7 +268,11 @@ module DictKind {
|
||||
Implementation::copyCall(fromnode, tonode) and
|
||||
edgeLabel = "dict copy"
|
||||
or
|
||||
tonode.(CallNode).getFunction().pointsTo(ObjectInternal::builtin("dict")) and
|
||||
tonode
|
||||
.(CallNode)
|
||||
.getFunction()
|
||||
.(ControlFlowNodeWithPointsTo)
|
||||
.pointsTo(ObjectInternal::builtin("dict")) and
|
||||
tonode.(CallNode).getArg(0) = fromnode and
|
||||
edgeLabel = "dict() call"
|
||||
}
|
||||
@@ -615,7 +620,7 @@ module DataFlow {
|
||||
TCfgNode(ControlFlowNode node)
|
||||
|
||||
abstract class Node extends TDataFlowNode {
|
||||
abstract ControlFlowNode asCfgNode();
|
||||
abstract ControlFlowNodeWithPointsTo asCfgNode();
|
||||
|
||||
abstract EssaVariable asVariable();
|
||||
|
||||
@@ -632,7 +637,7 @@ module DataFlow {
|
||||
}
|
||||
|
||||
class CfgNode extends Node, TCfgNode {
|
||||
override ControlFlowNode asCfgNode() { this = TCfgNode(result) }
|
||||
override ControlFlowNodeWithPointsTo asCfgNode() { this = TCfgNode(result) }
|
||||
|
||||
override EssaVariable asVariable() { none() }
|
||||
|
||||
@@ -647,7 +652,7 @@ module DataFlow {
|
||||
}
|
||||
|
||||
class EssaNode extends Node, TEssaNode {
|
||||
override ControlFlowNode asCfgNode() { none() }
|
||||
override ControlFlowNodeWithPointsTo asCfgNode() { none() }
|
||||
|
||||
override EssaVariable asVariable() { this = TEssaNode(result) }
|
||||
|
||||
@@ -668,7 +673,11 @@ pragma[noinline]
|
||||
private predicate dict_construct(ControlFlowNode itemnode, ControlFlowNode dictnode) {
|
||||
dictnode.(DictNode).getAValue() = itemnode
|
||||
or
|
||||
dictnode.(CallNode).getFunction().pointsTo(ObjectInternal::builtin("dict")) and
|
||||
dictnode
|
||||
.(CallNode)
|
||||
.getFunction()
|
||||
.(ControlFlowNodeWithPointsTo)
|
||||
.pointsTo(ObjectInternal::builtin("dict")) and
|
||||
dictnode.(CallNode).getArgByName(_) = itemnode
|
||||
}
|
||||
|
||||
@@ -688,7 +697,7 @@ private predicate sequence_construct(ControlFlowNode itemnode, ControlFlowNode s
|
||||
pragma[noinline]
|
||||
private predicate sequence_call(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode.getArg(0) = fromnode and
|
||||
exists(ControlFlowNode cls | cls = tonode.getFunction() |
|
||||
exists(ControlFlowNodeWithPointsTo cls | cls = tonode.getFunction() |
|
||||
cls.pointsTo(ObjectInternal::builtin("list"))
|
||||
or
|
||||
cls.pointsTo(ObjectInternal::builtin("tuple"))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
import semmle.python.dependencies.DependencyKind
|
||||
|
||||
private predicate importDependency(Object target, AstNode source) {
|
||||
@@ -59,7 +60,7 @@ class PythonUse extends DependencyKind {
|
||||
interesting(target) and
|
||||
this = this and
|
||||
source != target.(ControlFlowNode).getNode() and
|
||||
exists(ControlFlowNode use, Object obj |
|
||||
exists(ControlFlowNodeWithPointsTo use, Object obj |
|
||||
use.getNode() = source and
|
||||
use.refersTo(obj) and
|
||||
use.isLoad()
|
||||
@@ -114,12 +115,14 @@ private predicate attribute_access_dependency(Object target, AstNode source) {
|
||||
|
||||
private predicate use_of_attribute(Attribute attr, Scope s, string name) {
|
||||
exists(AttrNode cfg | cfg.isLoad() and cfg.getNode() = attr |
|
||||
exists(Object obj | cfg.getObject(name).refersTo(obj) |
|
||||
exists(Object obj | cfg.getObject(name).(ControlFlowNodeWithPointsTo).refersTo(obj) |
|
||||
s = obj.(PythonModuleObject).getModule() or
|
||||
s = obj.(ClassObject).getPyClass()
|
||||
)
|
||||
or
|
||||
exists(ClassObject cls | cfg.getObject(name).refersTo(_, cls, _) | s = cls.getPyClass())
|
||||
exists(ClassObject cls | cfg.getObject(name).(ControlFlowNodeWithPointsTo).refersTo(_, cls, _) |
|
||||
s = cls.getPyClass()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(SelfAttributeRead sar | sar = attr |
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
@@ -704,12 +705,14 @@ abstract class FunctionValue extends CallableValue {
|
||||
abstract ClassValue getARaisedType();
|
||||
|
||||
/** Gets a call-site from where this function is called as a function */
|
||||
CallNode getAFunctionCall() { result.getFunction().pointsTo() = this }
|
||||
CallNode getAFunctionCall() {
|
||||
result.getFunction().(ControlFlowNodeWithPointsTo).pointsTo() = this
|
||||
}
|
||||
|
||||
/** Gets a call-site from where this function is called as a method */
|
||||
CallNode getAMethodCall() {
|
||||
exists(BoundMethodObjectInternal bm |
|
||||
result.getFunction().pointsTo() = bm and
|
||||
result.getFunction().(ControlFlowNodeWithPointsTo).pointsTo() = bm and
|
||||
bm.getFunction() = this
|
||||
)
|
||||
}
|
||||
@@ -753,7 +756,7 @@ class PythonFunctionValue extends FunctionValue {
|
||||
* explicit return nodes that we can query and get the class of.
|
||||
*/
|
||||
|
||||
result = this.getAReturnedNode().pointsTo().getClass()
|
||||
result = this.getAReturnedNode().(ControlFlowNodeWithPointsTo).pointsTo().getClass()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.objects.Classes
|
||||
private import semmle.python.objects.Instances
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
@@ -193,7 +194,9 @@ class ClassObject extends Object {
|
||||
* It is guaranteed that getProbableSingletonInstance() returns at most one Object for each ClassObject.
|
||||
*/
|
||||
Object getProbableSingletonInstance() {
|
||||
exists(ControlFlowNode use, Expr origin | use.refersTo(result, this, origin.getAFlowNode()) |
|
||||
exists(ControlFlowNodeWithPointsTo use, Expr origin |
|
||||
use.refersTo(result, this, origin.getAFlowNode())
|
||||
|
|
||||
this.hasStaticallyUniqueInstance() and
|
||||
/* Ensure that original expression will be executed only one. */
|
||||
origin.getScope() instanceof ImportTimeScope and
|
||||
@@ -351,7 +354,7 @@ class ClassObject extends Object {
|
||||
* Gets a call to this class. Note that the call may not create a new instance of
|
||||
* this class, as that depends on the `__new__` method of this class.
|
||||
*/
|
||||
CallNode getACall() { result.getFunction().refersTo(this) }
|
||||
CallNode getACall() { result.getFunction().(ControlFlowNodeWithPointsTo).refersTo(this) }
|
||||
|
||||
override predicate notClass() { none() }
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
/** The subset of ControlFlowNodes which might raise an exception */
|
||||
class RaisingNode extends ControlFlowNode {
|
||||
@@ -30,7 +31,9 @@ class RaisingNode extends ControlFlowNode {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate quits() { this.(CallNode).getFunction().refersTo(Object::quitter(_)) }
|
||||
private predicate quits() {
|
||||
this.(CallNode).getFunction().(ControlFlowNodeWithPointsTo).refersTo(Object::quitter(_))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of an exception that may be raised
|
||||
@@ -68,7 +71,7 @@ class RaisingNode extends ControlFlowNode {
|
||||
private ClassObject localRaisedType_objectapi() {
|
||||
result.isSubclassOf(theBaseExceptionType()) and
|
||||
(
|
||||
exists(ControlFlowNode ex |
|
||||
exists(ControlFlowNodeWithPointsTo ex |
|
||||
ex = this.getExceptionNode() and
|
||||
(ex.refersTo(result) or ex.refersTo(_, result, _))
|
||||
)
|
||||
@@ -95,7 +98,7 @@ class RaisingNode extends ControlFlowNode {
|
||||
private ClassValue localRaisedType() {
|
||||
result.getASuperType() = ClassValue::baseException() and
|
||||
(
|
||||
exists(ControlFlowNode ex |
|
||||
exists(ControlFlowNodeWithPointsTo ex |
|
||||
ex = this.getExceptionNode() and
|
||||
(ex.pointsTo(result) or ex.pointsTo().getClass() = result)
|
||||
)
|
||||
@@ -153,7 +156,9 @@ class RaisingNode extends ControlFlowNode {
|
||||
/* Call to an unknown object */
|
||||
this.getNode() instanceof Call and
|
||||
not exists(FunctionObject func | this = func.getACall()) and
|
||||
not exists(ClassObject known | this.(CallNode).getFunction().refersTo(known))
|
||||
not exists(ClassObject known |
|
||||
this.(CallNode).getFunction().(ControlFlowNodeWithPointsTo).refersTo(known)
|
||||
)
|
||||
or
|
||||
this.getNode() instanceof Exec
|
||||
or
|
||||
@@ -371,7 +376,7 @@ class ExceptFlowNode extends ControlFlowNode {
|
||||
* Gets the type handled by this exception handler.
|
||||
* `ExceptionType` in `except ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getType() {
|
||||
ControlFlowNodeWithPointsTo getType() {
|
||||
exists(ExceptStmt ex |
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
ex = this.getNode() and
|
||||
@@ -470,7 +475,7 @@ class ExceptGroupFlowNode extends ControlFlowNode {
|
||||
}
|
||||
}
|
||||
|
||||
private ControlFlowNode element_from_tuple_objectapi(Object tuple) {
|
||||
private ControlFlowNodeWithPointsTo element_from_tuple_objectapi(Object tuple) {
|
||||
exists(Tuple t | t = tuple.getOrigin() and result = t.getAnElt().getAFlowNode())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
import semmle.python.types.Exceptions
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.objects.Callables
|
||||
@@ -32,27 +33,31 @@ abstract class FunctionObject extends Object {
|
||||
abstract string descriptiveString();
|
||||
|
||||
/** Gets a call-site from where this function is called as a function */
|
||||
CallNode getAFunctionCall() { result.getFunction().inferredValue() = this.theCallable() }
|
||||
CallNode getAFunctionCall() {
|
||||
result.getFunction().(ControlFlowNodeWithPointsTo).inferredValue() = this.theCallable()
|
||||
}
|
||||
|
||||
/** Gets a call-site from where this function is called as a method */
|
||||
CallNode getAMethodCall() {
|
||||
exists(BoundMethodObjectInternal bm |
|
||||
result.getFunction().inferredValue() = bm and
|
||||
result.getFunction().(ControlFlowNodeWithPointsTo).inferredValue() = bm and
|
||||
bm.getFunction() = this.theCallable()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a call-site from where this function is called */
|
||||
ControlFlowNode getACall() { result = this.theCallable().getACall() }
|
||||
ControlFlowNodeWithPointsTo getACall() { result = this.theCallable().getACall() }
|
||||
|
||||
/** Gets a call-site from where this function is called, given the `context` */
|
||||
ControlFlowNode getACall(Context context) { result = this.theCallable().getACall(context) }
|
||||
ControlFlowNodeWithPointsTo getACall(Context context) {
|
||||
result = this.theCallable().getACall(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `ControlFlowNode` that will be passed as the nth argument to `this` when called at `call`.
|
||||
* This predicate will correctly handle `x.y()`, treating `x` as the zeroth argument.
|
||||
*/
|
||||
ControlFlowNode getArgumentForCall(CallNode call, int n) {
|
||||
ControlFlowNodeWithPointsTo getArgumentForCall(CallNode call, int n) {
|
||||
result = this.theCallable().getArgumentForCall(call, n)
|
||||
}
|
||||
|
||||
@@ -60,7 +65,7 @@ abstract class FunctionObject extends Object {
|
||||
* Gets the `ControlFlowNode` that will be passed as the named argument to `this` when called at `call`.
|
||||
* This predicate will correctly handle `x.y()`, treating `x` as the self argument.
|
||||
*/
|
||||
ControlFlowNode getNamedArgumentForCall(CallNode call, string name) {
|
||||
ControlFlowNodeWithPointsTo getNamedArgumentForCall(CallNode call, string name) {
|
||||
result = this.theCallable().getNamedArgumentForCall(call, name)
|
||||
}
|
||||
|
||||
@@ -134,7 +139,9 @@ class PyFunctionObject extends FunctionObject {
|
||||
override predicate raisesUnknownType() { scope_raises_unknown(this.getFunction()) }
|
||||
|
||||
/** Gets a control flow node corresponding to the value of a return statement */
|
||||
ControlFlowNode getAReturnedNode() { result = this.getFunction().getAReturnValueFlowNode() }
|
||||
ControlFlowNodeWithPointsTo getAReturnedNode() {
|
||||
result = this.getFunction().getAReturnValueFlowNode()
|
||||
}
|
||||
|
||||
override string descriptiveString() {
|
||||
if this.getFunction().isMethod()
|
||||
@@ -216,7 +223,7 @@ abstract class BuiltinCallable extends FunctionObject {
|
||||
|
||||
abstract override string getQualifiedName();
|
||||
|
||||
override ControlFlowNode getArgumentForCall(CallNode call, int n) {
|
||||
override ControlFlowNodeWithPointsTo getArgumentForCall(CallNode call, int n) {
|
||||
call = this.getACall() and result = call.getArg(n)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.types.Builtins
|
||||
private import semmle.python.internal.CachedStages
|
||||
@@ -41,7 +42,7 @@ class Object extends @py_object {
|
||||
* for a control flow node 'f'
|
||||
*/
|
||||
ClassObject getAnInferredType() {
|
||||
exists(ControlFlowNode somewhere | somewhere.refersTo(this, result, _))
|
||||
exists(ControlFlowNodeWithPointsTo somewhere | somewhere.refersTo(this, result, _))
|
||||
or
|
||||
this.asBuiltin().getClass() = result.asBuiltin() and not this = unknownValue()
|
||||
or
|
||||
@@ -327,7 +328,7 @@ abstract class SequenceObject extends Object {
|
||||
Object getInferredElement(int n) {
|
||||
result = this.getBuiltinElement(n)
|
||||
or
|
||||
this.getSourceElement(n).refersTo(result)
|
||||
this.getSourceElement(n).(ControlFlowNodeWithPointsTo).refersTo(result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +439,8 @@ class SuperBoundMethod extends Object {
|
||||
string name;
|
||||
|
||||
SuperBoundMethod() {
|
||||
this.(AttrNode).getObject(name).inferredValue().getClass() = Value::named("super")
|
||||
this.(AttrNode).getObject(name).(ControlFlowNodeWithPointsTo).inferredValue().getClass() =
|
||||
Value::named("super")
|
||||
}
|
||||
|
||||
override string toString() { result = "super()." + name }
|
||||
@@ -446,7 +448,7 @@ class SuperBoundMethod extends Object {
|
||||
Object getFunction(string fname) {
|
||||
fname = name and
|
||||
exists(SuperInstance sup, BoundMethodObjectInternal m |
|
||||
sup = this.(AttrNode).getObject(name).inferredValue() and
|
||||
sup = this.(AttrNode).getObject(name).(ControlFlowNodeWithPointsTo).inferredValue() and
|
||||
sup.attribute(name, m, _) and
|
||||
result = m.getFunction().getSource()
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
/**
|
||||
* A Python property:
|
||||
@@ -77,32 +78,32 @@ class BuiltinPropertyObject extends PropertyObject {
|
||||
}
|
||||
|
||||
private predicate property_getter(CallNode decorated, FunctionObject getter) {
|
||||
decorated.getFunction().refersTo(thePropertyType()) and
|
||||
decorated.getArg(0).refersTo(getter)
|
||||
decorated.getFunction().(ControlFlowNodeWithPointsTo).refersTo(thePropertyType()) and
|
||||
decorated.getArg(0).(ControlFlowNodeWithPointsTo).refersTo(getter)
|
||||
}
|
||||
|
||||
private predicate property_setter(CallNode decorated, FunctionObject setter) {
|
||||
property_getter(decorated, _) and
|
||||
exists(CallNode setter_call, AttrNode prop_setter |
|
||||
prop_setter.getObject("setter").refersTo(decorated)
|
||||
prop_setter.getObject("setter").(ControlFlowNodeWithPointsTo).refersTo(decorated)
|
||||
|
|
||||
setter_call.getArg(0).refersTo(setter) and
|
||||
setter_call.getArg(0).(ControlFlowNodeWithPointsTo).refersTo(setter) and
|
||||
setter_call.getFunction() = prop_setter
|
||||
)
|
||||
or
|
||||
decorated.getFunction().refersTo(thePropertyType()) and
|
||||
decorated.getArg(1).refersTo(setter)
|
||||
decorated.getFunction().(ControlFlowNodeWithPointsTo).refersTo(thePropertyType()) and
|
||||
decorated.getArg(1).(ControlFlowNodeWithPointsTo).refersTo(setter)
|
||||
}
|
||||
|
||||
private predicate property_deleter(CallNode decorated, FunctionObject deleter) {
|
||||
property_getter(decorated, _) and
|
||||
exists(CallNode deleter_call, AttrNode prop_deleter |
|
||||
prop_deleter.getObject("deleter").refersTo(decorated)
|
||||
prop_deleter.getObject("deleter").(ControlFlowNodeWithPointsTo).refersTo(decorated)
|
||||
|
|
||||
deleter_call.getArg(0).refersTo(deleter) and
|
||||
deleter_call.getArg(0).(ControlFlowNodeWithPointsTo).refersTo(deleter) and
|
||||
deleter_call.getFunction() = prop_deleter
|
||||
)
|
||||
or
|
||||
decorated.getFunction().refersTo(thePropertyType()) and
|
||||
decorated.getArg(2).refersTo(deleter)
|
||||
decorated.getFunction().(ControlFlowNodeWithPointsTo).refersTo(thePropertyType()) and
|
||||
decorated.getArg(2).(ControlFlowNodeWithPointsTo).refersTo(deleter)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.types.Object
|
||||
private import semmle.python.types.ClassObject
|
||||
private import semmle.python.types.FunctionObject
|
||||
|
||||
predicate string_attribute_all(ControlFlowNode n, string attr) {
|
||||
predicate string_attribute_all(ControlFlowNodeWithPointsTo n, string attr) {
|
||||
(n.getNode() instanceof Unicode or n.getNode() instanceof Bytes) and
|
||||
attr = "const"
|
||||
or
|
||||
@@ -19,18 +23,27 @@ predicate tracked_object(ControlFlowNode obj, string attr) {
|
||||
tracked_object_any(obj, attr)
|
||||
}
|
||||
|
||||
predicate open_file(Object obj) { obj.(CallNode).getFunction().refersTo(Object::builtin("open")) }
|
||||
predicate open_file(Object obj) {
|
||||
obj.(CallNode).getFunction().(ControlFlowNodeWithPointsTo).refersTo(Object::builtin("open"))
|
||||
}
|
||||
|
||||
predicate string_attribute_any(ControlFlowNode n, string attr) {
|
||||
predicate string_attribute_any(ControlFlowNodeWithPointsTo n, string attr) {
|
||||
attr = "user-input" and
|
||||
exists(Object input | n.(CallNode).getFunction().refersTo(input) |
|
||||
exists(Object input | n.(CallNode).getFunction().(ControlFlowNodeWithPointsTo).refersTo(input) |
|
||||
if major_version() = 2
|
||||
then input = Object::builtin("raw_input")
|
||||
else input = Object::builtin("input")
|
||||
)
|
||||
or
|
||||
attr = "file-input" and
|
||||
exists(Object fd | n.(CallNode).getFunction().(AttrNode).getObject("read").refersTo(fd) |
|
||||
exists(Object fd |
|
||||
n.(CallNode)
|
||||
.getFunction()
|
||||
.(AttrNode)
|
||||
.getObject("read")
|
||||
.(ControlFlowNodeWithPointsTo)
|
||||
.refersTo(fd)
|
||||
|
|
||||
open_file(fd)
|
||||
)
|
||||
or
|
||||
@@ -65,7 +78,7 @@ ControlFlowNode sequence_for_iterator(ControlFlowNode f) {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate tracking_step(ControlFlowNode src, ControlFlowNode dest) {
|
||||
private predicate tracking_step(ControlFlowNode src, ControlFlowNodeWithPointsTo dest) {
|
||||
src = dest.(BinaryExprNode).getAnOperand()
|
||||
or
|
||||
src = dest.(UnaryExprNode).getOperand()
|
||||
|
||||
Reference in New Issue
Block a user