mirror of
https://github.com/github/codeql.git
synced 2026-02-12 05:01:06 +01:00
Merge remote-tracking branch 'upstream/main' into igfoo/mb
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from Value len, CallNode call
|
||||
where len.getName() = "len" and len.getACall() = call
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from ClassObject sub, ClassObject base
|
||||
where
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from AstNode call, PythonFunctionValue method
|
||||
where
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from FunctionObject m, FunctionObject n
|
||||
where m != n and m.getACallee() = n and n.getACallee() = m
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from FunctionObject override, FunctionObject base
|
||||
where
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from PythonFunctionValue f
|
||||
where f.getACall().getScope() = f.getScope()
|
||||
|
||||
@@ -20,8 +20,21 @@
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.objects.Modules
|
||||
import semmle.python.pointsto.Base
|
||||
import semmle.python.pointsto.Context
|
||||
import semmle.python.pointsto.PointsTo
|
||||
import semmle.python.pointsto.PointsToContext
|
||||
import semmle.python.objects.ObjectAPI
|
||||
import semmle.python.objects.ObjectInternal
|
||||
import semmle.python.types.Object
|
||||
import semmle.python.types.ClassObject
|
||||
import semmle.python.types.FunctionObject
|
||||
import semmle.python.types.ModuleObject
|
||||
import semmle.python.types.Exceptions
|
||||
import semmle.python.types.Properties
|
||||
import semmle.python.types.Descriptors
|
||||
import semmle.python.SelfAttribute
|
||||
import semmle.python.Metrics
|
||||
|
||||
/**
|
||||
* An extension of `ControlFlowNode` that provides points-to predicates.
|
||||
@@ -93,6 +106,24 @@ class ControlFlowNodeWithPointsTo extends ControlFlowNode {
|
||||
// for that variable.
|
||||
exists(SsaVariable v | v.getAUse() = this | varHasCompletePointsToSet(v))
|
||||
}
|
||||
|
||||
/** Whether it is unlikely that this ControlFlowNode can be reached */
|
||||
predicate unlikelyReachable() {
|
||||
not start_bb_likely_reachable(this.getBasicBlock())
|
||||
or
|
||||
exists(BasicBlock b |
|
||||
start_bb_likely_reachable(b) and
|
||||
not end_bb_likely_reachable(b) and
|
||||
// If there is an unlikely successor edge earlier in the BB
|
||||
// than this node, then this node must be unreachable.
|
||||
exists(ControlFlowNode p, int i, int j |
|
||||
p.(RaisingNode).unlikelySuccessor(_) and
|
||||
p = b.getNode(i) and
|
||||
this = b.getNode(j) and
|
||||
i < j
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,6 +152,45 @@ private predicate varHasCompletePointsToSet(SsaVariable var) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate start_bb_likely_reachable(BasicBlock b) {
|
||||
exists(Scope s | s.getEntryNode() = b.getNode(_))
|
||||
or
|
||||
exists(BasicBlock pred |
|
||||
pred = b.getAPredecessor() and
|
||||
end_bb_likely_reachable(pred) and
|
||||
not pred.getLastNode().(RaisingNode).unlikelySuccessor(b)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate end_bb_likely_reachable(BasicBlock b) {
|
||||
start_bb_likely_reachable(b) and
|
||||
not exists(ControlFlowNode p, ControlFlowNode s |
|
||||
p.(RaisingNode).unlikelySuccessor(s) and
|
||||
p = b.getNode(_) and
|
||||
s = b.getNode(_) and
|
||||
not p = b.getLastNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An extension of `BasicBlock` that provides points-to related methods.
|
||||
*/
|
||||
class BasicBlockWithPointsTo extends BasicBlock {
|
||||
/**
|
||||
* Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ.
|
||||
*/
|
||||
predicate unlikelySuccessor(BasicBlockWithPointsTo succ) {
|
||||
this.getLastNode().(RaisingNode).unlikelySuccessor(succ.firstNode())
|
||||
or
|
||||
not end_bb_likely_reachable(this) and succ = this.getASuccessor()
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether (as inferred by type inference) this basic block is likely to be reachable.
|
||||
*/
|
||||
predicate likelyReachable() { start_bb_likely_reachable(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An extension of `Expr` that provides points-to predicates.
|
||||
*/
|
||||
@@ -208,3 +278,155 @@ class ModuleWithPointsTo extends Module {
|
||||
|
||||
override string getAQlClass() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An extension of `Function` that provides points-to related methods.
|
||||
*/
|
||||
class FunctionWithPointsTo extends Function {
|
||||
/** Gets the FunctionObject corresponding to this function */
|
||||
FunctionObject getFunctionObject() { result.getOrigin() = this.getDefinition() }
|
||||
|
||||
override string getAQlClass() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An extension of `Class` that provides points-to related methods.
|
||||
*/
|
||||
class ClassWithPointsTo extends Class {
|
||||
/** Gets the ClassObject corresponding to this class */
|
||||
ClassObject getClassObject() { result.getOrigin() = this.getParent() }
|
||||
|
||||
override string getAQlClass() { none() }
|
||||
}
|
||||
|
||||
/** Gets the `Object` corresponding to the immutable literal `l`. */
|
||||
Object getLiteralObject(ImmutableLiteral l) {
|
||||
l instanceof IntegerLiteral and
|
||||
(
|
||||
py_cobjecttypes(result, theIntType()) and py_cobjectnames(result, l.(Num).getN())
|
||||
or
|
||||
py_cobjecttypes(result, theLongType()) and py_cobjectnames(result, l.(Num).getN())
|
||||
)
|
||||
or
|
||||
l instanceof FloatLiteral and
|
||||
py_cobjecttypes(result, theFloatType()) and
|
||||
py_cobjectnames(result, l.(Num).getN())
|
||||
or
|
||||
l instanceof ImaginaryLiteral and
|
||||
py_cobjecttypes(result, theComplexType()) and
|
||||
py_cobjectnames(result, l.(Num).getN())
|
||||
or
|
||||
l instanceof NegativeIntegerLiteral and
|
||||
(
|
||||
(py_cobjecttypes(result, theIntType()) or py_cobjecttypes(result, theLongType())) and
|
||||
py_cobjectnames(result, "-" + l.(UnaryExpr).getOperand().(IntegerLiteral).getN())
|
||||
)
|
||||
or
|
||||
l instanceof Bytes and
|
||||
py_cobjecttypes(result, theBytesType()) and
|
||||
py_cobjectnames(result, l.(Bytes).quotedString())
|
||||
or
|
||||
l instanceof Unicode and
|
||||
py_cobjecttypes(result, theUnicodeType()) and
|
||||
py_cobjectnames(result, l.(Unicode).quotedString())
|
||||
or
|
||||
l instanceof True and
|
||||
name_consts(l, "True") and
|
||||
result = theTrueObject()
|
||||
or
|
||||
l instanceof False and
|
||||
name_consts(l, "False") and
|
||||
result = theFalseObject()
|
||||
or
|
||||
l instanceof None and
|
||||
name_consts(l, "None") and
|
||||
result = theNoneObject()
|
||||
}
|
||||
|
||||
private predicate gettext_installed() {
|
||||
// Good enough (and fast) approximation
|
||||
exists(Module m | m.getName() = "gettext")
|
||||
}
|
||||
|
||||
private predicate builtin_constant(string name) {
|
||||
exists(Object::builtin(name))
|
||||
or
|
||||
name = "WindowsError"
|
||||
or
|
||||
name = "_" and gettext_installed()
|
||||
}
|
||||
|
||||
/** Whether this name is (almost) always defined, ie. it is a builtin or VM defined name */
|
||||
predicate globallyDefinedName(string name) { builtin_constant(name) or auto_name(name) }
|
||||
|
||||
private predicate auto_name(string name) {
|
||||
name = "__file__" or name = "__builtins__" or name = "__name__"
|
||||
}
|
||||
|
||||
/** An extension of `SsaVariable` that provides points-to related methods. */
|
||||
class SsaVariableWithPointsTo extends SsaVariable {
|
||||
/** Gets an argument of the phi function defining this variable, pruned of unlikely edges. */
|
||||
SsaVariable getAPrunedPhiInput() {
|
||||
result = this.getAPhiInput() and
|
||||
exists(BasicBlock incoming | incoming = this.getPredecessorBlockForPhiArgument(result) |
|
||||
not incoming.getLastNode().(RaisingNode).unlikelySuccessor(this.getDefinition())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the incoming edges for a Phi node, pruned of unlikely edges. */
|
||||
private BasicBlockWithPointsTo getAPrunedPredecessorBlockForPhi() {
|
||||
result = this.getAPredecessorBlockForPhi() and
|
||||
not result.unlikelySuccessor(this.getDefinition().getBasicBlock())
|
||||
}
|
||||
|
||||
private predicate implicitlyDefined() {
|
||||
not exists(this.getDefinition()) and
|
||||
not py_ssa_phi(this, _) and
|
||||
exists(GlobalVariable var | this.getVariable() = var |
|
||||
globallyDefinedName(var.getId())
|
||||
or
|
||||
var.getId() = "__path__" and var.getScope().(Module).isPackageInit()
|
||||
)
|
||||
}
|
||||
|
||||
/** Whether this variable may be undefined */
|
||||
predicate maybeUndefined() {
|
||||
not exists(this.getDefinition()) and not py_ssa_phi(this, _) and not this.implicitlyDefined()
|
||||
or
|
||||
this.getDefinition().isDelete()
|
||||
or
|
||||
exists(SsaVariableWithPointsTo var | var = this.getAPrunedPhiInput() | var.maybeUndefined())
|
||||
or
|
||||
/*
|
||||
* For phi-nodes, there must be a corresponding phi-input for each control-flow
|
||||
* predecessor. Otherwise, the variable will be undefined on that incoming edge.
|
||||
* WARNING: the same phi-input may cover multiple predecessors, so this check
|
||||
* cannot be done by counting.
|
||||
*/
|
||||
|
||||
exists(BasicBlock incoming |
|
||||
reaches_end(incoming) and
|
||||
incoming = this.getAPrunedPredecessorBlockForPhi() and
|
||||
not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming)
|
||||
)
|
||||
}
|
||||
|
||||
override string getAQlClass() { none() }
|
||||
}
|
||||
|
||||
private predicate reaches_end(BasicBlock b) {
|
||||
not exits_early(b) and
|
||||
(
|
||||
/* Entry point */
|
||||
not exists(BasicBlock prev | prev.getASuccessor() = b)
|
||||
or
|
||||
exists(BasicBlock prev | prev.getASuccessor() = b | reaches_end(prev))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exits_early(BasicBlock b) {
|
||||
exists(FunctionObject f |
|
||||
f.neverReturns() and
|
||||
f.getACall().getBasicBlock() = b
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.types.ImportTime
|
||||
import IDEContextual
|
||||
|
||||
private newtype TDefinition =
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Additional models for remote flow sources for `tornado.websocket.WebSocketHandler` have been added.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added taint flow model and type model for `urllib.parseurl`.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
|
||||
* All modules that depend on the points-to analysis have now been removed from the top level `python.qll` module. To access the points-to functionality, import the new `LegacyPointsTo` module. This also means that some predicates have been removed from various classes, for instance `Function.getFunctionObject()`. To access these predicates, import the `LegacyPointsTo` module and use the `FunctionWithPointsTo` class instead. Most cases follow this pattern, but there are a few exceptions:
|
||||
* The `getLiteralObject` method on `ImmutableLiteral` subclasses has been replaced with a predicate `getLiteralObject(ImmutableLiteral l)` in the `LegacyPointsTo` module.
|
||||
* The `getMetrics` method on `Function`, `Class`, and `Module` has been removed. To access metrics, import `LegacyPointsTo` and use the classes `FunctionMetrics`, etc. instead.
|
||||
4
python/ql/lib/change-notes/2025-11-26-socketio.md
Normal file
4
python/ql/lib/change-notes/2025-11-26-socketio.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Remote flow sources for the `python-socketio` package have been modeled.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* The Python extractor now supports template strings as defined in [PEP-750](https://peps.python.org/pep-0750/), through the classes `TemplateString` and `JoinedTemplateString`.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `compression.zstd` library (added in Python 3.14) is now supported by the `py/decompression-bomb` query.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* When a code-scanning configuration specifies the `paths:` and/or `paths-ignore:` settings, these are now taken into account by the Python extractor's search for YAML files.
|
||||
@@ -14,27 +14,27 @@ import semmle.python.Patterns
|
||||
import semmle.python.Keywords
|
||||
import semmle.python.Comprehensions
|
||||
import semmle.python.Flow
|
||||
import semmle.python.Metrics
|
||||
private import semmle.python.Metrics
|
||||
import semmle.python.Constants
|
||||
import semmle.python.Scope
|
||||
import semmle.python.Comment
|
||||
import semmle.python.GuardedControlFlow
|
||||
import semmle.python.types.ImportTime
|
||||
import semmle.python.types.Object
|
||||
import semmle.python.types.ClassObject
|
||||
import semmle.python.types.FunctionObject
|
||||
import semmle.python.types.ModuleObject
|
||||
import semmle.python.types.Version
|
||||
import semmle.python.types.Descriptors
|
||||
private import semmle.python.types.ImportTime
|
||||
private import semmle.python.types.Object
|
||||
private import semmle.python.types.ClassObject
|
||||
private import semmle.python.types.FunctionObject
|
||||
private import semmle.python.types.ModuleObject
|
||||
private import semmle.python.types.Version
|
||||
private import semmle.python.types.Descriptors
|
||||
import semmle.python.SSA
|
||||
import semmle.python.SelfAttribute
|
||||
import semmle.python.types.Properties
|
||||
private import semmle.python.SelfAttribute
|
||||
private import semmle.python.types.Properties
|
||||
import semmle.python.xml.XML
|
||||
import semmle.python.essa.Essa
|
||||
import semmle.python.pointsto.Base
|
||||
import semmle.python.pointsto.Context
|
||||
import semmle.python.pointsto.CallGraph
|
||||
import semmle.python.objects.ObjectAPI
|
||||
private import semmle.python.pointsto.Base
|
||||
private import semmle.python.pointsto.Context
|
||||
private import semmle.python.pointsto.CallGraph
|
||||
private import semmle.python.objects.ObjectAPI
|
||||
import semmle.python.Unit
|
||||
import site
|
||||
private import semmle.python.Overlay
|
||||
|
||||
@@ -218,6 +218,9 @@ class DictItemListParent extends DictItemListParent_ { }
|
||||
/** A list of strings (the primitive type string not Bytes or Unicode) */
|
||||
class StringList extends StringList_ { }
|
||||
|
||||
/** A list of template strings. */
|
||||
class TemplateStringList extends TemplateStringList_ { }
|
||||
|
||||
/** A list of aliases in an import statement */
|
||||
class AliasList extends AliasList_ { }
|
||||
|
||||
@@ -273,3 +276,9 @@ class ParamSpec extends ParamSpec_, TypeParameter {
|
||||
|
||||
override Expr getAChildNode() { result = this.getName() }
|
||||
}
|
||||
|
||||
/** A template string literal. */
|
||||
class TemplateString extends TemplateString_, Expr { }
|
||||
|
||||
/** An (implicitly) concatenated list of template strings. */
|
||||
class JoinedTemplateString extends JoinedTemplateString_, Expr { }
|
||||
|
||||
@@ -768,6 +768,20 @@ class Fstring_ extends @py_Fstring, Expr {
|
||||
override string toString() { result = "Fstring" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `JoinedTemplateString` for further information. */
|
||||
class JoinedTemplateString_ extends @py_JoinedTemplateString, Expr {
|
||||
/** Gets the strings of this joined template string. */
|
||||
TemplateStringList getStrings() { py_TemplateString_lists(result, this) }
|
||||
|
||||
/** Gets the nth string of this joined template string. */
|
||||
TemplateString getString(int index) { result = this.getStrings().getItem(index) }
|
||||
|
||||
/** Gets a string of this joined template string. */
|
||||
TemplateString getAString() { result = this.getStrings().getAnItem() }
|
||||
|
||||
override string toString() { result = "JoinedTemplateString" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `KeyValuePair` for further information. */
|
||||
class KeyValuePair_ extends @py_KeyValuePair, DictItem {
|
||||
/** Gets the location of this key-value pair. */
|
||||
@@ -1373,6 +1387,48 @@ class TemplateDottedNotation_ extends @py_TemplateDottedNotation, Expr {
|
||||
override string toString() { result = "TemplateDottedNotation" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `TemplateString` for further information. */
|
||||
class TemplateString_ extends @py_TemplateString, Expr {
|
||||
/** Gets the prefix of this template string literal. */
|
||||
string getPrefix() { py_strs(result, this, 2) }
|
||||
|
||||
/** Gets the values of this template string literal. */
|
||||
ExprList getValues() { py_expr_lists(result, this, 3) }
|
||||
|
||||
/** Gets the nth value of this template string literal. */
|
||||
Expr getValue(int index) { result = this.getValues().getItem(index) }
|
||||
|
||||
/** Gets a value of this template string literal. */
|
||||
Expr getAValue() { result = this.getValues().getAnItem() }
|
||||
|
||||
override ExprParent getParent() { py_exprs(this, _, result, _) }
|
||||
|
||||
override string toString() { result = "TemplateString" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `TemplateStringPart` for further information. */
|
||||
class TemplateStringPart_ extends @py_TemplateStringPart, Expr {
|
||||
/** Gets the text of this string part of a template string. */
|
||||
string getText() { py_strs(result, this, 2) }
|
||||
|
||||
override string toString() { result = "TemplateStringPart" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `TemplateStringList` for further information. */
|
||||
class TemplateStringList_ extends @py_TemplateString_list {
|
||||
/** Gets a parent of this template string literal list */
|
||||
JoinedTemplateString getParent() { py_TemplateString_lists(this, result) }
|
||||
|
||||
/** Gets an item of this template string literal list */
|
||||
Expr getAnItem() { py_exprs(result, _, this, _) }
|
||||
|
||||
/** Gets the nth item of this template string literal list */
|
||||
Expr getItem(int index) { py_exprs(result, _, this, index) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "TemplateStringList" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `TemplateWrite` for further information. */
|
||||
class TemplateWrite_ extends @py_TemplateWrite, Stmt {
|
||||
/** Gets the value of this template write statement. */
|
||||
|
||||
@@ -141,18 +141,12 @@ class Class extends Class_, Scope, AstNode {
|
||||
/** Gets the metaclass expression */
|
||||
Expr getMetaClass() { result = this.getParent().getMetaClass() }
|
||||
|
||||
/** Gets the ClassObject corresponding to this class */
|
||||
ClassObject getClassObject() { result.getOrigin() = this.getParent() }
|
||||
|
||||
/** Gets the nth base of this class definition. */
|
||||
Expr getBase(int index) { result = this.getParent().getBase(index) }
|
||||
|
||||
/** Gets a base of this class definition. */
|
||||
Expr getABase() { result = this.getParent().getABase() }
|
||||
|
||||
/** Gets the metrics for this class */
|
||||
ClassMetrics getMetrics() { result = this }
|
||||
|
||||
/**
|
||||
* Gets the qualified name for this class.
|
||||
* Should return the same name as the `__qualname__` attribute on classes in Python 3.
|
||||
|
||||
@@ -240,17 +240,12 @@ class Bytes extends StringLiteral {
|
||||
/* syntax: b"hello" */
|
||||
Bytes() { not this.isUnicode() }
|
||||
|
||||
override Object getLiteralObject() {
|
||||
py_cobjecttypes(result, theBytesType()) and
|
||||
py_cobjectnames(result, this.quotedString())
|
||||
}
|
||||
|
||||
/**
|
||||
* The extractor puts quotes into the name of each string (to prevent "0" clashing with 0).
|
||||
* The following predicate help us match up a string/byte literals in the source
|
||||
* which the equivalent object.
|
||||
*/
|
||||
private string quotedString() {
|
||||
string quotedString() {
|
||||
exists(string b_unquoted | b_unquoted = this.getS() | result = "b'" + b_unquoted + "'")
|
||||
}
|
||||
}
|
||||
@@ -266,8 +261,6 @@ class Ellipsis extends Ellipsis_ {
|
||||
* Consists of string (both unicode and byte) literals and numeric literals.
|
||||
*/
|
||||
abstract class ImmutableLiteral extends Expr {
|
||||
abstract Object getLiteralObject();
|
||||
|
||||
abstract boolean booleanValue();
|
||||
}
|
||||
|
||||
@@ -292,12 +285,6 @@ class IntegerLiteral extends Num {
|
||||
|
||||
override string toString() { result = "IntegerLiteral" }
|
||||
|
||||
override Object getLiteralObject() {
|
||||
py_cobjecttypes(result, theIntType()) and py_cobjectnames(result, this.getN())
|
||||
or
|
||||
py_cobjecttypes(result, theLongType()) and py_cobjectnames(result, this.getN())
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
this.getValue() = 0 and result = false
|
||||
or
|
||||
@@ -317,10 +304,6 @@ class FloatLiteral extends Num {
|
||||
|
||||
override string toString() { result = "FloatLiteral" }
|
||||
|
||||
override Object getLiteralObject() {
|
||||
py_cobjecttypes(result, theFloatType()) and py_cobjectnames(result, this.getN())
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
this.getValue() = 0.0 and result = false
|
||||
or
|
||||
@@ -343,10 +326,6 @@ class ImaginaryLiteral extends Num {
|
||||
|
||||
override string toString() { result = "ImaginaryLiteral" }
|
||||
|
||||
override Object getLiteralObject() {
|
||||
py_cobjecttypes(result, theComplexType()) and py_cobjectnames(result, this.getN())
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
this.getValue() = 0.0 and result = false
|
||||
or
|
||||
@@ -365,11 +344,6 @@ class NegativeIntegerLiteral extends ImmutableLiteral, UnaryExpr {
|
||||
|
||||
override boolean booleanValue() { result = this.getOperand().(IntegerLiteral).booleanValue() }
|
||||
|
||||
override Object getLiteralObject() {
|
||||
(py_cobjecttypes(result, theIntType()) or py_cobjecttypes(result, theLongType())) and
|
||||
py_cobjectnames(result, "-" + this.getOperand().(IntegerLiteral).getN())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (integer) value of this constant. Will not return a result if the value does not fit into
|
||||
* a 32 bit signed value
|
||||
@@ -385,11 +359,6 @@ class Unicode extends StringLiteral {
|
||||
/* syntax: "hello" */
|
||||
Unicode() { this.isUnicode() }
|
||||
|
||||
override Object getLiteralObject() {
|
||||
py_cobjecttypes(result, theUnicodeType()) and
|
||||
py_cobjectnames(result, this.quotedString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the quoted representation fo this string.
|
||||
*
|
||||
@@ -593,12 +562,11 @@ class StringLiteral extends Str_, ImmutableLiteral {
|
||||
this.getText() != "" and result = true
|
||||
}
|
||||
|
||||
override Object getLiteralObject() { none() }
|
||||
|
||||
override string toString() { result = "StringLiteral" }
|
||||
}
|
||||
|
||||
private predicate name_consts(Name_ n, string id) {
|
||||
/** Holds if `n` is a named constant (`True`, `False`, or `None`) with name `id`. */
|
||||
predicate name_consts(Name_ n, string id) {
|
||||
exists(Variable v | py_variables(v, n) and id = v.getId() |
|
||||
id = "True" or id = "False" or id = "None"
|
||||
)
|
||||
@@ -627,8 +595,6 @@ class True extends BooleanLiteral {
|
||||
/* syntax: True */
|
||||
True() { name_consts(this, "True") }
|
||||
|
||||
override Object getLiteralObject() { name_consts(this, "True") and result = theTrueObject() }
|
||||
|
||||
override boolean booleanValue() { result = true }
|
||||
}
|
||||
|
||||
@@ -637,8 +603,6 @@ class False extends BooleanLiteral {
|
||||
/* syntax: False */
|
||||
False() { name_consts(this, "False") }
|
||||
|
||||
override Object getLiteralObject() { name_consts(this, "False") and result = theFalseObject() }
|
||||
|
||||
override boolean booleanValue() { result = false }
|
||||
}
|
||||
|
||||
@@ -647,8 +611,6 @@ class None extends NameConstant {
|
||||
/* syntax: None */
|
||||
None() { name_consts(this, "None") }
|
||||
|
||||
override Object getLiteralObject() { name_consts(this, "None") and result = theNoneObject() }
|
||||
|
||||
override boolean booleanValue() { result = false }
|
||||
}
|
||||
|
||||
|
||||
@@ -190,24 +190,6 @@ class ControlFlowNode extends @py_flow_node {
|
||||
/** Whether this node is a normal (non-exceptional) exit */
|
||||
predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) }
|
||||
|
||||
/** Whether it is unlikely that this ControlFlowNode can be reached */
|
||||
predicate unlikelyReachable() {
|
||||
not start_bb_likely_reachable(this.getBasicBlock())
|
||||
or
|
||||
exists(BasicBlock b |
|
||||
start_bb_likely_reachable(b) and
|
||||
not end_bb_likely_reachable(b) and
|
||||
// If there is an unlikely successor edge earlier in the BB
|
||||
// than this node, then this node must be unreachable.
|
||||
exists(ControlFlowNode p, int i, int j |
|
||||
p.(RaisingNode).unlikelySuccessor(_) and
|
||||
p = b.getNode(i) and
|
||||
this = b.getNode(j) and
|
||||
i < j
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Whether this strictly dominates other. */
|
||||
pragma[inline]
|
||||
predicate strictlyDominates(ControlFlowNode other) {
|
||||
@@ -901,6 +883,58 @@ class StarredNode extends ControlFlowNode {
|
||||
ControlFlowNode getValue() { toAst(result) = toAst(this).(Starred).getValue() }
|
||||
}
|
||||
|
||||
/** The ControlFlowNode for an 'except' statement. */
|
||||
class ExceptFlowNode extends ControlFlowNode {
|
||||
ExceptFlowNode() { this.getNode() instanceof ExceptStmt }
|
||||
|
||||
/**
|
||||
* Gets the type handled by this exception handler.
|
||||
* `ExceptionType` in `except ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getType() {
|
||||
exists(ExceptStmt ex |
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
ex = this.getNode() and
|
||||
result = ex.getType().getAFlowNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name assigned to the handled exception, if any.
|
||||
* `e` in `except ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getName() {
|
||||
exists(ExceptStmt ex |
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
ex = this.getNode() and
|
||||
result = ex.getName().getAFlowNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The ControlFlowNode for an 'except*' statement. */
|
||||
class ExceptGroupFlowNode extends ControlFlowNode {
|
||||
ExceptGroupFlowNode() { this.getNode() instanceof ExceptGroupStmt }
|
||||
|
||||
/**
|
||||
* Gets the type handled by this exception handler.
|
||||
* `ExceptionType` in `except* ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getType() {
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
result = this.getNode().(ExceptGroupStmt).getType().getAFlowNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name assigned to the handled exception, if any.
|
||||
* `e` in `except* ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getName() {
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
result = this.getNode().(ExceptGroupStmt).getName().getAFlowNode()
|
||||
}
|
||||
}
|
||||
|
||||
private module Scopes {
|
||||
private predicate fast_local(NameNode n) {
|
||||
exists(FastLocalVariable v |
|
||||
@@ -1004,7 +1038,8 @@ class BasicBlock extends @py_flow_node {
|
||||
)
|
||||
}
|
||||
|
||||
private ControlFlowNode firstNode() { result = this }
|
||||
/** Gets the first node in this basic block */
|
||||
ControlFlowNode firstNode() { result = this }
|
||||
|
||||
/** Gets the last node in this basic block */
|
||||
ControlFlowNode getLastNode() {
|
||||
@@ -1093,15 +1128,6 @@ class BasicBlock extends @py_flow_node {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ.
|
||||
*/
|
||||
predicate unlikelySuccessor(BasicBlock succ) {
|
||||
this.getLastNode().(RaisingNode).unlikelySuccessor(succ.firstNode())
|
||||
or
|
||||
not end_bb_likely_reachable(this) and succ = this.getASuccessor()
|
||||
}
|
||||
|
||||
/** Holds if this basic block strictly reaches the other. Is the start of other reachable from the end of this. */
|
||||
cached
|
||||
predicate strictlyReaches(BasicBlock other) {
|
||||
@@ -1112,11 +1138,6 @@ class BasicBlock extends @py_flow_node {
|
||||
/** Holds if this basic block reaches the other. Is the start of other reachable from the end of this. */
|
||||
predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) }
|
||||
|
||||
/**
|
||||
* Whether (as inferred by type inference) this basic block is likely to be reachable.
|
||||
*/
|
||||
predicate likelyReachable() { start_bb_likely_reachable(this) }
|
||||
|
||||
/**
|
||||
* Gets the `ConditionBlock`, if any, that controls this block and
|
||||
* does not control any other `ConditionBlock`s that control this block.
|
||||
@@ -1144,26 +1165,6 @@ class BasicBlock extends @py_flow_node {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate start_bb_likely_reachable(BasicBlock b) {
|
||||
exists(Scope s | s.getEntryNode() = b.getNode(_))
|
||||
or
|
||||
exists(BasicBlock pred |
|
||||
pred = b.getAPredecessor() and
|
||||
end_bb_likely_reachable(pred) and
|
||||
not pred.getLastNode().(RaisingNode).unlikelySuccessor(b)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate end_bb_likely_reachable(BasicBlock b) {
|
||||
start_bb_likely_reachable(b) and
|
||||
not exists(ControlFlowNode p, ControlFlowNode s |
|
||||
p.(RaisingNode).unlikelySuccessor(s) and
|
||||
p = b.getNode(_) and
|
||||
s = b.getNode(_) and
|
||||
not p = b.getLastNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class ControlFlowNodeAlias = ControlFlowNode;
|
||||
|
||||
final private class FinalBasicBlock = BasicBlock;
|
||||
|
||||
@@ -78,6 +78,7 @@ private import semmle.python.frameworks.Sanic
|
||||
private import semmle.python.frameworks.ServerLess
|
||||
private import semmle.python.frameworks.Setuptools
|
||||
private import semmle.python.frameworks.Simplejson
|
||||
private import semmle.python.frameworks.Socketio
|
||||
private import semmle.python.frameworks.SqlAlchemy
|
||||
private import semmle.python.frameworks.Starlette
|
||||
private import semmle.python.frameworks.Stdlib
|
||||
|
||||
@@ -84,12 +84,6 @@ class Function extends Function_, Scope, AstNode {
|
||||
/** Gets the name used to define this function */
|
||||
override string getName() { result = Function_.super.getName() }
|
||||
|
||||
/** Gets the metrics for this function */
|
||||
FunctionMetrics getMetrics() { result = this }
|
||||
|
||||
/** Gets the FunctionObject corresponding to this function */
|
||||
FunctionObject getFunctionObject() { result.getOrigin() = this.getDefinition() }
|
||||
|
||||
/**
|
||||
* Whether this function is a procedure, that is, it has no explicit return statement and always returns None.
|
||||
* Note that generator and async functions are not procedures as they return generators and coroutines respectively.
|
||||
|
||||
@@ -29,9 +29,9 @@ class FunctionMetrics extends Function {
|
||||
*/
|
||||
int getCyclomaticComplexity() {
|
||||
exists(int e, int n |
|
||||
n = count(BasicBlock b | b = this.getABasicBlock() and b.likelyReachable()) and
|
||||
n = count(BasicBlockWithPointsTo b | b = this.getABasicBlock() and b.likelyReachable()) and
|
||||
e =
|
||||
count(BasicBlock b1, BasicBlock b2 |
|
||||
count(BasicBlockWithPointsTo b1, BasicBlockWithPointsTo b2 |
|
||||
b1 = this.getABasicBlock() and
|
||||
b1.likelyReachable() and
|
||||
b2 = this.getABasicBlock() and
|
||||
|
||||
@@ -86,9 +86,6 @@ class Module extends Module_, Scope, AstNode {
|
||||
result = this.getName().regexpReplaceAll("\\.[^.]*$", "")
|
||||
}
|
||||
|
||||
/** Gets the metrics for this module */
|
||||
ModuleMetrics getMetrics() { result = this }
|
||||
|
||||
string getAnImportedModuleName() {
|
||||
exists(Import i | i.getEnclosingModule() = this | result = i.getAnImportedModuleName())
|
||||
or
|
||||
|
||||
@@ -61,14 +61,6 @@ class SsaVariable extends @py_ssa_var {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets an argument of the phi function defining this variable, pruned of unlikely edges. */
|
||||
SsaVariable getAPrunedPhiInput() {
|
||||
result = this.getAPhiInput() and
|
||||
exists(BasicBlock incoming | incoming = this.getPredecessorBlockForPhiArgument(result) |
|
||||
not incoming.getLastNode().(RaisingNode).unlikelySuccessor(this.getDefinition())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a variable that ultimately defines this variable and is not itself defined by another variable */
|
||||
SsaVariable getAnUltimateDefinition() {
|
||||
result = this and not exists(this.getAPhiInput())
|
||||
@@ -85,17 +77,11 @@ class SsaVariable extends @py_ssa_var {
|
||||
string getId() { result = this.getVariable().getId() }
|
||||
|
||||
/** Gets the incoming edges for a Phi node. */
|
||||
private BasicBlock getAPredecessorBlockForPhi() {
|
||||
BasicBlock getAPredecessorBlockForPhi() {
|
||||
exists(this.getAPhiInput()) and
|
||||
result.getASuccessor() = this.getDefinition().getBasicBlock()
|
||||
}
|
||||
|
||||
/** Gets the incoming edges for a Phi node, pruned of unlikely edges. */
|
||||
private BasicBlock getAPrunedPredecessorBlockForPhi() {
|
||||
result = this.getAPredecessorBlockForPhi() and
|
||||
not result.unlikelySuccessor(this.getDefinition().getBasicBlock())
|
||||
}
|
||||
|
||||
/** Whether it is possible to reach a use of this variable without passing a definition */
|
||||
predicate reachableWithoutDefinition() {
|
||||
not exists(this.getDefinition()) and not py_ssa_phi(this, _)
|
||||
@@ -115,38 +101,6 @@ class SsaVariable extends @py_ssa_var {
|
||||
)
|
||||
}
|
||||
|
||||
/** Whether this variable may be undefined */
|
||||
predicate maybeUndefined() {
|
||||
not exists(this.getDefinition()) and not py_ssa_phi(this, _) and not this.implicitlyDefined()
|
||||
or
|
||||
this.getDefinition().isDelete()
|
||||
or
|
||||
exists(SsaVariable var | var = this.getAPrunedPhiInput() | var.maybeUndefined())
|
||||
or
|
||||
/*
|
||||
* For phi-nodes, there must be a corresponding phi-input for each control-flow
|
||||
* predecessor. Otherwise, the variable will be undefined on that incoming edge.
|
||||
* WARNING: the same phi-input may cover multiple predecessors, so this check
|
||||
* cannot be done by counting.
|
||||
*/
|
||||
|
||||
exists(BasicBlock incoming |
|
||||
reaches_end(incoming) and
|
||||
incoming = this.getAPrunedPredecessorBlockForPhi() and
|
||||
not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate implicitlyDefined() {
|
||||
not exists(this.getDefinition()) and
|
||||
not py_ssa_phi(this, _) and
|
||||
exists(GlobalVariable var | this.getVariable() = var |
|
||||
globallyDefinedName(var.getId())
|
||||
or
|
||||
var.getId() = "__path__" and var.getScope().(Module).isPackageInit()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the global variable that is accessed if this local is undefined.
|
||||
* Only applies to local variables in class scopes.
|
||||
@@ -173,43 +127,6 @@ class SsaVariable extends @py_ssa_var {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate reaches_end(BasicBlock b) {
|
||||
not exits_early(b) and
|
||||
(
|
||||
/* Entry point */
|
||||
not exists(BasicBlock prev | prev.getASuccessor() = b)
|
||||
or
|
||||
exists(BasicBlock prev | prev.getASuccessor() = b | reaches_end(prev))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exits_early(BasicBlock b) {
|
||||
exists(FunctionObject f |
|
||||
f.neverReturns() and
|
||||
f.getACall().getBasicBlock() = b
|
||||
)
|
||||
}
|
||||
|
||||
private predicate gettext_installed() {
|
||||
// Good enough (and fast) approximation
|
||||
exists(Module m | m.getName() = "gettext")
|
||||
}
|
||||
|
||||
private predicate builtin_constant(string name) {
|
||||
exists(Object::builtin(name))
|
||||
or
|
||||
name = "WindowsError"
|
||||
or
|
||||
name = "_" and gettext_installed()
|
||||
}
|
||||
|
||||
private predicate auto_name(string name) {
|
||||
name = "__file__" or name = "__builtins__" or name = "__name__"
|
||||
}
|
||||
|
||||
/** Whether this name is (almost) always defined, ie. it is a builtin or VM defined name */
|
||||
predicate globallyDefinedName(string name) { builtin_constant(name) or auto_name(name) }
|
||||
|
||||
/** An SSA variable that is backed by a global variable */
|
||||
class GlobalSsaVariable extends EssaVariable {
|
||||
GlobalSsaVariable() { this.getSourceVariable() instanceof GlobalVariable }
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import python
|
||||
private import semmle.python.pointsto.Filters
|
||||
private import LegacyPointsTo
|
||||
|
||||
/**
|
||||
* An attribute access where the left hand side of the attribute expression
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/** This module provides an API for attribute reads and writes. */
|
||||
|
||||
private import python
|
||||
import DataFlowUtil
|
||||
import DataFlowPublic
|
||||
private import DataFlowPrivate
|
||||
private import semmle.python.types.Builtins
|
||||
private import semmle.python.dataflow.new.internal.Builtins
|
||||
|
||||
/**
|
||||
* A data flow node that reads or writes an attribute of an object.
|
||||
@@ -134,8 +135,12 @@ private class BuiltInCallNode extends CallNode {
|
||||
|
||||
BuiltInCallNode() {
|
||||
// TODO disallow instances where the name of the built-in may refer to an in-scope variable of that name.
|
||||
exists(NameNode id | this.getFunction() = id and id.getId() = name and id.isGlobal()) and
|
||||
name = any(Builtin b).getName()
|
||||
exists(NameNode id |
|
||||
name = Builtins::getBuiltinName() and
|
||||
this.getFunction() = id and
|
||||
id.getId() = name and
|
||||
id.isGlobal()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the name of the built-in function that is called at this `CallNode` */
|
||||
|
||||
@@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.dataflow.new.internal.ImportStar
|
||||
private import semmle.python.dataflow.new.TypeTracking
|
||||
private import semmle.python.dataflow.new.internal.DataFlowPrivate
|
||||
private import semmle.python.essa.SsaDefinitions
|
||||
|
||||
/**
|
||||
* Python modules and the way imports are resolved are... complicated. Here's a crash course in how
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import python
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.dataflow.Implementation
|
||||
|
||||
module TaintTracking {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
class OpenFile extends TaintKind {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.Filters as Filters
|
||||
import semmle.python.dataflow.Legacy
|
||||
|
||||
@@ -257,7 +256,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
|
||||
TaintKind kind, string edgeLabel
|
||||
) {
|
||||
this.unprunedStep(src, node, context, path, kind, edgeLabel) and
|
||||
node.getBasicBlock().likelyReachable() and
|
||||
node.getBasicBlock().(BasicBlockWithPointsTo).likelyReachable() and
|
||||
not super.isBarrier(node) and
|
||||
(
|
||||
not path = TNoAttribute()
|
||||
@@ -685,7 +684,9 @@ private class EssaTaintTracking extends string instanceof TaintTracking::Configu
|
||||
TaintTrackingNode src, PhiFunction defn, TaintTrackingContext context, AttributePath path,
|
||||
TaintKind kind
|
||||
) {
|
||||
exists(DataFlow::Node srcnode, BasicBlock pred, EssaVariable predvar, DataFlow::Node phi |
|
||||
exists(
|
||||
DataFlow::Node srcnode, BasicBlockWithPointsTo pred, EssaVariable predvar, DataFlow::Node phi
|
||||
|
|
||||
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
|
||||
defn = phi.asVariable().getDefinition() and
|
||||
predvar = defn.getInput(pred) and
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import LegacyPointsTo
|
||||
|
||||
/** A state that should be tracked. */
|
||||
abstract class TrackableState extends string {
|
||||
|
||||
@@ -89,7 +89,6 @@
|
||||
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
|
||||
import semmle.python.dataflow.Configuration
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import semmle.python.dependencies.Dependencies
|
||||
private import LegacyPointsTo
|
||||
|
||||
/**
|
||||
* A library describing an abstract mechanism for representing dependency categories.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import python
|
||||
import semmle.python.dependencies.Dependencies
|
||||
import semmle.python.dependencies.DependencyKind
|
||||
private import LegacyPointsTo
|
||||
|
||||
/**
|
||||
* Combine the source-file and package into a single string:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import python
|
||||
|
||||
/*
|
||||
* Classification of variables. These should be non-overlapping and complete.
|
||||
*
|
||||
@@ -12,6 +11,9 @@ import python
|
||||
* Escaping globals -- Global variables that have definitions and at least one of those definitions is in another scope.
|
||||
*/
|
||||
|
||||
private import semmle.python.types.ImportTime
|
||||
private import semmle.python.essa.SsaDefinitions
|
||||
|
||||
/** A source language variable, to be converted into a set of SSA variables. */
|
||||
abstract class SsaSourceVariable extends @py_variable {
|
||||
SsaSourceVariable() {
|
||||
@@ -274,6 +276,17 @@ class ModuleVariable extends SsaSourceVariable instanceof GlobalVariable {
|
||||
override CallNode redefinedAtCallSite() { none() }
|
||||
}
|
||||
|
||||
/** Holds if `f` is an import of the form `from .[...] import ...` and the enclosing scope is an __init__ module */
|
||||
private predicate import_from_dot_in_init(ImportExprNode f) {
|
||||
f.getScope() = any(Module m).getInitModule() and
|
||||
(
|
||||
f.getNode().getLevel() = 1 and
|
||||
not exists(f.getNode().getName())
|
||||
or
|
||||
f.getNode().getImportedModuleName() = f.getEnclosingModule().getPackage().getName()
|
||||
)
|
||||
}
|
||||
|
||||
class NonEscapingGlobalVariable extends ModuleVariable {
|
||||
NonEscapingGlobalVariable() {
|
||||
this instanceof GlobalVariable and
|
||||
|
||||
@@ -6,6 +6,7 @@ import python
|
||||
private import SsaCompute
|
||||
import semmle.python.essa.Definitions
|
||||
private import semmle.python.internal.CachedStages
|
||||
private import semmle.python.essa.SsaDefinitions
|
||||
|
||||
/** An (enhanced) SSA variable derived from `SsaSourceVariable`. */
|
||||
class EssaVariable extends TEssaDefinition {
|
||||
|
||||
@@ -6,6 +6,13 @@
|
||||
import python
|
||||
private import semmle.python.internal.CachedStages
|
||||
|
||||
/** Hold if `expr` is a test (a branch) and `use` is within that test */
|
||||
predicate test_contains(ControlFlowNode expr, ControlFlowNode use) {
|
||||
expr.getNode() instanceof Expr and
|
||||
expr.isBranch() and
|
||||
expr.getAChild*() = use
|
||||
}
|
||||
|
||||
cached
|
||||
module SsaSource {
|
||||
/** Holds if `v` is used as the receiver in a method call. */
|
||||
|
||||
119
python/ql/lib/semmle/python/frameworks/Socketio.qll
Normal file
119
python/ql/lib/semmle/python/frameworks/Socketio.qll
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Provides definitions and modeling for the `python-socketio` PyPI package.
|
||||
* See https://python-socketio.readthedocs.io/en/stable/.
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.TaintTracking
|
||||
private import semmle.python.dataflow.new.RemoteFlowSources
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
private import semmle.python.frameworks.internal.PoorMansFunctionResolution
|
||||
|
||||
/**
|
||||
* Provides models for the `python-socketio` PyPI package.
|
||||
* See https://python-socketio.readthedocs.io/en/stable/.
|
||||
*/
|
||||
module SocketIO {
|
||||
/** Provides models for socketio `Server` and `AsyncServer` classes. */
|
||||
module Server {
|
||||
/** Gets an instance of a socketio `Server` or `AsyncServer`. */
|
||||
API::Node server() {
|
||||
result = API::moduleImport("socketio").getMember(["Server", "AsyncServer"]).getAnInstance()
|
||||
}
|
||||
|
||||
/** Gets a decorator that indicates a socketio event handler. */
|
||||
private API::Node serverEventAnnotation() {
|
||||
result = server().getMember("event")
|
||||
or
|
||||
result = server().getMember("on").getReturn()
|
||||
}
|
||||
|
||||
private class EventHandler extends Http::Server::RequestHandler::Range {
|
||||
EventHandler() {
|
||||
serverEventAnnotation().getAValueReachableFromSource().asExpr() = this.getADecorator()
|
||||
or
|
||||
exists(DataFlow::CallCfgNode c, DataFlow::Node arg |
|
||||
c = server().getMember("on").getACall()
|
||||
|
|
||||
(
|
||||
arg = c.getArg(1)
|
||||
or
|
||||
arg = c.getArgByName("handler")
|
||||
) and
|
||||
poorMansFunctionTracker(this) = arg
|
||||
)
|
||||
}
|
||||
|
||||
override Parameter getARoutedParameter() {
|
||||
result = this.getAnArg() and
|
||||
not result = this.getArg(0) // First parameter is `sid`, which is not a remote flow source as it cannot be controlled by the client.
|
||||
}
|
||||
|
||||
override string getFramework() { result = "socketio" }
|
||||
}
|
||||
|
||||
private class CallbackArgument extends DataFlow::Node {
|
||||
CallbackArgument() {
|
||||
exists(DataFlow::CallCfgNode c |
|
||||
c = [server(), Namespace::instance()].getMember(["emit", "send"]).getACall()
|
||||
|
|
||||
this = c.getArgByName("callback")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class CallbackHandler extends Http::Server::RequestHandler::Range {
|
||||
CallbackHandler() { any(CallbackArgument ca) = poorMansFunctionTracker(this) }
|
||||
|
||||
override Parameter getARoutedParameter() { result = this.getAnArg() }
|
||||
|
||||
override string getFramework() { result = "socketio" }
|
||||
}
|
||||
|
||||
private class SocketIOCall extends RemoteFlowSource::Range {
|
||||
SocketIOCall() { this = [server(), Namespace::instance()].getMember("call").getACall() }
|
||||
|
||||
override string getSourceType() { result = "socketio call" }
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides modeling for socketio server Namespace/AsyncNamespace classes. */
|
||||
module Namespace {
|
||||
/** Gets a reference to the `socketio.Namespace` or `socketio.AsyncNamespace` classes or any subclass. */
|
||||
API::Node subclassRef() {
|
||||
result =
|
||||
API::moduleImport("socketio").getMember(["Namespace", "AsyncNamespace"]).getASubclass*()
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of a subclass of `socketio.Namespace` or `socketio.AsyncNamespace`. */
|
||||
API::Node instance() {
|
||||
result = subclassRef().getAnInstance()
|
||||
or
|
||||
result = subclassRef().getAMember().getSelfParameter()
|
||||
}
|
||||
|
||||
/** A socketio Namespace class. */
|
||||
class NamespaceClass extends Class {
|
||||
NamespaceClass() { this.getABase() = subclassRef().asSource().asExpr() }
|
||||
|
||||
/** Gets a handler for socketio events. */
|
||||
Function getAnEventHandler() {
|
||||
result = this.getAMethod() and
|
||||
result.getName().matches("on_%")
|
||||
}
|
||||
}
|
||||
|
||||
private class NamespaceEventHandler extends Http::Server::RequestHandler::Range {
|
||||
NamespaceEventHandler() { this = any(NamespaceClass nc).getAnEventHandler() }
|
||||
|
||||
override Parameter getARoutedParameter() {
|
||||
result = this.getAnArg() and
|
||||
not result = this.getArg(0) and
|
||||
not result = this.getArg(1) // First 2 parameters are `self` and `sid`.
|
||||
}
|
||||
|
||||
override string getFramework() { result = "socketio" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,6 +142,8 @@ extensions:
|
||||
- ["typing", "Member[cast]", "Argument[1,val:]", "ReturnValue", "value"]
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.parse_qs
|
||||
- ["urllib", "Member[parse].Member[parse_qs]", "Argument[0,qs:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlparse
|
||||
- ["urllib", "Member[parse].Member[urlparse]", "Argument[0,urlstring:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.quote
|
||||
- ["urllib", "Member[parse].Member[quote]", "Argument[0,string:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.quote_plus
|
||||
@@ -181,7 +183,9 @@ extensions:
|
||||
- addsTo:
|
||||
pack: codeql/python-all
|
||||
extensible: typeModel
|
||||
data: []
|
||||
data:
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlparse
|
||||
- ["urllib.parse.ParseResult~Subclass", 'urllib', 'Member[parse].Member[urlparse]']
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/python-all
|
||||
|
||||
@@ -245,6 +245,67 @@ module Stdlib {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides models for the `urllib.parse.ParseResult` class
|
||||
*
|
||||
* See https://docs.python.org/3.9/library/urllib.parse.html#urllib.parse.ParseResult.
|
||||
*/
|
||||
module ParseResult {
|
||||
/** Gets a reference to the `urllib.parse.ParseResult` class. */
|
||||
API::Node classRef() {
|
||||
result = API::moduleImport("urllib").getMember("parse").getMember("ParseResult")
|
||||
or
|
||||
result = ModelOutput::getATypeNode("urllib.parse.ParseResult~Subclass").getASubclass*()
|
||||
}
|
||||
|
||||
/**
|
||||
* A source of instances of `urllib.parse.ParseResult`, extend this class to model new instances.
|
||||
*
|
||||
* This can include instantiations of the class, return values from function
|
||||
* calls, or a special parameter that will be set when functions are called by an external
|
||||
* library.
|
||||
*
|
||||
* Use the predicate `ParseResult::instance()` to get references to instances of `urllib.parse.ParseResult`.
|
||||
*/
|
||||
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
|
||||
|
||||
/** A direct instantiation of `urllib.parse.ParseResult`. */
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
|
||||
ClassInstantiation() { this = classRef().getACall() }
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `urllib.parse.ParseResult`. */
|
||||
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result instanceof InstanceSource
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `urllib.parse.ParseResult`. */
|
||||
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
|
||||
/**
|
||||
* Taint propagation for `urllib.parse.ParseResult`.
|
||||
*/
|
||||
private class InstanceTaintSteps extends InstanceTaintStepsHelper {
|
||||
InstanceTaintSteps() { this = "urllib.parse.ParseResult" }
|
||||
|
||||
override DataFlow::Node getInstance() { result = instance() }
|
||||
|
||||
override string getAttributeName() {
|
||||
result in [
|
||||
"netloc", "path", "params", "query", "fragment", "username", "password", "hostname",
|
||||
"port"
|
||||
]
|
||||
}
|
||||
|
||||
override string getMethodName() { none() }
|
||||
|
||||
override string getAsyncMethodName() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// logging
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -135,6 +135,8 @@ module Tornado {
|
||||
API::Node subclassRef() {
|
||||
result = web().getMember("RequestHandler").getASubclass*()
|
||||
or
|
||||
result = WebSocket::WebSocketHandler::subclassRef()
|
||||
or
|
||||
result = ModelOutput::getATypeNode("tornado.web.RequestHandler~Subclass").getASubclass*()
|
||||
}
|
||||
|
||||
@@ -428,6 +430,49 @@ module Tornado {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// tornado.websocket
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Gets a reference to the `tornado.websocket` module. */
|
||||
API::Node websocket() { result = Tornado::tornado().getMember("websocket") }
|
||||
|
||||
/** Provides models for the `tornado.websocket` module */
|
||||
module WebSocket {
|
||||
/**
|
||||
* Provides models for the `tornado.websocket.WebSocketHandler` class and subclasses.
|
||||
*
|
||||
* See https://www.tornadoweb.org/en/stable/websocket.html#tornado.websocket.WebSocketHandler.
|
||||
*/
|
||||
module WebSocketHandler {
|
||||
/** Gets a reference to the `tornado.websocket.WebSocketHandler` class or any subclass. */
|
||||
API::Node subclassRef() {
|
||||
result = websocket().getMember("WebSocketHandler").getASubclass*()
|
||||
or
|
||||
result =
|
||||
ModelOutput::getATypeNode("tornado.websocket.WebSocketHandler~Subclass").getASubclass*()
|
||||
}
|
||||
|
||||
/** A subclass of `tornado.websocket.WebSocketHandler`. */
|
||||
class WebSocketHandlerClass extends Web::RequestHandler::RequestHandlerClass {
|
||||
WebSocketHandlerClass() { this.getParent() = subclassRef().asSource().asExpr() }
|
||||
|
||||
override Function getARequestHandler() {
|
||||
result = super.getARequestHandler()
|
||||
or
|
||||
result = this.getAMethod() and
|
||||
result.getName() = "open"
|
||||
}
|
||||
|
||||
/** Gets a function that could handle incoming WebSocket events, if any. */
|
||||
Function getAWebSocketEventHandler() {
|
||||
result = this.getAMethod() and
|
||||
result.getName() =
|
||||
["on_message", "on_close", "on_ping", "on_pong", "select_subprotocol", "check_origin"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -542,6 +587,27 @@ module Tornado {
|
||||
override string getFramework() { result = "Tornado" }
|
||||
}
|
||||
|
||||
/** A request handler for WebSocket events. */
|
||||
private class TornadoWebSocketEventHandler extends Http::Server::RequestHandler::Range {
|
||||
TornadoWebSocketEventHandler() {
|
||||
exists(TornadoModule::WebSocket::WebSocketHandler::WebSocketHandlerClass cls |
|
||||
cls.getAWebSocketEventHandler() = this
|
||||
)
|
||||
}
|
||||
|
||||
override Parameter getARoutedParameter() {
|
||||
// The `open` method is handled as a normal request handler in `TornadoRouteSetup` or `TornadoRequestHandlerWithoutKnownRoute`.
|
||||
// For other event handlers (such as `on_message`), all parameters should be remote flow sources, as they are not affected by routing.
|
||||
result in [
|
||||
this.getArg(_), this.getArgByName(_), this.getVararg().(Parameter),
|
||||
this.getKwarg().(Parameter)
|
||||
] and
|
||||
not result = this.getArg(0)
|
||||
}
|
||||
|
||||
override string getFramework() { result = "Tornado" }
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Response modeling
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** Utilities for handling the zope libraries */
|
||||
|
||||
import python
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import LegacyPointsTo
|
||||
|
||||
/** A method that belongs to a sub-class of `zope.interface.Interface` */
|
||||
class ZopeInterfaceMethodValue extends PythonFunctionValue {
|
||||
|
||||
@@ -5,6 +5,7 @@ private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.pointsto.MRO
|
||||
private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.types.Builtins
|
||||
private import semmle.python.objects.ObjectAPI
|
||||
|
||||
/**
|
||||
* A constant.
|
||||
|
||||
@@ -5,6 +5,7 @@ private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.pointsto.MRO
|
||||
private import semmle.python.types.Builtins
|
||||
private import semmle.python.pointsto.Context
|
||||
|
||||
/** A property object. */
|
||||
class PropertyInternal extends ObjectInternal, TProperty {
|
||||
|
||||
@@ -5,6 +5,8 @@ private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.pointsto.MRO
|
||||
private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.types.Builtins
|
||||
private import semmle.python.pointsto.Context
|
||||
private import semmle.python.pointsto.Base
|
||||
|
||||
/** A class representing instances */
|
||||
abstract class InstanceObject extends ObjectInternal {
|
||||
|
||||
@@ -5,6 +5,7 @@ private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.pointsto.MRO
|
||||
private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.types.Builtins
|
||||
private import semmle.python.types.ImportTime
|
||||
|
||||
/** A class representing modules */
|
||||
abstract class ModuleObjectInternal extends ObjectInternal {
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.pointsto.MRO
|
||||
private import semmle.python.types.Builtins
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.internal.CachedStages
|
||||
private import semmle.python.pointsto.Context
|
||||
|
||||
/**
|
||||
* Internal type backing `ObjectInternal` and `Value`
|
||||
|
||||
@@ -12,6 +12,8 @@ import python
|
||||
import semmle.python.essa.SsaDefinitions
|
||||
private import semmle.python.types.Builtins
|
||||
private import semmle.python.internal.CachedStages
|
||||
private import semmle.python.types.Object
|
||||
private import semmle.python.types.ClassObject
|
||||
|
||||
/*
|
||||
* The following predicates exist in order to provide
|
||||
@@ -42,24 +44,6 @@ private predicate class_defines_name(Class cls, string name) {
|
||||
exists(SsaVariable var | name = var.getId() and var.getAUse() = cls.getANormalExit())
|
||||
}
|
||||
|
||||
/** Hold if `expr` is a test (a branch) and `use` is within that test */
|
||||
predicate test_contains(ControlFlowNode expr, ControlFlowNode use) {
|
||||
expr.getNode() instanceof Expr and
|
||||
expr.isBranch() and
|
||||
expr.getAChild*() = use
|
||||
}
|
||||
|
||||
/** Holds if `f` is an import of the form `from .[...] import ...` and the enclosing scope is an __init__ module */
|
||||
predicate import_from_dot_in_init(ImportExprNode f) {
|
||||
f.getScope() = any(Module m).getInitModule() and
|
||||
(
|
||||
f.getNode().getLevel() = 1 and
|
||||
not exists(f.getNode().getName())
|
||||
or
|
||||
f.getNode().getImportedModuleName() = f.getEnclosingModule().getPackage().getName()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the pseudo-object representing the value referred to by an undefined variable */
|
||||
Object undefinedVariable() { py_special_objects(result, "_semmle_undefined_value") }
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
import python
|
||||
private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.types.FunctionObject
|
||||
private import semmle.python.pointsto.Context
|
||||
|
||||
private newtype TTInvocation =
|
||||
TInvocation(FunctionObject f, Context c) {
|
||||
|
||||
@@ -6,7 +6,13 @@ private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.pointsto.MRO
|
||||
private import semmle.python.types.Builtins
|
||||
private import semmle.python.types.Extensions
|
||||
private import semmle.python.pointsto.Context
|
||||
private import semmle.python.internal.CachedStages
|
||||
private import semmle.python.types.Object
|
||||
private import semmle.python.types.FunctionObject
|
||||
private import semmle.python.types.ClassObject
|
||||
private import semmle.python.pointsto.Base
|
||||
private import semmle.python.types.ImportTime
|
||||
|
||||
/* Use this version for speed */
|
||||
class CfgOrigin extends @py_object {
|
||||
@@ -709,7 +715,7 @@ private module InterModulePointsTo {
|
||||
i.getImportedModuleName() = name and
|
||||
PointsToInternal::module_imported_as(value, name) and
|
||||
origin = f and
|
||||
context.appliesTo(f)
|
||||
context.appliesTo(pragma[only_bind_into](f))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import python
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.types.ImportTime
|
||||
private import semmle.python.types.Version
|
||||
|
||||
/*
|
||||
* A note on 'cost'. Cost doesn't represent the cost to compute,
|
||||
|
||||
@@ -50,7 +50,7 @@ module FullServerSideRequestForgeryFlow = TaintTracking::Global<FullServerSideRe
|
||||
*/
|
||||
predicate fullyControlledRequest(Http::Client::Request request) {
|
||||
forall(DataFlow::Node urlPart | urlPart = request.getAUrlPart() |
|
||||
FullServerSideRequestForgeryFlow::flow(_, urlPart)
|
||||
FullServerSideRequestForgeryFlow::flowTo(urlPart)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
class Builtin extends @py_cobject {
|
||||
Builtin() {
|
||||
|
||||
@@ -6,6 +6,7 @@ private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.pointsto.MRO
|
||||
private import semmle.python.types.Builtins
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.types.ImportTime
|
||||
|
||||
/**
|
||||
* A class whose instances represents Python classes.
|
||||
@@ -88,7 +89,7 @@ class ClassObject extends Object {
|
||||
}
|
||||
|
||||
/** Gets the scope associated with this class, if it is not a builtin class */
|
||||
Class getPyClass() { result.getClassObject() = this }
|
||||
ClassWithPointsTo getPyClass() { result.getClassObject() = this }
|
||||
|
||||
/** Returns an attribute declared on this class (not on a super-class) */
|
||||
Object declaredAttribute(string name) {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import python
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.types.Object
|
||||
private import semmle.python.types.FunctionObject
|
||||
private import semmle.python.pointsto.Context
|
||||
|
||||
/** A class method object. Either a decorated function or an explicit call to classmethod(f) */
|
||||
class ClassMethodObject extends Object {
|
||||
|
||||
@@ -80,7 +80,7 @@ class RaisingNode extends ControlFlowNode {
|
||||
or
|
||||
this.getNode() instanceof Print and result = theIOErrorType()
|
||||
or
|
||||
exists(ExceptFlowNode except |
|
||||
exists(ExceptFlowNodeWithPointsTo except |
|
||||
except = this.getAnExceptionalSuccessor() and
|
||||
except.handles_objectapi(result) and
|
||||
result = this.innateException_objectapi()
|
||||
@@ -107,7 +107,7 @@ class RaisingNode extends ControlFlowNode {
|
||||
or
|
||||
this.getNode() instanceof Print and result = ClassValue::ioError()
|
||||
or
|
||||
exists(ExceptFlowNode except |
|
||||
exists(ExceptFlowNodeWithPointsTo except |
|
||||
except = this.getAnExceptionalSuccessor() and
|
||||
except.handles(result) and
|
||||
result = this.innateException()
|
||||
@@ -200,8 +200,8 @@ class RaisingNode extends ControlFlowNode {
|
||||
succ = this.getAnExceptionalSuccessor() and
|
||||
(
|
||||
/* An 'except' that handles raised and there is no more previous handler */
|
||||
succ.(ExceptFlowNode).handles_objectapi(raised) and
|
||||
not exists(ExceptFlowNode other, StmtList s, int i, int j |
|
||||
succ.(ExceptFlowNodeWithPointsTo).handles_objectapi(raised) and
|
||||
not exists(ExceptFlowNodeWithPointsTo other, StmtList s, int i, int j |
|
||||
not other = succ and
|
||||
other.handles_objectapi(raised) and
|
||||
s.getItem(i) = succ.getNode() and
|
||||
@@ -211,7 +211,7 @@ class RaisingNode extends ControlFlowNode {
|
||||
)
|
||||
or
|
||||
/* Any successor that is not an 'except', provided that 'raised' is not handled by a different successor. */
|
||||
not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles_objectapi(raised) and
|
||||
not this.getAnExceptionalSuccessor().(ExceptFlowNodeWithPointsTo).handles_objectapi(raised) and
|
||||
not succ instanceof ExceptFlowNode
|
||||
)
|
||||
}
|
||||
@@ -223,8 +223,8 @@ class RaisingNode extends ControlFlowNode {
|
||||
succ = this.getAnExceptionalSuccessor() and
|
||||
(
|
||||
/* An 'except' that handles raised and there is no more previous handler */
|
||||
succ.(ExceptFlowNode).handles(raised) and
|
||||
not exists(ExceptFlowNode other, StmtList s, int i, int j |
|
||||
succ.(ExceptFlowNodeWithPointsTo).handles(raised) and
|
||||
not exists(ExceptFlowNodeWithPointsTo other, StmtList s, int i, int j |
|
||||
not other = succ and
|
||||
other.handles(raised) and
|
||||
s.getItem(i) = succ.getNode() and
|
||||
@@ -234,7 +234,7 @@ class RaisingNode extends ControlFlowNode {
|
||||
)
|
||||
or
|
||||
/* Any successor that is not an 'except', provided that 'raised' is not handled by a different successor. */
|
||||
not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles(raised) and
|
||||
not this.getAnExceptionalSuccessor().(ExceptFlowNodeWithPointsTo).handles(raised) and
|
||||
not succ instanceof ExceptFlowNode
|
||||
)
|
||||
}
|
||||
@@ -248,7 +248,7 @@ class RaisingNode extends ControlFlowNode {
|
||||
raised.isLegalExceptionType() and
|
||||
raised = this.getARaisedType_objectapi() and
|
||||
this.isExceptionalExit(s) and
|
||||
not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles_objectapi(raised)
|
||||
not this.getAnExceptionalSuccessor().(ExceptFlowNodeWithPointsTo).handles_objectapi(raised)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,7 +260,7 @@ class RaisingNode extends ControlFlowNode {
|
||||
raised.isLegalExceptionType() and
|
||||
raised = this.getARaisedType() and
|
||||
this.isExceptionalExit(s) and
|
||||
not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles(raised)
|
||||
not this.getAnExceptionalSuccessor().(ExceptFlowNodeWithPointsTo).handles(raised)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,36 +368,10 @@ predicate scope_raises_unknown(Scope s) {
|
||||
)
|
||||
}
|
||||
|
||||
/** The ControlFlowNode for an 'except' statement. */
|
||||
class ExceptFlowNode extends ControlFlowNode {
|
||||
ExceptFlowNode() { this.getNode() instanceof ExceptStmt }
|
||||
|
||||
/**
|
||||
* Gets the type handled by this exception handler.
|
||||
* `ExceptionType` in `except ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNodeWithPointsTo getType() {
|
||||
exists(ExceptStmt ex |
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
ex = this.getNode() and
|
||||
result = ex.getType().getAFlowNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name assigned to the handled exception, if any.
|
||||
* `e` in `except ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getName() {
|
||||
exists(ExceptStmt ex |
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
ex = this.getNode() and
|
||||
result = ex.getName().getAFlowNode()
|
||||
)
|
||||
}
|
||||
|
||||
/** An extension of `ExceptFlowNode` that provides points-to related methods. */
|
||||
class ExceptFlowNodeWithPointsTo extends ExceptFlowNode {
|
||||
private predicate handledObject_objectapi(Object obj, ClassObject cls, ControlFlowNode origin) {
|
||||
this.getType().refersTo(obj, cls, origin)
|
||||
this.getType().(ControlFlowNodeWithPointsTo).refersTo(obj, cls, origin)
|
||||
or
|
||||
exists(Object tup | this.handledObject_objectapi(tup, theTupleType(), _) |
|
||||
element_from_tuple_objectapi(tup).refersTo(obj, cls, origin)
|
||||
@@ -407,7 +381,7 @@ class ExceptFlowNode extends ControlFlowNode {
|
||||
private predicate handledObject(Value val, ClassValue cls, ControlFlowNode origin) {
|
||||
val.getClass() = cls and
|
||||
(
|
||||
this.getType().pointsTo(val, origin)
|
||||
this.getType().(ControlFlowNodeWithPointsTo).pointsTo(val, origin)
|
||||
or
|
||||
exists(TupleValue tup | this.handledObject(tup, ClassValue::tuple(), _) |
|
||||
val = tup.getItem(_) and origin = val.getOrigin()
|
||||
@@ -452,29 +426,6 @@ class ExceptFlowNode extends ControlFlowNode {
|
||||
}
|
||||
}
|
||||
|
||||
/** The ControlFlowNode for an 'except*' statement. */
|
||||
class ExceptGroupFlowNode extends ControlFlowNode {
|
||||
ExceptGroupFlowNode() { this.getNode() instanceof ExceptGroupStmt }
|
||||
|
||||
/**
|
||||
* Gets the type handled by this exception handler.
|
||||
* `ExceptionType` in `except* ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getType() {
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
result = this.getNode().(ExceptGroupStmt).getType().getAFlowNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name assigned to the handled exception, if any.
|
||||
* `e` in `except* ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getName() {
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
result = this.getNode().(ExceptGroupStmt).getName().getAFlowNode()
|
||||
}
|
||||
}
|
||||
|
||||
private ControlFlowNodeWithPointsTo element_from_tuple_objectapi(Object tuple) {
|
||||
exists(Tuple t | t = tuple.getOrigin() and result = t.getAnElt().getAFlowNode())
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.objects.TObject
|
||||
/* Make ObjectInternal visible to save extra imports in user code */
|
||||
import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.Context
|
||||
|
||||
abstract class PointsToExtension extends @py_flow_node {
|
||||
string toString() { result = "PointsToExtension with missing toString" }
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
import semmle.python.types.Exceptions
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.objects.Callables
|
||||
private import semmle.python.libraries.Zope
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.types.Builtins
|
||||
|
||||
/** A function object, whether written in Python or builtin */
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import python
|
||||
private import semmle.python.types.ModuleObject
|
||||
|
||||
private predicate is_normal_module(ModuleObject m) {
|
||||
m instanceof BuiltinModuleObject
|
||||
|
||||
@@ -2,6 +2,9 @@ import python
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.types.ModuleKind
|
||||
private import semmle.python.types.Object
|
||||
private import semmle.python.types.ClassObject
|
||||
private import semmle.python.objects.ObjectAPI
|
||||
|
||||
abstract class ModuleObject extends Object {
|
||||
ModuleValue theModule() {
|
||||
|
||||
@@ -1,6 +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
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
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(ControlFlowNodeWithPointsTo n, string attr) {
|
||||
(n.getNode() instanceof Unicode or n.getNode() instanceof Bytes) and
|
||||
|
||||
@@ -530,6 +530,10 @@ py_extracted_version(int module : @py_Module ref,
|
||||
/* <Field> Fstring.values = 2, expr_list */
|
||||
/* <Parent> Fstring = FormattedValue */
|
||||
|
||||
/* <Field> JoinedTemplateString.location = 0, location */
|
||||
/* <Field> JoinedTemplateString.parenthesised = 1, bool */
|
||||
/* <Field> JoinedTemplateString.strings = 2, TemplateString_list */
|
||||
|
||||
/* <Field> KeyValuePair.location = 0, location */
|
||||
/* <Field> KeyValuePair.value = 1, expr */
|
||||
/* <Field> KeyValuePair.key = 2, expr */
|
||||
@@ -709,6 +713,17 @@ py_extracted_version(int module : @py_Module ref,
|
||||
/* <Field> TemplateDottedNotation.attr = 3, str */
|
||||
/* <Field> TemplateDottedNotation.ctx = 4, expr_context */
|
||||
|
||||
/* <Field> TemplateString.location = 0, location */
|
||||
/* <Field> TemplateString.parenthesised = 1, bool */
|
||||
/* <Field> TemplateString.prefix = 2, str */
|
||||
/* <Field> TemplateString.values = 3, expr_list */
|
||||
/* <Parent> TemplateString = TemplateStringList */
|
||||
|
||||
/* <Field> TemplateStringPart.location = 0, location */
|
||||
/* <Field> TemplateStringPart.parenthesised = 1, bool */
|
||||
/* <Field> TemplateStringPart.text = 2, str */
|
||||
/* <Parent> TemplateStringList = JoinedTemplateString */
|
||||
|
||||
/* <Field> TemplateWrite.location = 0, location */
|
||||
/* <Field> TemplateWrite.value = 1, expr */
|
||||
|
||||
@@ -835,6 +850,9 @@ py_StringParts(unique int id : @py_StringPart,
|
||||
py_StringPart_lists(unique int id : @py_StringPart_list,
|
||||
unique int parent : @py_Bytes_or_Str ref);
|
||||
|
||||
py_TemplateString_lists(unique int id : @py_TemplateString_list,
|
||||
unique int parent : @py_JoinedTemplateString ref);
|
||||
|
||||
py_aliases(unique int id : @py_alias,
|
||||
int parent : @py_alias_list ref,
|
||||
int idx : int ref);
|
||||
@@ -1010,7 +1028,10 @@ case @py_expr.kind of
|
||||
| 36 = @py_Fstring
|
||||
| 37 = @py_FormattedValue
|
||||
| 38 = @py_AssignExpr
|
||||
| 39 = @py_SpecialOperation;
|
||||
| 39 = @py_SpecialOperation
|
||||
| 40 = @py_TemplateString
|
||||
| 41 = @py_JoinedTemplateString
|
||||
| 42 = @py_TemplateStringPart;
|
||||
|
||||
case @py_expr_context.kind of
|
||||
0 = @py_AugLoad
|
||||
@@ -1105,11 +1126,11 @@ case @py_unaryop.kind of
|
||||
|
||||
@py_expr_context_parent = @py_Attribute | @py_List | @py_Name | @py_PlaceHolder | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_Tuple;
|
||||
|
||||
@py_expr_list_parent = @py_Assign | @py_BoolExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_Delete | @py_Fstring | @py_Function | @py_List | @py_Print | @py_Set | @py_SpecialOperation | @py_Tuple | @py_arguments | @py_comprehension;
|
||||
@py_expr_list_parent = @py_Assign | @py_BoolExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_Delete | @py_Fstring | @py_Function | @py_List | @py_Print | @py_Set | @py_SpecialOperation | @py_TemplateString | @py_Tuple | @py_arguments | @py_comprehension;
|
||||
|
||||
@py_expr_or_stmt = @py_expr | @py_stmt;
|
||||
|
||||
@py_expr_parent = @py_AnnAssign | @py_Assert | @py_Assign | @py_AssignExpr | @py_Attribute | @py_AugAssign | @py_Await | @py_BinaryExpr | @py_Call | @py_Case | @py_Compare | @py_DictComp | @py_DictUnpacking | @py_ExceptGroupStmt | @py_ExceptStmt | @py_Exec | @py_Expr_stmt | @py_Filter | @py_For | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_GeneratorExp | @py_Guard | @py_If | @py_IfExp | @py_ImportMember | @py_ImportStar | @py_KeyValuePair | @py_ListComp | @py_MatchAsPattern | @py_MatchCapturePattern | @py_MatchClassPattern | @py_MatchKeywordPattern | @py_MatchLiteralPattern | @py_MatchStmt | @py_MatchValuePattern | @py_ParamSpec | @py_Print | @py_Raise | @py_Repr | @py_Return | @py_SetComp | @py_Slice | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_TemplateWrite | @py_TypeAlias | @py_TypeVar | @py_TypeVarTuple | @py_UnaryExpr | @py_While | @py_With | @py_Yield | @py_YieldFrom | @py_alias | @py_arguments | @py_comprehension | @py_expr_list | @py_keyword | @py_parameter_list;
|
||||
@py_expr_parent = @py_AnnAssign | @py_Assert | @py_Assign | @py_AssignExpr | @py_Attribute | @py_AugAssign | @py_Await | @py_BinaryExpr | @py_Call | @py_Case | @py_Compare | @py_DictComp | @py_DictUnpacking | @py_ExceptGroupStmt | @py_ExceptStmt | @py_Exec | @py_Expr_stmt | @py_Filter | @py_For | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_GeneratorExp | @py_Guard | @py_If | @py_IfExp | @py_ImportMember | @py_ImportStar | @py_KeyValuePair | @py_ListComp | @py_MatchAsPattern | @py_MatchCapturePattern | @py_MatchClassPattern | @py_MatchKeywordPattern | @py_MatchLiteralPattern | @py_MatchStmt | @py_MatchValuePattern | @py_ParamSpec | @py_Print | @py_Raise | @py_Repr | @py_Return | @py_SetComp | @py_Slice | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_TemplateString_list | @py_TemplateWrite | @py_TypeAlias | @py_TypeVar | @py_TypeVarTuple | @py_UnaryExpr | @py_While | @py_With | @py_Yield | @py_YieldFrom | @py_alias | @py_arguments | @py_comprehension | @py_expr_list | @py_keyword | @py_parameter_list;
|
||||
|
||||
@py_location_parent = @py_DictUnpacking | @py_KeyValuePair | @py_StringPart | @py_comprehension | @py_expr | @py_keyword | @py_pattern | @py_stmt | @py_type_parameter;
|
||||
|
||||
@@ -1125,7 +1146,7 @@ case @py_unaryop.kind of
|
||||
|
||||
@py_str_list_parent = @py_Global | @py_Nonlocal;
|
||||
|
||||
@py_str_parent = @py_Attribute | @py_Class | @py_ClassExpr | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_ImportExpr | @py_ImportMember | @py_Module | @py_SpecialOperation | @py_Str | @py_StringPart | @py_TemplateDottedNotation | @py_keyword | @py_str_list;
|
||||
@py_str_parent = @py_Attribute | @py_Class | @py_ClassExpr | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_ImportExpr | @py_ImportMember | @py_Module | @py_SpecialOperation | @py_Str | @py_StringPart | @py_TemplateDottedNotation | @py_TemplateString | @py_TemplateStringPart | @py_keyword | @py_str_list;
|
||||
|
||||
@py_type_parameter_list_parent = @py_ClassExpr | @py_Function | @py_TypeAlias;
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
<k>@py_TypeVar</k><v>100</v></e><e>
|
||||
<k>@py_TypeVarTuple</k><v>100</v></e><e>
|
||||
<k>@py_type_parameter_list</k><v>100</v></e><e>
|
||||
<k>@py_TemplateStringPart</k><v>100</v></e><e>
|
||||
<k>@py_TemplateString_list</k><v>100</v></e><e>
|
||||
<k>@py_JoinedTemplateString</k><v>100</v></e><e>
|
||||
<k>@py_TemplateString</k><v>100</v></e><e>
|
||||
<k>@py_Guard</k><v>100</v></e><e>
|
||||
<k>@py_MatchAsPattern</k><v>100</v></e><e>
|
||||
<k>@py_MatchOrPattern</k><v>100</v></e><e>
|
||||
@@ -7959,6 +7963,21 @@
|
||||
</dependencies>
|
||||
</relation>
|
||||
<relation>
|
||||
<name>py_TemplateString_lists</name>
|
||||
<cardinality>1000</cardinality>
|
||||
<columnsizes>
|
||||
<e>
|
||||
<k>id</k>
|
||||
<v>1000</v>
|
||||
</e>
|
||||
<e>
|
||||
<k>parent</k>
|
||||
<v>1000</v>
|
||||
</e>
|
||||
</columnsizes>
|
||||
<dependencies/>
|
||||
</relation>
|
||||
<relation>
|
||||
<name>py_aliases</name>
|
||||
<cardinality>21374</cardinality>
|
||||
<columnsizes>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add support for template string literals
|
||||
compatibility: backwards
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import LegacyPointsTo
|
||||
|
||||
/** A helper class for UndefinedClassAttribute.ql and MaybeUndefinedClassAttribute.ql */
|
||||
class CheckClass extends ClassObject {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate does_nothing(PyFunctionObject f) {
|
||||
not exists(Stmt s | s.getScope() = f.getFunction() |
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
import python
|
||||
import Equality
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate class_stores_to_attribute(ClassValue cls, SelfAttributeStore store, string name) {
|
||||
exists(FunctionValue f |
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
ClassObject left_base(ClassObject type, ClassObject base) {
|
||||
exists(int i | i > 0 and type.getBaseType(i) = base and result = type.getBaseType(i - 1))
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
import python
|
||||
import ClassAttributes
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate guarded_by_other_attribute(SelfAttributeRead a, CheckClass c) {
|
||||
c.sometimesDefines(a.getName()) and
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate mutates_descriptor(ClassObject cls, SelfAttributeStore s) {
|
||||
cls.isDescriptorType() and
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
class InitCallStmt extends ExprStmt {
|
||||
InitCallStmt() {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from PropertyObject prop, ClassObject cls
|
||||
where cls.declaredAttribute(_) = prop and not cls.failedInference() and not cls.isNewStyle()
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from ClassValue c
|
||||
where not c.isBuiltin() and not c.isContextManager() and exists(c.declaredAttribute("__del__"))
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from ClassObject c
|
||||
where not c.isNewStyle() and c.declaresAttribute("__slots__") and not c.failedInference()
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate uses_of_super_in_old_style_class(Call s) {
|
||||
exists(Function f, ClassObject c |
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
import python
|
||||
import ClassAttributes
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate undefined_class_attribute(SelfAttributeRead a, CheckClass c, int line, string name) {
|
||||
name = a.getName() and
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate fewer_than_two_public_methods(Class cls, int methods) {
|
||||
(methods = 0 or methods = 1) and
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import python
|
||||
import Expressions.CallArgs
|
||||
private import LegacyPointsTo
|
||||
|
||||
from Call call, ClassValue cls, string name, FunctionValue init
|
||||
where
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import python
|
||||
import Expressions.CallArgs
|
||||
private import LegacyPointsTo
|
||||
|
||||
from Call call, ClassValue cls, string too, string should, int limit, FunctionValue init
|
||||
where
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from ExceptFlowNode ex, Value t, ClassValue c, ControlFlowNode origin, string what
|
||||
from ExceptFlowNodeWithPointsTo ex, Value t, ClassValue c, ControlFlowNode origin, string what
|
||||
where
|
||||
ex.handledException(t, c, origin) and
|
||||
(
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import python
|
||||
import Raising
|
||||
import Exceptions.NotImplemented
|
||||
private import LegacyPointsTo
|
||||
|
||||
from Raise r, ClassValue t
|
||||
where
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
import semmle.python.pointsto.PointsTo
|
||||
|
||||
predicate rhs_in_expr(ControlFlowNode rhs, Compare cmp) {
|
||||
exists(Cmpop op, int i | cmp.getOp(i) = op and cmp.getComparator(i) = rhs.getNode() |
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
|
||||
/** 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) {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
import python
|
||||
import IsComparisons
|
||||
private import LegacyPointsTo
|
||||
|
||||
from Compare comp, Cmpop op, ClassValue c
|
||||
where
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** Helper functions for queries that test redundant comparisons. */
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
/** A comparison where the left and right hand sides appear to be identical. */
|
||||
class RedundantComparison extends Compare {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import python
|
||||
import Expressions.CallArgs
|
||||
private import LegacyPointsTo
|
||||
|
||||
from Call call, FunctionObject func, string name
|
||||
where
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
import python
|
||||
import LegacyPointsTo
|
||||
import semmle.python.objects.ObjectInternal
|
||||
import semmle.python.strings
|
||||
|
||||
predicate string_format(BinaryExpr operation, StringLiteral str, Value args, AstNode origin) {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
import CallArgs
|
||||
|
||||
from Call call, FunctionValue func, string too, string should, int limit
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate explicitly_returns_non_none(Function func) {
|
||||
exists(Return return |
|
||||
@@ -21,7 +22,7 @@ predicate explicitly_returns_non_none(Function func) {
|
||||
}
|
||||
|
||||
predicate has_implicit_return(Function func) {
|
||||
exists(ControlFlowNode fallthru |
|
||||
exists(ControlFlowNodeWithPointsTo fallthru |
|
||||
fallthru = func.getFallthroughNode() and not fallthru.unlikelyReachable()
|
||||
)
|
||||
or
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate slice_method_name(string name) {
|
||||
name = "__getslice__" or name = "__setslice__" or name = "__delslice__"
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
import python
|
||||
import Expressions.CallArgs
|
||||
private import LegacyPointsTo
|
||||
|
||||
from Call call, FunctionValue func, FunctionValue overridden, string problem
|
||||
where
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
import python
|
||||
import Expressions.CallArgs
|
||||
private import LegacyPointsTo
|
||||
|
||||
from Call call, FunctionValue func, FunctionValue overriding, string problem
|
||||
where
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from ClassValue iterable, FunctionValue iter, ClassValue iterator
|
||||
where
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
from FunctionValue method
|
||||
where
|
||||
exists(ClassValue c |
|
||||
c.declaredAttribute("__del__") = method and
|
||||
method.getScope().getMetrics().getCyclomaticComplexity() > 3
|
||||
method.getScope().(FunctionMetrics).getCyclomaticComplexity() > 3
|
||||
)
|
||||
select method, "Overly complex '__del__' method."
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user