mirror of
https://github.com/github/codeql.git
synced 2025-12-18 01:33:15 +01:00
Merge branch 'master' into python-better-handling-calls-on-edge-of-context
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
|
||||
import python
|
||||
import Undefined
|
||||
|
||||
import semmle.python.pointsto.PointsTo
|
||||
|
||||
predicate uninitialized_local(NameNode use) {
|
||||
exists(FastLocalVariable local |
|
||||
@@ -21,7 +21,7 @@ predicate uninitialized_local(NameNode use) {
|
||||
)
|
||||
and
|
||||
(
|
||||
any(Uninitialized uninit).taints(use)
|
||||
any(Uninitialized uninit).taints(use) and PointsToInternal::reachableBlock(use.getBasicBlock(), _)
|
||||
or
|
||||
not exists(EssaVariable var | var.getASourceUse() = use)
|
||||
)
|
||||
|
||||
@@ -34,7 +34,7 @@ private AstNode toAst(ControlFlowNode n) {
|
||||
class ControlFlowNode extends @py_flow_node {
|
||||
|
||||
cached ControlFlowNode() {
|
||||
not Pruner::unreachable(this)
|
||||
Pruner::reachable(this)
|
||||
}
|
||||
|
||||
/** Whether this control flow node is a load (including those in augmented assignments) */
|
||||
@@ -175,12 +175,13 @@ class ControlFlowNode extends @py_flow_node {
|
||||
|
||||
/** Gets a predecessor of this flow node */
|
||||
ControlFlowNode getAPredecessor() {
|
||||
py_successors(result, this)
|
||||
this = result.getASuccessor()
|
||||
}
|
||||
|
||||
/** Gets a successor of this flow node */
|
||||
ControlFlowNode getASuccessor() {
|
||||
py_successors(this, result)
|
||||
py_successors(this, result) and
|
||||
not Pruner::unreachableEdge(this, result)
|
||||
}
|
||||
|
||||
/** Gets the immediate dominator of this flow node */
|
||||
@@ -291,22 +292,25 @@ class ControlFlowNode extends @py_flow_node {
|
||||
|
||||
/** Gets a successor for this node if the relevant condition is True. */
|
||||
ControlFlowNode getATrueSuccessor() {
|
||||
result = this.getASuccessor() and
|
||||
py_true_successors(this, result)
|
||||
}
|
||||
|
||||
/** Gets a successor for this node if the relevant condition is False. */
|
||||
ControlFlowNode getAFalseSuccessor() {
|
||||
result = this.getASuccessor() and
|
||||
py_false_successors(this, result)
|
||||
}
|
||||
|
||||
/** Gets a successor for this node if an exception is raised. */
|
||||
ControlFlowNode getAnExceptionalSuccessor() {
|
||||
result = this.getASuccessor() and
|
||||
py_exception_successors(this, result)
|
||||
}
|
||||
|
||||
/** Gets a successor for this node if no exception is raised. */
|
||||
ControlFlowNode getANormalSuccessor() {
|
||||
py_successors(this, result) and not
|
||||
result = this.getASuccessor() and not
|
||||
py_exception_successors(this, result)
|
||||
}
|
||||
|
||||
@@ -741,6 +745,8 @@ class DefinitionNode extends ControlFlowNode {
|
||||
exists(Assign a | a.getATarget().(Tuple).getAnElt().getAFlowNode() = this)
|
||||
or
|
||||
exists(Assign a | a.getATarget().(List).getAnElt().getAFlowNode() = this)
|
||||
or
|
||||
exists(For for | for.getTarget().getAFlowNode() = this)
|
||||
}
|
||||
|
||||
/** flow node corresponding to the value assigned for the definition corresponding to this flow node */
|
||||
@@ -860,7 +866,7 @@ class DictNode extends ControlFlowNode {
|
||||
|
||||
}
|
||||
|
||||
private Expr assigned_value(Expr lhs) {
|
||||
private AstNode assigned_value(Expr lhs) {
|
||||
/* lhs = result */
|
||||
exists(Assign a | a.getATarget() = lhs and result = a.getValue())
|
||||
or
|
||||
@@ -877,6 +883,9 @@ private Expr assigned_value(Expr lhs) {
|
||||
lhs = target.getElt(index) and
|
||||
result = values.getElt(index)
|
||||
)
|
||||
or
|
||||
/* for lhs in seq: => `result` is the `for` node, representing the `iter(next(seq))` operation. */
|
||||
result.(For).getTarget() = lhs
|
||||
}
|
||||
|
||||
/** A flow node for a `for` statement. */
|
||||
@@ -946,21 +955,91 @@ predicate defined_by(NameNode def, Variable v) {
|
||||
exists(NameNode p | defined_by(p, v) and p.getASuccessor() = def and not p.defines(v))
|
||||
}
|
||||
|
||||
/** A basic block (ignoring exceptional flow edges to scope exit) */
|
||||
class BasicBlock extends @py_flow_node {
|
||||
/* Combine extractor-generated basic block after pruning */
|
||||
|
||||
BasicBlock() {
|
||||
py_flow_bb_node(_, _, this, _)
|
||||
private class BasicBlockPart extends @py_flow_node {
|
||||
|
||||
string toString() { result = "Basic block part" }
|
||||
|
||||
BasicBlockPart() {
|
||||
py_flow_bb_node(_, _, this, _) and
|
||||
Pruner::reachable(this)
|
||||
}
|
||||
|
||||
predicate isHead() {
|
||||
count(this.(ControlFlowNode).getAPredecessor()) != 1
|
||||
or
|
||||
exists(ControlFlowNode pred | pred = this.(ControlFlowNode).getAPredecessor() | strictcount(pred.getASuccessor()) > 1)
|
||||
}
|
||||
|
||||
private BasicBlockPart previous() {
|
||||
not this.isHead() and
|
||||
py_flow_bb_node(this.(ControlFlowNode).getAPredecessor(), _, result, _)
|
||||
}
|
||||
|
||||
BasicBlockPart getHead() {
|
||||
this.isHead() and result = this
|
||||
or
|
||||
result = this.previous().getHead()
|
||||
}
|
||||
|
||||
predicate isLast() {
|
||||
not exists(BasicBlockPart part | part.previous() = this)
|
||||
}
|
||||
|
||||
int length() {
|
||||
result = max(int j | py_flow_bb_node(_, _, this, j)) + 1
|
||||
}
|
||||
|
||||
int startIndex() {
|
||||
this.isHead() and result = 0
|
||||
or
|
||||
exists(BasicBlockPart prev |
|
||||
prev = this.previous() and
|
||||
result = prev.startIndex() + prev.length()
|
||||
)
|
||||
}
|
||||
|
||||
/** Whether this basic block contains the specified node */
|
||||
predicate contains(ControlFlowNode node) {
|
||||
py_flow_bb_node(node, _, this, _)
|
||||
}
|
||||
|
||||
int indexOf(ControlFlowNode node) {
|
||||
py_flow_bb_node(node, _, this, result)
|
||||
}
|
||||
|
||||
ControlFlowNode lastNode() {
|
||||
this.indexOf(result) = max(this.indexOf(_))
|
||||
}
|
||||
|
||||
BasicBlockPart getImmediateDominator() {
|
||||
result.contains(this.(ControlFlowNode).getImmediateDominator())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A basic block (ignoring exceptional flow edges to scope exit) */
|
||||
class BasicBlock extends @py_flow_node {
|
||||
|
||||
BasicBlock() {
|
||||
this.(BasicBlockPart).isHead()
|
||||
}
|
||||
|
||||
private BasicBlockPart getAPart() {
|
||||
result.getHead() = this
|
||||
}
|
||||
|
||||
/** Whether this basic block contains the specified node */
|
||||
predicate contains(ControlFlowNode node) {
|
||||
this.getAPart().contains(node)
|
||||
}
|
||||
|
||||
/** Gets the nth node in this basic block */
|
||||
ControlFlowNode getNode(int n) {
|
||||
py_flow_bb_node(result, _, this, n)
|
||||
exists(BasicBlockPart part |
|
||||
part = this.getAPart() and
|
||||
n = part.startIndex() + part.indexOf(result)
|
||||
)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
@@ -980,7 +1059,7 @@ class BasicBlock extends @py_flow_node {
|
||||
}
|
||||
|
||||
BasicBlock getImmediateDominator() {
|
||||
this.firstNode().getImmediateDominator().getBasicBlock() = result
|
||||
this.getAPart().getImmediateDominator() = result.getAPart()
|
||||
}
|
||||
|
||||
/** Dominance frontier of a node x is the set of all nodes `other` such that `this` dominates a predecessor
|
||||
@@ -996,9 +1075,10 @@ class BasicBlock extends @py_flow_node {
|
||||
|
||||
/** Gets the last node in this basic block */
|
||||
ControlFlowNode getLastNode() {
|
||||
exists(int i |
|
||||
this.getNode(i) = result and
|
||||
i = max(int j | py_flow_bb_node(_, _, this, j))
|
||||
exists(BasicBlockPart part |
|
||||
part = this.getAPart() and
|
||||
part.isLast() and
|
||||
result = part.lastNode()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -396,16 +396,25 @@ module Pruner {
|
||||
)
|
||||
}
|
||||
|
||||
predicate reachable(UnprunedCfgNode n) {
|
||||
exists(UnprunedBasicBlock bb |
|
||||
reachableBB(bb) and bb.contains(n)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if the basic block `bb` is unreachable due to
|
||||
* one or more constraints.
|
||||
*/
|
||||
predicate unreachableBB(UnprunedBasicBlock bb) {
|
||||
not bb.isEntry() and
|
||||
forall(UnprunedBasicBlock pred |
|
||||
pred.getASuccessor() = bb
|
||||
|
|
||||
unreachableEdge(pred, bb)
|
||||
)
|
||||
not reachableBB(bb)
|
||||
}
|
||||
|
||||
/** Holds if the basic block `bb` is reachable despite
|
||||
* constraints
|
||||
*/
|
||||
predicate reachableBB(UnprunedBasicBlock bb) {
|
||||
bb.isEntry() or
|
||||
reachableEdge(_, bb)
|
||||
}
|
||||
|
||||
Constraint constraintFromTest(SsaVariable var, UnprunedCfgNode node) {
|
||||
@@ -533,18 +542,30 @@ module Pruner {
|
||||
}
|
||||
|
||||
/** Holds if the edge `pred` -> `succ` should be pruned as it cannot be reached */
|
||||
predicate unreachableEdge(UnprunedBasicBlock pred, UnprunedBasicBlock succ) {
|
||||
predicate unreachableEdge(UnprunedCfgNode pred, UnprunedCfgNode succ) {
|
||||
exists(UnprunedBasicBlock predBB, UnprunedBasicBlock succBB |
|
||||
succBB = predBB.getASuccessor() and
|
||||
not reachableEdge(predBB, succBB) and
|
||||
pred = predBB.last() and succ = succBB.first()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if the edge `pred` -> `succ` is reachable as a result of
|
||||
* `pred` being reachable and this edge not being pruned. */
|
||||
predicate reachableEdge(UnprunedBasicBlock pred, UnprunedBasicBlock succ) {
|
||||
reachableBB(pred) and succ = pred.getASuccessor() and
|
||||
not contradictoryEdge(pred, succ) and
|
||||
not simplyDead(pred, succ)
|
||||
}
|
||||
|
||||
predicate contradictoryEdge(UnprunedBasicBlock pred, UnprunedBasicBlock succ) {
|
||||
exists(Constraint pre, Constraint cond |
|
||||
controllingConditions(pred, succ, pre, cond) and
|
||||
contradicts(pre, cond)
|
||||
)
|
||||
or
|
||||
unreachableBB(pred) and succ = pred.getASuccessor()
|
||||
or
|
||||
simply_dead(pred, succ)
|
||||
}
|
||||
|
||||
/* Helper for `unreachableEdge`, deal with inequalities here to avoid blow up */
|
||||
/* Helper for `contradictoryEdge`, deal with inequalities here to avoid blow up */
|
||||
pragma [inline]
|
||||
private predicate contradicts(Constraint a, Constraint b) {
|
||||
a = TIsNone(true) and b.cannotBeNone()
|
||||
@@ -567,13 +588,13 @@ module Pruner {
|
||||
}
|
||||
|
||||
/** Holds if edge is simply dead. Stuff like `if False: ...` */
|
||||
predicate simply_dead(UnprunedBasicBlock pred, UnprunedBasicBlock succ) {
|
||||
predicate simplyDead(UnprunedBasicBlock pred, UnprunedBasicBlock succ) {
|
||||
constTest(pred.last()) = true and pred.getAFalseSuccessor() = succ
|
||||
or
|
||||
constTest(pred.last()) = false and pred.getATrueSuccessor() = succ
|
||||
}
|
||||
|
||||
/* Helper for simply_dead */
|
||||
/* Helper for simplyDead */
|
||||
private boolean constTest(UnprunedCfgNode node) {
|
||||
exists(ImmutableLiteral lit |
|
||||
result = lit.booleanValue() and lit = node.getNode()
|
||||
|
||||
@@ -58,12 +58,10 @@ abstract class PythonSsaSourceVariable extends SsaSourceVariable {
|
||||
or
|
||||
SsaSource::assignment_definition(this, def, _)
|
||||
or
|
||||
SsaSource::multi_assignment_definition(this, def)
|
||||
SsaSource::multi_assignment_definition(this, def, _, _)
|
||||
or
|
||||
SsaSource::deletion_definition(this, def)
|
||||
or
|
||||
SsaSource::iteration_defined_variable(this, def, _)
|
||||
or
|
||||
SsaSource::init_module_submodule_defn(this, def)
|
||||
or
|
||||
SsaSource::parameter_definition(this, def)
|
||||
@@ -381,10 +379,11 @@ cached module SsaSource {
|
||||
}
|
||||
|
||||
/** Holds if `v` is defined by multiple assignment at `defn`. */
|
||||
cached predicate multi_assignment_definition(Variable v, ControlFlowNode defn) {
|
||||
cached predicate multi_assignment_definition(Variable v, ControlFlowNode defn, int n, SequenceNode lhs) {
|
||||
defn.(NameNode).defines(v) and
|
||||
not exists(defn.(DefinitionNode).getValue()) and
|
||||
exists(SequenceNode s | s.getAnElement() = defn)
|
||||
lhs.getElement(n) = defn and
|
||||
lhs.getBasicBlock().dominates(defn.getBasicBlock())
|
||||
}
|
||||
|
||||
/** Holds if `v` is defined by a `for` statement, the definition being `defn` */
|
||||
|
||||
@@ -48,6 +48,9 @@ abstract class CallableObjectInternal extends ObjectInternal {
|
||||
|
||||
override string strValue() { none() }
|
||||
|
||||
/* Callables aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
/** Class representing Python functions */
|
||||
|
||||
@@ -92,6 +92,9 @@ abstract class ClassObjectInternal extends ObjectInternal {
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
/* Classes aren't usually iterable, but can e.g. Enums */
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
}
|
||||
|
||||
/** Class representing Python source classes */
|
||||
|
||||
@@ -85,6 +85,9 @@ private abstract class BooleanObjectInternal extends ConstantObjectInternal {
|
||||
none()
|
||||
}
|
||||
|
||||
/* Booleans aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
private class TrueObjectInternal extends BooleanObjectInternal, TTrue {
|
||||
@@ -167,6 +170,9 @@ private class NoneObjectInternal extends ConstantObjectInternal, TNone {
|
||||
|
||||
override int length() { none() }
|
||||
|
||||
/* None isn't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -205,6 +211,9 @@ private class IntObjectInternal extends ConstantObjectInternal, TInt {
|
||||
|
||||
override int length() { none() }
|
||||
|
||||
/* ints aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
private class FloatObjectInternal extends ConstantObjectInternal, TFloat {
|
||||
@@ -250,6 +259,9 @@ private class FloatObjectInternal extends ConstantObjectInternal, TFloat {
|
||||
|
||||
override int length() { none() }
|
||||
|
||||
/* floats aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -292,6 +304,10 @@ private class UnicodeObjectInternal extends ConstantObjectInternal, TUnicode {
|
||||
result = this.strValue().length()
|
||||
}
|
||||
|
||||
override ObjectInternal getIterNext() {
|
||||
result = TUnknownInstance(this.getClass())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class BytesObjectInternal extends ConstantObjectInternal, TBytes {
|
||||
@@ -333,6 +349,10 @@ private class BytesObjectInternal extends ConstantObjectInternal, TBytes {
|
||||
result = this.strValue().length()
|
||||
}
|
||||
|
||||
override ObjectInternal getIterNext() {
|
||||
result = TUnknownInstance(this.getClass())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -93,6 +93,9 @@ class PropertyInternal extends ObjectInternal, TProperty {
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
/* Properties aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
/** A class representing classmethods in Python */
|
||||
@@ -180,6 +183,9 @@ class ClassMethodObjectInternal extends ObjectInternal, TClassMethod {
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
/* Classmethods aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
|
||||
@@ -253,4 +259,7 @@ class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
/* Staticmethods aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ abstract class InstanceObject extends ObjectInternal {
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
}
|
||||
|
||||
private predicate self_variable_reaching_init_exit(EssaVariable self) {
|
||||
@@ -370,6 +372,8 @@ class UnknownInstanceInternal extends TUnknownInstance, ObjectInternal {
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
}
|
||||
|
||||
private int lengthFromClass(ClassObjectInternal cls) {
|
||||
@@ -478,5 +482,7 @@ class SuperInstance extends TSuperInstance, ObjectInternal {
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,9 @@ abstract class ModuleObjectInternal extends ObjectInternal {
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
/* Modules aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
/** A class representing built-in modules */
|
||||
@@ -412,5 +415,8 @@ class AbsentModuleAttributeObjectInternal extends ObjectInternal, TAbsentModuleA
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
/* Modules aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -169,6 +169,12 @@ class ObjectInternal extends TObject {
|
||||
|
||||
abstract predicate contextSensitiveCallee();
|
||||
|
||||
/** Gets the 'object' resulting from iterating over this object.
|
||||
* Used in the context `for i in this:`. The result is the 'object'
|
||||
* assigned to `i`.
|
||||
*/
|
||||
abstract ObjectInternal getIterNext();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -254,6 +260,8 @@ class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject {
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -333,6 +341,8 @@ class UnknownInternal extends ObjectInternal, TUnknown {
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
}
|
||||
|
||||
class UndefinedInternal extends ObjectInternal, TUndefined {
|
||||
@@ -415,6 +425,8 @@ class UndefinedInternal extends ObjectInternal, TUndefined {
|
||||
* True for most callables. */
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
module ObjectInternal {
|
||||
|
||||
@@ -34,6 +34,8 @@ abstract class SequenceObjectInternal extends ObjectInternal {
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
override ObjectInternal getIterNext() { result = this.getItem(_) }
|
||||
|
||||
}
|
||||
|
||||
abstract class TupleObjectInternal extends SequenceObjectInternal {
|
||||
|
||||
@@ -234,13 +234,21 @@ class ExceptionCapture extends PyNodeDefinition {
|
||||
class MultiAssignmentDefinition extends PyNodeDefinition {
|
||||
|
||||
MultiAssignmentDefinition() {
|
||||
SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode())
|
||||
SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode(), _, _)
|
||||
}
|
||||
|
||||
override string getRepresentation() {
|
||||
result = "..."
|
||||
exists(ControlFlowNode value, int n |
|
||||
this.indexOf(n, value) and
|
||||
result = value.(DefinitionNode).getValue().getNode().toString() + "[" + n + "]"
|
||||
)
|
||||
}
|
||||
|
||||
predicate indexOf(int index, SequenceNode lhs) {
|
||||
SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode(), index, lhs)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -294,21 +302,27 @@ class ParameterDefinition extends PyNodeDefinition {
|
||||
|
||||
}
|
||||
|
||||
/** A definition of a variable in a for loop `for v in ...:` */
|
||||
class IterationDefinition extends PyNodeDefinition {
|
||||
|
||||
ControlFlowNode sequence;
|
||||
private newtype TIterationDefinition =
|
||||
TIterationDefinition_(SsaSourceVariable var, ControlFlowNode def, ControlFlowNode sequence) {
|
||||
SsaSource::iteration_defined_variable(var, def, sequence)
|
||||
}
|
||||
|
||||
IterationDefinition() {
|
||||
SsaSource::iteration_defined_variable(this.getSourceVariable(), this.getDefiningNode(), sequence)
|
||||
/** DEPRECATED. For backwards compatibility only.
|
||||
* A definition of a variable in a for loop `for v in ...:` */
|
||||
deprecated class IterationDefinition extends TIterationDefinition {
|
||||
|
||||
string toString() {
|
||||
result = "IterationDefinition"
|
||||
}
|
||||
|
||||
ControlFlowNode getSequence() {
|
||||
result = sequence
|
||||
this = TIterationDefinition_(_, _, result)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** A deletion of a variable `del v` */
|
||||
class DeletionDefinition extends PyNodeDefinition {
|
||||
|
||||
|
||||
@@ -208,6 +208,8 @@ cached module PointsToInternal {
|
||||
AttributePointsTo::pointsTo(f, context, value, origin)
|
||||
or
|
||||
f.(PointsToExtension).pointsTo(context, value, origin)
|
||||
or
|
||||
iteration_points_to(f, context, value, origin)
|
||||
}
|
||||
|
||||
/** Holds if the attribute `name` is required for `obj`
|
||||
@@ -368,6 +370,20 @@ cached module PointsToInternal {
|
||||
//)
|
||||
}
|
||||
|
||||
/* Treat `ForNode` as intermediate step between sequence and iteration variable.
|
||||
* In otherwords treat `for i in x:` as being equivalent to `i = next(iter(x))`
|
||||
* attaching the value of `next(iter(x))` to the `ForNode`.
|
||||
*/
|
||||
pragma [noinline]
|
||||
private predicate iteration_points_to(ForNode for, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
|
||||
exists(ControlFlowNode seqNode, ObjectInternal seq |
|
||||
for.iterates(_, seqNode) and
|
||||
pointsTo(seqNode, context, seq, _) and
|
||||
value = seq.getIterNext() and
|
||||
origin = for
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if the ESSA definition `def` refers to `(value, origin)` given the context `context`. */
|
||||
private predicate ssa_definition_points_to(EssaDefinition def, PointsToContext context, ObjectInternal value, CfgOrigin origin) {
|
||||
ssa_phi_points_to(def, context, value, origin)
|
||||
@@ -394,6 +410,8 @@ cached module PointsToInternal {
|
||||
or
|
||||
assignment_points_to(def, context, value, origin)
|
||||
or
|
||||
multi_assignment_points_to(def, context, value, origin)
|
||||
or
|
||||
self_parameter_points_to(def, context, value, origin)
|
||||
or
|
||||
delete_points_to(def, context, value, origin)
|
||||
@@ -403,8 +421,6 @@ cached module PointsToInternal {
|
||||
scope_entry_points_to(def, context, value, origin)
|
||||
or
|
||||
InterModulePointsTo::implicit_submodule_points_to(def, value, origin) and context.isImport()
|
||||
or
|
||||
iteration_definition_points_to(def, context, value, origin)
|
||||
/*
|
||||
* No points-to for non-local function entry definitions yet.
|
||||
*/
|
||||
@@ -484,6 +500,16 @@ cached module PointsToInternal {
|
||||
pointsTo(def.getValue(), context, value, origin)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
private predicate multi_assignment_points_to(MultiAssignmentDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
|
||||
exists(int index, ControlFlowNode rhs, SequenceObjectInternal sequence |
|
||||
def.indexOf(index, rhs) and
|
||||
pointsTo(rhs, context, sequence, _) and
|
||||
value = sequence.getItem(index) and
|
||||
origin = def.getDefiningNode()
|
||||
)
|
||||
}
|
||||
|
||||
/** Points-to for deletion: `del name`. */
|
||||
pragma [noinline]
|
||||
private predicate delete_points_to(DeletionDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
|
||||
@@ -563,11 +589,6 @@ cached module PointsToInternal {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate iteration_definition_points_to(IterationDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
|
||||
pointsTo(def.getSequence(), context, ObjectInternal::unknown(), _) and
|
||||
value = ObjectInternal::unknown() and origin = def.getDefiningNode()
|
||||
}
|
||||
|
||||
/** Holds if `f` is an expression node `tval if cond else fval` and points to `(value, origin)`. */
|
||||
private predicate if_exp_points_to(IfExprNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
|
||||
pointsTo(f.getAnOperand(), context, value, origin)
|
||||
|
||||
@@ -68,7 +68,8 @@ abstract class RegexString extends Expr {
|
||||
/** Whether there is a character class, between start (inclusive) and end (exclusive) */
|
||||
predicate charSet(int start, int end) {
|
||||
exists(int inner_start, int inner_end |
|
||||
this.char_set_start(start, inner_start) |
|
||||
this.char_set_start(start, inner_start) and
|
||||
not this.char_set_start(_, start) |
|
||||
end = inner_end + 1 and inner_end > inner_start and
|
||||
this.nonEscapedCharAt(inner_end) = "]" and
|
||||
not exists(int mid | this.nonEscapedCharAt(mid) = "]" |
|
||||
|
||||
@@ -1102,8 +1102,8 @@ library module TaintFlowImplementation {
|
||||
}
|
||||
|
||||
/** Holds if `v` is defined by a `for` statement, the definition being `defn` */
|
||||
cached predicate iteration_step(TaintedNode fromnode, TrackedValue totaint, CallContext tocontext, ControlFlowNode iter) {
|
||||
exists(ForNode for | for.iterates(iter, fromnode.getNode())) and
|
||||
cached predicate iteration_step(TaintedNode fromnode, TrackedValue totaint, CallContext tocontext, ForNode for) {
|
||||
for.iterates(_, fromnode.getNode()) and
|
||||
totaint = TTrackedTaint(fromnode.getTaintKind().getTaintForIteration()) and
|
||||
tocontext = fromnode.getContext()
|
||||
}
|
||||
@@ -1202,9 +1202,6 @@ library module TaintFlowImplementation {
|
||||
tainted_with(def, context, origin)
|
||||
or
|
||||
tainted_exception_capture(def, context, origin)
|
||||
or
|
||||
tainted_iteration(def, context, origin)
|
||||
|
||||
}
|
||||
|
||||
predicate tainted_scope_entry(ScopeEntryDefinition def, CallContext context, TaintedNode origin) {
|
||||
@@ -1407,11 +1404,6 @@ library module TaintFlowImplementation {
|
||||
context = fromnode.getContext()
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
private predicate tainted_iteration(IterationDefinition def, CallContext context, TaintedNode fromnode) {
|
||||
def.getDefiningNode() = fromnode.getNode() and
|
||||
context = fromnode.getContext()
|
||||
}
|
||||
|
||||
/* A call that returns a copy (or similar) of the argument */
|
||||
predicate copyCall(ControlFlowNode fromnode, CallNode tonode) {
|
||||
|
||||
Reference in New Issue
Block a user