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:
Taus
2025-10-29 22:05:43 +00:00
parent 4461be180a
commit fef08afff9
75 changed files with 410 additions and 236 deletions

View File

@@ -10,9 +10,10 @@
*/
import python
private import LegacyPointsTo
from SubscriptNode store
where
store.isStore() and
store.getIndex().pointsTo(Value::named("None"))
store.getIndex().(ControlFlowNodeWithPointsTo).pointsTo(Value::named("None"))
select store

View 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)
)
)
}

View File

@@ -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
)

View File

@@ -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())
}
/**

View File

@@ -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 }

View File

@@ -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 |

View File

@@ -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
)
}

View File

@@ -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
}
}

View File

@@ -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"))

View File

@@ -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 |

View File

@@ -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()
}
}

View File

@@ -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() }
}

View File

@@ -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())
}

View File

@@ -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)
}
}

View File

@@ -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()
)

View File

@@ -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)
}

View File

@@ -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()

View File

@@ -12,6 +12,7 @@
*/
import python
private import LegacyPointsTo
import semmle.python.pointsto.PointsTo
predicate rhs_in_expr(ControlFlowNode rhs, Compare cmp) {
@@ -20,7 +21,8 @@ predicate rhs_in_expr(ControlFlowNode rhs, Compare cmp) {
)
}
from ControlFlowNode non_seq, Compare cmp, Value v, ClassValue cls, ControlFlowNode origin
from
ControlFlowNodeWithPointsTo non_seq, Compare cmp, Value v, ClassValue cls, ControlFlowNode origin
where
rhs_in_expr(non_seq, cmp) and
non_seq.pointsTo(_, v, origin) and

View File

@@ -1,4 +1,5 @@
import python
private import LegacyPointsTo
/** A string constant that looks like it may be used in string formatting operations. */
class PossibleAdvancedFormatString extends StringLiteral {
@@ -98,11 +99,15 @@ private predicate brace_pair(PossibleAdvancedFormatString fmt, int start, int en
private predicate advanced_format_call(Call format_expr, PossibleAdvancedFormatString fmt, int args) {
exists(CallNode call | call = format_expr.getAFlowNode() |
call.getFunction().pointsTo(Value::named("format")) and
call.getArg(0).pointsTo(_, fmt.getAFlowNode()) and
call.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(Value::named("format")) and
call.getArg(0).(ControlFlowNodeWithPointsTo).pointsTo(_, fmt.getAFlowNode()) and
args = count(format_expr.getAnArg()) - 1
or
call.getFunction().(AttrNode).getObject("format").pointsTo(_, fmt.getAFlowNode()) and
call.getFunction()
.(AttrNode)
.getObject("format")
.(ControlFlowNodeWithPointsTo)
.pointsTo(_, fmt.getAFlowNode()) and
args = count(format_expr.getAnArg())
)
}

View File

@@ -12,6 +12,7 @@
*/
import python
private import LegacyPointsTo
/*
* This assumes that any indexing operation where the value is not a sequence or numpy array involves hashing.
@@ -41,13 +42,13 @@ predicate unhashable_subscript(ControlFlowNode f, ClassValue c, ControlFlowNode
is_unhashable(f, c, origin) and
exists(SubscriptNode sub | sub.getIndex() = f |
exists(Value custom_getitem |
sub.getObject().pointsTo(custom_getitem) and
sub.getObject().(ControlFlowNodeWithPointsTo).pointsTo(custom_getitem) and
not has_custom_getitem(custom_getitem)
)
)
}
predicate is_unhashable(ControlFlowNode f, ClassValue cls, ControlFlowNode origin) {
predicate is_unhashable(ControlFlowNodeWithPointsTo f, ClassValue cls, ControlFlowNode origin) {
exists(Value v | f.pointsTo(v, origin) and v.getClass() = cls |
not cls.hasAttribute("__hash__") and not cls.failedInference(_) and cls.isNewStyle()
or

View File

@@ -1,6 +1,7 @@
/** INTERNAL - Helper predicates for queries that inspect the comparison of objects using `is`. */
import python
private import LegacyPointsTo
/** Holds if the comparison `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */
predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) {
@@ -42,7 +43,7 @@ predicate invalid_to_use_is_portably(ClassValue c) {
}
/** Holds if the control flow node `f` points to either `True`, `False`, or `None`. */
predicate simple_constant(ControlFlowNode f) {
predicate simple_constant(ControlFlowNodeWithPointsTo f) {
exists(Value val | f.pointsTo(val) |
val = Value::named("True") or val = Value::named("False") or val = Value::named("None")
)
@@ -84,7 +85,7 @@ predicate universally_interned_constant(Expr e) {
}
private predicate comparison_both_types(Compare comp, Cmpop op, ClassValue cls1, ClassValue cls2) {
exists(ControlFlowNode op1, ControlFlowNode op2 |
exists(ControlFlowNodeWithPointsTo op1, ControlFlowNodeWithPointsTo op2 |
comparison_using_is(comp, op1, op, op2) or comparison_using_is(comp, op2, op, op1)
|
op1.inferredValue().getClass() = cls1 and
@@ -94,7 +95,7 @@ private predicate comparison_both_types(Compare comp, Cmpop op, ClassValue cls1,
private predicate comparison_one_type(Compare comp, Cmpop op, ClassValue cls) {
not comparison_both_types(comp, _, _, _) and
exists(ControlFlowNode operand |
exists(ControlFlowNodeWithPointsTo operand |
comparison_using_is(comp, operand, op, _) or comparison_using_is(comp, _, op, operand)
|
operand.inferredValue().getClass() = cls

View File

@@ -12,6 +12,7 @@
*/
import python
private import LegacyPointsTo
from BinaryExpr div, ControlFlowNode left, ControlFlowNode right
where
@@ -20,9 +21,9 @@ where
exists(BinaryExprNode bin, Value lval, Value rval |
bin = div.getAFlowNode() and
bin.getNode().getOp() instanceof Div and
bin.getLeft().pointsTo(lval, left) and
bin.getLeft().(ControlFlowNodeWithPointsTo).pointsTo(lval, left) and
lval.getClass() = ClassValue::int_() and
bin.getRight().pointsTo(rval, right) and
bin.getRight().(ControlFlowNodeWithPointsTo).pointsTo(rval, right) and
rval.getClass() = ClassValue::int_() and
// Ignore instances where integer division leaves no remainder
not lval.(NumericValue).getIntValue() % rval.(NumericValue).getIntValue() = 0 and

View File

@@ -10,8 +10,9 @@
*/
import python
private import LegacyPointsTo
private import semmle.python.types.Builtins
from CallNode call, ControlFlowNode func
from CallNode call, ControlFlowNodeWithPointsTo func
where major_version() = 2 and call.getFunction() = func and func.pointsTo(Value::named("apply"))
select call, "Call to the obsolete builtin function 'apply'."

View File

@@ -12,6 +12,7 @@
*/
import python
private import LegacyPointsTo
import semmle.python.filters.Tests
from ImportMember im, ModuleValue m, AttrNode store_attr, string name
@@ -23,7 +24,7 @@ where
/* variable resulting from import must have a long lifetime */
not im.getScope() instanceof Function and
store_attr.isStore() and
store_attr.getObject(name).pointsTo(m) and
store_attr.getObject(name).(ControlFlowNodeWithPointsTo).pointsTo(m) and
/* Import not in same module as modification. */
not im.getEnclosingModule() = store_attr.getScope().getEnclosingModule() and
/* Modification is not in a test */

View File

@@ -12,6 +12,7 @@
*/
import python
private import LegacyPointsTo
import semmle.python.filters.Tests
predicate has_string_type(Value v) {
@@ -21,7 +22,7 @@ predicate has_string_type(Value v) {
}
from
For loop, ControlFlowNode iter, Value str, Value seq, ControlFlowNode seq_origin,
For loop, ControlFlowNodeWithPointsTo iter, Value str, Value seq, ControlFlowNode seq_origin,
ControlFlowNode str_origin
where
loop.getIter().getAFlowNode() = iter and

View File

@@ -12,8 +12,11 @@
*/
import python
private import LegacyPointsTo
predicate originIsLocals(ControlFlowNode n) { n.pointsTo(_, _, Value::named("locals").getACall()) }
predicate originIsLocals(ControlFlowNodeWithPointsTo n) {
n.pointsTo(_, _, Value::named("locals").getACall())
}
predicate modification_of_locals(ControlFlowNode f) {
originIsLocals(f.(SubscriptNode).getObject()) and

View File

@@ -12,8 +12,9 @@
*/
import python
private import LegacyPointsTo
from For loop, ControlFlowNode iter, Value v, ClassValue t, ControlFlowNode origin
from For loop, ControlFlowNodeWithPointsTo iter, Value v, ClassValue t, ControlFlowNode origin
where
loop.getIter().getAFlowNode() = iter and
iter.pointsTo(_, v, origin) and

View File

@@ -13,6 +13,7 @@
*/
import python
private import LegacyPointsTo
predicate calls_close(Call c) { exists(Attribute a | c.getFunc() = a and a.getName() = "close") }
@@ -22,7 +23,7 @@ predicate only_stmt_in_finally(Try t, Call c) {
)
}
predicate points_to_context_manager(ControlFlowNode f, ClassValue cls) {
predicate points_to_context_manager(ControlFlowNodeWithPointsTo f, ClassValue cls) {
forex(Value v | f.pointsTo(v) | v.getClass() = cls) and
cls.isContextManager()
}

View File

@@ -11,6 +11,7 @@
*/
import python
private import LegacyPointsTo
predicate string_concat_in_loop(BinaryExpr b) {
b.getOp() instanceof Add and
@@ -19,7 +20,7 @@ predicate string_concat_in_loop(BinaryExpr b) {
|
d.getDefinition().(DefinitionNode).getValue() = add and
u.getAUse() = add.getAnOperand() and
add.getAnOperand().pointsTo().getClass() = ClassValue::str()
add.getAnOperand().(ControlFlowNodeWithPointsTo).pointsTo().getClass() = ClassValue::str()
)
}

View File

@@ -12,9 +12,10 @@
*/
import python
private import LegacyPointsTo
from CallNode call, string name
where call.getFunction().pointsTo(Value::siteQuitter(name))
where call.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(Value::siteQuitter(name))
select call,
"The '" + name +
"' site.Quitter object may not exist if the 'site' module is not loaded or is modified."

View File

@@ -1,9 +1,10 @@
import python
private import LegacyPointsTo
/** Whether `mox` or `.StubOutWithMock()` is used in thin module `m`. */
predicate useOfMoxInModule(Module m) {
exists(ModuleObject mox | mox.getName() = "mox" or mox.getName() = "mox3.mox" |
exists(ControlFlowNode use |
exists(ControlFlowNodeWithPointsTo use |
use.refersTo(mox) and
use.getScope().getEnclosingModule() = m
)

View File

@@ -1,4 +1,5 @@
import python
private import LegacyPointsTo
predicate monkey_patched_builtin(string name) {
exists(AttrNode attr, SubscriptNode subscr, StringLiteral s |
@@ -6,19 +7,19 @@ predicate monkey_patched_builtin(string name) {
subscr.getIndex().getNode() = s and
s.getText() = name and
subscr.getObject() = attr and
attr.getObject("__dict__").pointsTo(Module::builtinModule())
attr.getObject("__dict__").(ControlFlowNodeWithPointsTo).pointsTo(Module::builtinModule())
)
or
exists(CallNode call, ControlFlowNode bltn, StringLiteral s |
exists(CallNode call, ControlFlowNodeWithPointsTo bltn, StringLiteral s |
call.getArg(0) = bltn and
bltn.pointsTo(Module::builtinModule()) and
call.getArg(1).getNode() = s and
s.getText() = name and
call.getFunction().pointsTo(Value::named("setattr"))
call.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(Value::named("setattr"))
)
or
exists(AttrNode attr |
attr.isStore() and
attr.getObject(name).pointsTo(Module::builtinModule())
attr.getObject(name).(ControlFlowNodeWithPointsTo).pointsTo(Module::builtinModule())
)
}

View File

@@ -15,6 +15,7 @@
*/
import python
private import LegacyPointsTo
import Shadowing
import semmle.python.types.Builtins
@@ -35,7 +36,9 @@ predicate shadows(Name d, GlobalVariable g, Function scope, int line) {
/* pytest dynamically populates its namespace so, we cannot look directly for the pytest.fixture function */
AttrNode pytest_fixture_attr() {
exists(ModuleValue pytest | result.getObject("fixture").pointsTo(pytest))
exists(ModuleValue pytest |
result.getObject("fixture").(ControlFlowNodeWithPointsTo).pointsTo(pytest)
)
}
Value pytest_fixture() {
@@ -44,14 +47,15 @@ Value pytest_fixture() {
or
call.getFunction().(CallNode).getFunction() = pytest_fixture_attr()
|
call.pointsTo(result)
call.(ControlFlowNodeWithPointsTo).pointsTo(result)
)
}
/* pytest fixtures require that the parameter name is also a global */
predicate assigned_pytest_fixture(GlobalVariable v) {
exists(NameNode def |
def.defines(v) and def.(DefinitionNode).getValue().pointsTo(pytest_fixture())
def.defines(v) and
def.(DefinitionNode).getValue().(ControlFlowNodeWithPointsTo).pointsTo(pytest_fixture())
)
}

View File

@@ -12,6 +12,7 @@
*/
import python
private import LegacyPointsTo
import Definition
predicate is_increment(Stmt s) {
@@ -55,7 +56,7 @@ predicate points_to_call_to_range(ControlFlowNode f) {
)
or
/* Handle list(range(...)) and list(list(range(...))) */
f.(CallNode).pointsTo().getClass() = ClassValue::list() and
f.(CallNode).(ControlFlowNodeWithPointsTo).pointsTo().getClass() = ClassValue::list() and
points_to_call_to_range(f.(CallNode).getArg(0))
}

View File

@@ -13,6 +13,7 @@
*/
import python
private import LegacyPointsTo
/** Whether name is declared in the __all__ list of this module */
predicate declaredInAll(Module m, StringLiteral name) {
@@ -44,7 +45,7 @@ predicate mutates_globals(ModuleValue m) {
enum_convert = enum_class.attr("_convert") and
exists(CallNode call | call.getScope() = m.getScope() |
enum_convert.getACall() = call or
call.getFunction().pointsTo(enum_convert)
call.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(enum_convert)
)
)
or
@@ -52,7 +53,11 @@ predicate mutates_globals(ModuleValue m) {
// analysis doesn't handle that well enough. So we need a special case for this
not exists(enum_class.attr("_convert")) and
exists(CallNode call | call.getScope() = m.getScope() |
call.getFunction().(AttrNode).getObject(["_convert", "_convert_"]).pointsTo() = enum_class
call.getFunction()
.(AttrNode)
.getObject(["_convert", "_convert_"])
.(ControlFlowNodeWithPointsTo)
.pointsTo() = enum_class
)
)
)
@@ -65,9 +70,9 @@ predicate is_exported_submodule_name(ModuleValue m, string exported_name) {
predicate contains_unknown_import_star(ModuleValue m) {
exists(ImportStarNode imp | imp.getEnclosingModule() = m.getScope() |
imp.getModule().pointsTo().isAbsent()
imp.getModule().(ControlFlowNodeWithPointsTo).pointsTo().isAbsent()
or
not exists(imp.getModule().pointsTo())
not exists(imp.getModule().(ControlFlowNodeWithPointsTo).pointsTo())
)
}

View File

@@ -5,6 +5,7 @@
*/
import python
private import LegacyPointsTo
import analysis.DefinitionTracking
predicate uniqueness_error(int number, string what, string problem) {
@@ -208,18 +209,22 @@ predicate function_object_consistency(string clsname, string problem, string wha
predicate multiple_origins_per_object(Object obj) {
not obj.isC() and
not obj instanceof ModuleObject and
exists(ControlFlowNode use, Context ctx |
exists(ControlFlowNodeWithPointsTo use, Context ctx |
strictcount(ControlFlowNode orig | use.refersTo(ctx, obj, _, orig)) > 1
)
}
predicate intermediate_origins(ControlFlowNode use, ControlFlowNode inter, Object obj) {
predicate intermediate_origins(
ControlFlowNodeWithPointsTo use, ControlFlowNodeWithPointsTo inter, Object obj
) {
exists(ControlFlowNode orig, Context ctx | not inter = orig |
use.refersTo(ctx, obj, _, inter) and
inter.refersTo(ctx, obj, _, orig) and
// It can sometimes happen that two different modules (e.g. cPickle and Pickle)
// have the same attribute, but different origins.
not strictcount(Object val | inter.(AttrNode).getObject().refersTo(val)) > 1
not strictcount(Object val |
inter.(AttrNode).getObject().(ControlFlowNodeWithPointsTo).refersTo(val)
) > 1
)
}

View File

@@ -4,6 +4,7 @@
*/
import python
private import LegacyPointsTo
import semmle.python.pointsto.PointsTo
import semmle.python.pointsto.PointsToContext
@@ -18,11 +19,11 @@ predicate trivial(ControlFlowNode f) {
from int interesting_facts, int interesting_facts_in_source, int total_size, float efficiency
where
interesting_facts =
strictcount(ControlFlowNode f, Object value, ClassObject cls |
strictcount(ControlFlowNodeWithPointsTo f, Object value, ClassObject cls |
f.refersTo(value, cls, _) and not trivial(f)
) and
interesting_facts_in_source =
strictcount(ControlFlowNode f, Object value, ClassObject cls |
strictcount(ControlFlowNodeWithPointsTo f, Object value, ClassObject cls |
f.refersTo(value, cls, _) and
not trivial(f) and
exists(f.getScope().getEnclosingModule().getFile().getRelativePath())

View File

@@ -7,6 +7,7 @@
*/
import python
private import LegacyPointsTo
ImportExpr alternative_import(ImportExpr ie) {
exists(Alias thisalias, Alias otheralias |
@@ -62,7 +63,10 @@ class VersionTest extends ControlFlowNode {
VersionTest() {
exists(string name |
name.matches("%version%") and
this.(CompareNode).getAChild+().pointsTo(Module::named("sys").attr(name))
this.(CompareNode)
.getAChild+()
.(ControlFlowNodeWithPointsTo)
.pointsTo(Module::named("sys").attr(name))
)
}

View File

@@ -9,7 +9,8 @@
*/
import python
private import LegacyPointsTo
from Expr e
where exists(ControlFlowNode f | f = e.getAFlowNode() | not f.refersTo(_))
where exists(ControlFlowNodeWithPointsTo f | f = e.getAFlowNode() | not f.refersTo(_))
select e, "Expression does not 'point-to' any object."

View File

@@ -8,8 +8,9 @@
*/
import python
private import LegacyPointsTo
from ControlFlowNode f, Object o
from ControlFlowNodeWithPointsTo f, Object o
where
f.refersTo(o) and
not f.refersTo(o, _, _)

View File

@@ -1,10 +1,11 @@
import python
private import LegacyPointsTo
from ClassValue cls, string res
where
exists(CallNode call |
call.getFunction().(NameNode).getId() = "test" and
call.getAnArg().pointsTo(cls)
call.getAnArg().(ControlFlowNodeWithPointsTo).pointsTo(cls)
) and
(
cls.isSequence() and

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from int line, ControlFlowNode f, Object o, ControlFlowNode orig
from int line, ControlFlowNodeWithPointsTo f, Object o, ControlFlowNode orig
where
not f.getLocation().getFile().inStdlib() and
f.refersTo(o, orig) and

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from int line, ControlFlowNode f, Object o, ControlFlowNode orig
from int line, ControlFlowNodeWithPointsTo f, Object o, ControlFlowNode orig
where
not f.getLocation().getFile().inStdlib() and
f.refersTo(o, orig) and

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from int line, ControlFlowNode f, Object o, ClassObject cls, ControlFlowNode orig
from int line, ControlFlowNodeWithPointsTo f, Object o, ClassObject cls, ControlFlowNode orig
where
not f.getLocation().getFile().inStdlib() and
f.refersTo(o, cls, orig) and

View File

@@ -1,8 +1,9 @@
import python
private import LegacyPointsTo
string short_loc(Location l) { result = l.getFile().getShortName() + ":" + l.getStartLine() }
from ControlFlowNode use, Object obj, ControlFlowNode orig, int line
from ControlFlowNodeWithPointsTo use, Object obj, ControlFlowNode orig, int line
where
use.refersTo(obj, orig) and
use.getLocation().getFile().getShortName() = "test.py" and

View File

@@ -1,5 +1,6 @@
import python
private import LegacyPointsTo
from ControlFlowNode f, Object o, ControlFlowNode x
from ControlFlowNodeWithPointsTo f, Object o, ControlFlowNode x
where f.refersTo(o, x)
select f.getLocation().getStartLine(), f.toString(), o.toString(), x.getLocation().getStartLine()

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x
from ControlFlowNodeWithPointsTo f, Object o, ClassObject c, ControlFlowNode x
where f.refersTo(o, c, x)
select f.getLocation().getStartLine(), f.toString(), o.toString(), c.toString(),
x.getLocation().getStartLine()

View File

@@ -1,10 +1,11 @@
import python
private import LegacyPointsTo
from ClassValue cls, string res
where
exists(CallNode call |
call.getFunction().(NameNode).getId() = "test" and
call.getAnArg().pointsTo(cls)
call.getAnArg().(ControlFlowNodeWithPointsTo).pointsTo(cls)
) and
(
cls.isSequence() and

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from int line, ControlFlowNode f, Object o, ControlFlowNode orig
from int line, ControlFlowNodeWithPointsTo f, Object o, ControlFlowNode orig
where
not f.getLocation().getFile().inStdlib() and
f.refersTo(o, orig) and

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from int line, ControlFlowNode f, Object o, ClassObject cls, ControlFlowNode orig
from int line, ControlFlowNodeWithPointsTo f, Object o, ClassObject cls, ControlFlowNode orig
where
not f.getLocation().getFile().inStdlib() and
f.refersTo(o, cls, orig) and

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from ControlFlowNode f, Context ctx, Value v, ControlFlowNode origin
from ControlFlowNodeWithPointsTo f, Context ctx, Value v, ControlFlowNode origin
where
f.pointsTo(ctx, v, origin) and
f.getLocation().getFile().getBaseName() = "test.py"

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
import semmle.python.objects.Modules
from Value val, ControlFlowNode f
from Value val, ControlFlowNodeWithPointsTo f
where f.pointsTo(val)
select f, val

View File

@@ -1,5 +1,6 @@
import python
private import LegacyPointsTo
from CallNode call, Value func
where call.getFunction().pointsTo(func)
where call.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(func)
select call.getLocation().getStartLine(), call.toString(), func.toString()

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from int line, ControlFlowNode f, Value v
from int line, ControlFlowNodeWithPointsTo f, Value v
where
any(ExprStmt s).getValue() = f.getNode() and
line = f.getLocation().getStartLine() and

View File

@@ -1,10 +1,11 @@
import python
private import LegacyPointsTo
// We don't care about the internals of functools which vary from
// version to version, just the end result.
from NameNode f, Object o, ControlFlowNode x, int line
where
f.refersTo(o, x) and
f.(ControlFlowNodeWithPointsTo).refersTo(o, x) and
f.getLocation().getFile().getBaseName() = "test.py" and
line = f.getLocation().getStartLine()
select line, f.toString(), o.toString(), x.getLocation().toString()

View File

@@ -1,7 +1,8 @@
import python
private import LegacyPointsTo
import interesting
from int line, ControlFlowNode f, Object o, ImportTimeScope n
from int line, ControlFlowNodeWithPointsTo f, Object o, ImportTimeScope n
where
of_interest(f, line) and
f.refersTo(o) and

View File

@@ -6,10 +6,11 @@
*/
import python
private import LegacyPointsTo
import interesting
import Util
from int line, ControlFlowNode f, Object o
from int line, ControlFlowNodeWithPointsTo f, Object o
where
of_interest(f, line) and
f.refersTo(o)

View File

@@ -1,8 +1,9 @@
import python
private import LegacyPointsTo
import interesting
import Util
from int line, ControlFlowNode f, Object o, ClassObject cls
from int line, ControlFlowNodeWithPointsTo f, Object o, ClassObject cls
where
of_interest(f, line) and
f.refersTo(o, cls, _)

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from ControlFlowNode f, Object o, ControlFlowNode x
from ControlFlowNodeWithPointsTo f, Object o, ControlFlowNode x
where
f.refersTo(o, x) and
exists(CallNode call | call.getFunction().getNode().(Name).getId() = "use" and call.getArg(0) = f)

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x
from ControlFlowNodeWithPointsTo f, Object o, ClassObject c, ControlFlowNode x
where
f.refersTo(o, c, x) and
exists(CallNode call | call.getFunction().getNode().(Name).getId() = "use" and call.getArg(0) = f)

View File

@@ -1,5 +1,6 @@
import python
private import LegacyPointsTo
from ControlFlowNode f, Context ctx, Value v, ControlFlowNode origin
from ControlFlowNodeWithPointsTo f, Context ctx, Value v, ControlFlowNode origin
where f.pointsTo(ctx, v, origin)
select f, ctx, v

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from ControlFlowNode f, Object o, ControlFlowNode x
from ControlFlowNodeWithPointsTo f, Object o, ControlFlowNode x
where
f.refersTo(o, x) and
f.getLocation().getFile().getBaseName() = "test.py"

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x
from ControlFlowNodeWithPointsTo f, Object o, ClassObject c, ControlFlowNode x
where
f.refersTo(o, c, x) and
f.getLocation().getFile().getBaseName() = "test.py"

View File

@@ -1,5 +1,6 @@
import python
private import LegacyPointsTo
from NameNode n, Object value, ClassObject cls
where n.getId() = "self" and n.refersTo(value, cls, _)
where n.getId() = "self" and n.(ControlFlowNodeWithPointsTo).refersTo(value, cls, _)
select n.getNode().getLocation().getStartLine(), value.toString(), cls.toString()

View File

@@ -4,10 +4,11 @@
*/
private import python
private import LegacyPointsTo
import semmle.python.dataflow.new.DataFlow
predicate pointsToOrigin(DataFlow::CfgNode pointer, DataFlow::CfgNode origin) {
origin.getNode() = pointer.getNode().pointsTo().getOrigin()
origin.getNode() = pointer.getNode().(ControlFlowNodeWithPointsTo).pointsTo().getOrigin()
}
module PointsToConfig implements DataFlow::ConfigSig {

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
import Util
from ControlFlowNode f, ControlFlowNode x
from ControlFlowNodeWithPointsTo f, ControlFlowNode x
where f.refersTo(theNoneObject(), _, x)
select locate(f.getLocation(), "abcdghijklmopqr"), f.toString(), x.getLocation().getStartLine()

View File

@@ -1,7 +1,8 @@
import python
private import LegacyPointsTo
import Util
from ControlFlowNode f, Context ctx, Value v, ControlFlowNode origin
from ControlFlowNodeWithPointsTo f, Context ctx, Value v, ControlFlowNode origin
where f.pointsTo(ctx, v, origin)
select locate(f.getLocation(), "abeghijklmnpqrstu"), f.toString(), ctx, vrepr(v),
vrepr(v.getClass())

View File

@@ -1,4 +1,5 @@
import python
private import LegacyPointsTo
import semmle.python.objects.ObjectInternal
string vrepr(Value v) {
@@ -8,6 +9,6 @@ string vrepr(Value v) {
v = ObjectInternal::boundMethod() and result = "builtin-class method"
}
from ControlFlowNode f, Context ctx, Value v, ControlFlowNode origin
from ControlFlowNodeWithPointsTo f, Context ctx, Value v, ControlFlowNode origin
where f.pointsTo(ctx, v, origin)
select f.getLocation(), f.toString(), ctx, vrepr(v), vrepr(v.getClass())

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from ControlFlowNode arg, CallNode call, string debug
from ControlFlowNodeWithPointsTo arg, CallNode call, string debug
where
call.getAnArg() = arg and
call.getFunction().(NameNode).getId() = "check" and

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from ControlFlowNode arg, CallNode call, string debug
from ControlFlowNodeWithPointsTo arg, CallNode call, string debug
where
call.getAnArg() = arg and
call.getFunction().(NameNode).getId() = "check" and

View File

@@ -1,6 +1,7 @@
import python
private import LegacyPointsTo
from ControlFlowNode arg, CallNode call, string debug
from ControlFlowNodeWithPointsTo arg, CallNode call, string debug
where
call.getAnArg() = arg and
call.getFunction().(NameNode).getId() = "check" and

View File

@@ -1,10 +1,11 @@
import python
private import LegacyPointsTo
from NameNode name, CallNode call, string debug
where
call.getAnArg() = name and
call.getFunction().(NameNode).getId() = "check" and
if exists(name.pointsTo())
then debug = name.pointsTo().toString()
if exists(name.(ControlFlowNodeWithPointsTo).pointsTo())
then debug = name.(ControlFlowNodeWithPointsTo).pointsTo().toString()
else debug = "<MISSING pointsTo()>"
select name, debug

View File

@@ -1,11 +1,12 @@
import python
private import LegacyPointsTo
import semmle.python.pointsto.PointsTo
import semmle.python.pointsto.PointsToContext
import semmle.python.objects.ObjectInternal
from CallNode call, SuperInstance sup, BoundMethodObjectInternal bm
where
call.getFunction().inferredValue() = bm and
call.getFunction().(AttrNode).getObject().inferredValue() = sup
call.getFunction().(ControlFlowNodeWithPointsTo).inferredValue() = bm and
call.getFunction().(AttrNode).getObject().(ControlFlowNodeWithPointsTo).inferredValue() = sup
select call.getLocation().getStartLine(), call.toString(),
bm.getFunction().getSource().(FunctionObject).getQualifiedName()

View File

@@ -1,5 +1,6 @@
import python
private import LegacyPointsTo
from StringObject s, ControlFlowNode f
from StringObject s, ControlFlowNodeWithPointsTo f
where f.refersTo(s)
select f.getLocation().toString(), s.getText()

View File

@@ -1,4 +1,5 @@
import python
private import LegacyPointsTo
import semmle.python.dataflow.TaintTracking
class SimpleTest extends TaintKind {
@@ -30,7 +31,7 @@ predicate visit_call(CallNode call, FunctionObject func) {
exists(AttrNode attr, ClassObject cls, string name |
name.matches("visit\\_%") and
func = cls.lookupAttribute(name) and
attr.getObject("visit").refersTo(_, cls, _) and
attr.getObject("visit").(ControlFlowNodeWithPointsTo).refersTo(_, cls, _) and
attr = call.getFunction()
)
}