Merge pull request #21116 from github/tausbn/python-add-dataflow-overlay-annotations

Add `overlay[local]` annotations
This commit is contained in:
Taus
2026-02-21 13:44:09 +01:00
committed by GitHub
55 changed files with 225 additions and 21 deletions

View File

@@ -471,11 +471,10 @@ Definition getUniqueDefinition(Expr use) {
not result = TLocalDefinition(use)
}
/** A helper class to get suitable locations for attributes */
class NiceLocationExpr extends Expr {
/** Gets a textual representation of this element. */
override string toString() { result = this.(Expr).toString() }
final class FinalExpr = Expr;
/** A helper class to get suitable locations for attributes */
class NiceLocationExpr extends FinalExpr {
/**
* Holds if this element is at the specified location.
* The location spans column `bc` of line `bl` to

View File

@@ -0,0 +1,5 @@
---
category: majorAnalysis
---
- The CodeQL Python libraries have been updated to be compatible with overlay evaluation. This should result in a significant speedup on analyses for which a base database already exists. Note that it may be necessary to add `overlay[local?] module;` to user-managed libraries that extend classes that are now marked as `overlay[local]`.

View File

@@ -451,6 +451,7 @@ module API {
* allowing this predicate to be used in a negative
* context when constructing new nodes.
*/
overlay[local]
predicate moduleImportExists(string m) {
Impl::isImported(m) and
// restrict `moduleImport` so it will never give results for a dotted name. Note
@@ -695,6 +696,7 @@ module API {
*
* This is determined syntactically.
*/
overlay[local]
cached
predicate isImported(string name) {
// Ignore the following module name for Python 2, as we alias `__builtin__` to `builtins` elsewhere

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
private import semmle.python.internal.CachedStages

View File

@@ -3,6 +3,8 @@
* WARNING: Any modifications to this file will be lost.
* Relations can be changed by modifying master.py.
*/
overlay[local]
module;
import python

View File

@@ -1,6 +1,8 @@
/**
* Provides classes representing Python classes.
*/
overlay[local]
module;
import python

View File

@@ -1,6 +1,8 @@
/**
* Provides classes representing comments in Python.
*/
overlay[local]
module;
import python

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
/** The base class for list, set and dictionary comprehensions, and generator expressions. */

View File

@@ -1,4 +1,6 @@
/** Standard builtin types and modules */
overlay[local]
module;
import python

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import python
private import semmle.python.internal.CachedStages

View File

@@ -1,4 +1,6 @@
/** Provides classes for working with files and folders. */
overlay[local]
module;
import python
private import codeql.util.FileSystem
@@ -178,6 +180,7 @@ class Container extends Impl::Container {
override Container getParentContainer() { result = super.getParentContainer() }
overlay[global]
Container getChildContainer(string baseName) {
result = this.getAChildContainer() and
result.getBaseName() = baseName

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
private import semmle.python.internal.CachedStages
private import codeql.controlflow.BasicBlock as BB
@@ -191,6 +194,7 @@ class ControlFlowNode extends @py_flow_node {
predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) }
/** Whether this strictly dominates other. */
overlay[caller]
pragma[inline]
predicate strictlyDominates(ControlFlowNode other) {
// This predicate is gigantic, so it must be inlined.
@@ -204,6 +208,7 @@ class ControlFlowNode extends @py_flow_node {
* Whether this dominates other.
* Note that all nodes dominate themselves.
*/
overlay[caller]
pragma[inline]
predicate dominates(ControlFlowNode other) {
// This predicate is gigantic, so it must be inlined.
@@ -213,6 +218,7 @@ class ControlFlowNode extends @py_flow_node {
}
/** Whether this strictly reaches other. */
overlay[caller]
pragma[inline]
predicate strictlyReaches(ControlFlowNode other) {
// This predicate is gigantic, even larger than strictlyDominates,

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
/**

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
/** A basic block which terminates in a condition, splitting the subsequent control flow */

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
private import semmle.python.types.Builtins
private import semmle.python.internal.CachedStages

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
class KeyValuePair extends KeyValuePair_, DictDisplayItem {

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
private import semmle.python.internal.CachedStages

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
/** The base class for operators */

View File

@@ -1,6 +1,8 @@
/**
* Wrapping generated AST classes: `Pattern_` and subclasses.
*/
overlay[local]
module;
import python

View File

@@ -1,4 +1,6 @@
/** SSA library */
overlay[local]
module;
import python

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
private import semmle.python.dataflow.new.internal.ImportResolution
@@ -6,6 +9,7 @@ private import semmle.python.dataflow.new.internal.ImportResolution
*
* This aims to be the same as m.getAnExport(), but without using the points-to machinery.
*/
overlay[global]
private string getAModuleExport(Module m) {
py_exports(m, result)
or
@@ -76,6 +80,7 @@ class Scope extends Scope_ {
predicate isTopLevel() { this.getEnclosingModule() = this.getEnclosingScope() }
/** Holds if this scope is deemed to be public */
overlay[global]
predicate isPublic() {
/* Not inside a function */
not this.getEnclosingScope() instanceof Function and

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
/** A statement */

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
/** A variable, either a global or local variable (including parameters) */

View File

@@ -25,6 +25,7 @@ deprecated module SummaryComponentStack = Impl::Private::SummaryComponentStack;
class Provenance = Impl::Public::Provenance;
/** Provides the `Range` class used to define the extent of `SummarizedCallable`. */
overlay[local]
module SummarizedCallable {
/** A callable with a flow summary, identified by a unique string. */
abstract class Range extends LibraryCallable, Impl::Public::SummarizedCallable {

View File

@@ -1,4 +1,6 @@
/** This module provides an API for attribute reads and writes. */
overlay[local]
module;
private import python
import DataFlowUtil

View File

@@ -1,4 +1,6 @@
/** Provides predicates for reasoning about built-ins in Python. */
overlay[local]
module;
private import python
private import semmle.python.dataflow.new.DataFlow

View File

@@ -31,6 +31,8 @@
* Note: This hasn't been 100% realized yet, so we don't currently expose a predicate to
* ask what targets any data-flow node has. But it's still the plan to do this!
*/
overlay[local?]
module;
private import python
private import DataFlowPublic
@@ -39,6 +41,7 @@ private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.python.internal.CachedStages
private import semmle.python.dataflow.new.internal.TypeTrackingImpl::CallGraphConstruction as CallGraphConstruction
overlay[local]
newtype TParameterPosition =
/** Used for `self` in methods, and `cls` in classmethods. */
TSelfParameterPosition() or
@@ -84,6 +87,7 @@ newtype TParameterPosition =
TSynthDictSplatParameterPosition()
/** A parameter position. */
overlay[local]
class ParameterPosition extends TParameterPosition {
/** Holds if this position represents a `self`/`cls` parameter. */
predicate isSelf() { this = TSelfParameterPosition() }
@@ -146,6 +150,7 @@ class ParameterPosition extends TParameterPosition {
}
}
overlay[local]
newtype TArgumentPosition =
/** Used for `self` in methods, and `cls` in classmethods. */
TSelfArgumentPosition() or
@@ -180,6 +185,7 @@ newtype TArgumentPosition =
TDictSplatArgumentPosition()
/** An argument position. */
overlay[local]
class ArgumentPosition extends TArgumentPosition {
/** Holds if this position represents a `self`/`cls` argument. */
predicate isSelf() { this = TSelfArgumentPosition() }
@@ -248,6 +254,7 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
* `@staticmethod` decorator or by convention
* (like a `__new__` method on a class is a classmethod even without the decorator).
*/
overlay[local]
predicate isStaticmethod(Function func) {
exists(NameNode id | id.getId() = "staticmethod" and id.isGlobal() |
func.getADecorator() = id.getNode()
@@ -259,6 +266,7 @@ predicate isStaticmethod(Function func) {
* `@classmethod` decorator or by convention
* (like a `__new__` method on a class is a classmethod even without the decorator).
*/
overlay[local]
predicate isClassmethod(Function func) {
exists(NameNode id | id.getId() = "classmethod" and id.isGlobal() |
func.getADecorator() = id.getNode()
@@ -275,6 +283,7 @@ predicate isClassmethod(Function func) {
}
/** Holds if the function `func` has a `property` decorator. */
overlay[local]
predicate hasPropertyDecorator(Function func) {
exists(NameNode id | id.getId() = "property" and id.isGlobal() |
func.getADecorator() = id.getNode()
@@ -284,6 +293,7 @@ predicate hasPropertyDecorator(Function func) {
/**
* Holds if the function `func` has a `contextlib.contextmanager`.
*/
overlay[local]
predicate hasContextmanagerDecorator(Function func) {
exists(ControlFlowNode contextmanager |
contextmanager.(NameNode).getId() = "contextmanager" and contextmanager.(NameNode).isGlobal()
@@ -298,20 +308,25 @@ predicate hasContextmanagerDecorator(Function func) {
// Callables
// =============================================================================
/** A callable defined in library code, identified by a unique string. */
overlay[local]
abstract class LibraryCallable extends string {
bindingset[this]
LibraryCallable() { any() }
/** Gets a call to this library callable. */
overlay[global]
abstract CallCfgNode getACall();
/** Same as `getACall` but without referring to the call graph or API graph. */
overlay[global]
CallCfgNode getACallSimple() { none() }
/** Gets a data-flow node, where this library callable is used as a call-back. */
overlay[global]
abstract ArgumentNode getACallback();
}
overlay[local]
newtype TDataFlowCallable =
/**
* Is used as the target for all calls: plain functions, lambdas, methods on classes,
@@ -329,6 +344,7 @@ newtype TDataFlowCallable =
TLibraryCallable(LibraryCallable callable)
/** A callable. */
overlay[local]
abstract class DataFlowCallable extends TDataFlowCallable {
/** Gets a textual representation of this element. */
abstract string toString();
@@ -350,6 +366,7 @@ abstract class DataFlowCallable extends TDataFlowCallable {
}
/** A callable function. */
overlay[local]
abstract class DataFlowFunction extends DataFlowCallable, TFunction {
Function func;
@@ -370,6 +387,7 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction {
/** Gets the positional parameter offset, to take into account self/cls parameters. */
int positionalOffset() { result = 0 }
overlay[local]
override ParameterNode getParameter(ParameterPosition ppos) {
// Do not handle lower bound positions (such as `[1..]`) here
// they are handled by parameter matching and would create
@@ -408,11 +426,13 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction {
}
/** A plain (non-method) function. */
overlay[local]
class DataFlowPlainFunction extends DataFlowFunction {
DataFlowPlainFunction() { not this instanceof DataFlowMethod }
}
/** A method. */
overlay[local]
class DataFlowMethod extends DataFlowFunction {
Class cls;
@@ -431,11 +451,13 @@ class DataFlowMethod extends DataFlowFunction {
}
/** A classmethod. */
overlay[local]
class DataFlowClassmethod extends DataFlowMethod {
DataFlowClassmethod() { isClassmethod(func) }
}
/** A staticmethod. */
overlay[local]
class DataFlowStaticmethod extends DataFlowMethod, DataFlowFunction {
DataFlowStaticmethod() { isStaticmethod(func) }
@@ -450,6 +472,7 @@ class DataFlowStaticmethod extends DataFlowMethod, DataFlowFunction {
* A module. This is not actually a callable, but we need this so a
* `ModuleVariableNode` have an enclosing callable.
*/
overlay[local]
class DataFlowModuleScope extends DataFlowCallable, TModule {
Module mod;
@@ -466,6 +489,7 @@ class DataFlowModuleScope extends DataFlowCallable, TModule {
override ParameterNode getParameter(ParameterPosition ppos) { none() }
}
overlay[local]
class LibraryCallableValue extends DataFlowCallable, TLibraryCallable {
LibraryCallable callable;
@@ -476,6 +500,7 @@ class LibraryCallableValue extends DataFlowCallable, TLibraryCallable {
override string getQualifiedName() { result = callable.toString() }
/** Gets a data-flow node, where this library callable is used as a call-back. */
overlay[global]
ArgumentNode getACallback() { result = callable.getACallback() }
override Scope getScope() { none() }
@@ -1210,6 +1235,7 @@ predicate resolveCall(CallNode call, Function target, CallType type) {
* Holds if the argument of `call` at position `apos` is `arg`. This is just a helper
* predicate that maps ArgumentPositions to the arguments of the underlying `CallNode`.
*/
overlay[local]
cached
predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) {
exists(int index |
@@ -1589,6 +1615,7 @@ class SummaryCall extends DataFlowCall, TSummaryCall {
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
overlay[local]
abstract class ParameterNodeImpl extends Node {
/** Gets the `Parameter` this `ParameterNode` represents. */
abstract Parameter getParameter();
@@ -1610,6 +1637,7 @@ abstract class ParameterNodeImpl extends Node {
*
* This is used for tracking flow through captured variables.
*/
overlay[local]
class SynthCapturedVariablesParameterNode extends ParameterNodeImpl,
TSynthCapturedVariablesParameterNode
{
@@ -1634,6 +1662,7 @@ class SynthCapturedVariablesParameterNode extends ParameterNodeImpl,
}
/** A parameter for a library callable with a flow summary. */
overlay[local]
class SummaryParameterNode extends ParameterNodeImpl, FlowSummaryNode {
SummaryParameterNode() {
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), _)
@@ -1684,6 +1713,7 @@ private class SummaryReturnNode extends FlowSummaryNode, ReturnNode {
override ReturnKind getKind() { result = rk }
}
overlay[global]
private class SummaryArgumentNode extends FlowSummaryNode, ArgumentNode {
private SummaryCall call_;
private ArgumentPosition pos_;
@@ -1737,6 +1767,7 @@ class SynthCapturedVariablesArgumentNode extends Node, TSynthCapturedVariablesAr
class CapturedVariablesArgumentNodeAsArgumentNode extends ArgumentNode,
SynthCapturedVariablesArgumentNode
{
overlay[global]
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
exists(CallNode callNode | callNode = this.getCallNode() |
callNode = call.getNode() and
@@ -1773,6 +1804,7 @@ class SynthCapturedVariablesArgumentPostUpdateNode extends PostUpdateNodeImpl,
}
/** A synthetic node representing the values of variables captured by a comprehension. */
overlay[local]
class SynthCompCapturedVariablesArgumentNode extends Node, TSynthCompCapturedVariablesArgumentNode {
Comp comp;
@@ -1790,6 +1822,7 @@ class SynthCompCapturedVariablesArgumentNode extends Node, TSynthCompCapturedVar
class SynthCompCapturedVariablesArgumentNodeAsArgumentNode extends SynthCompCapturedVariablesArgumentNode,
ArgumentNode
{
overlay[global]
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
call.(ComprehensionCall).getComprehension() = comp and
pos.isLambdaSelf()
@@ -1834,12 +1867,14 @@ DataFlowCallable viableCallable(DataFlowCall call) {
// =============================================================================
// Remaining required data-flow things
// =============================================================================
overlay[local]
private newtype TReturnKind = TNormalReturnKind()
/**
* A return kind. A return kind describes how a value can be returned
* from a callable. For Python, this is simply a method return.
*/
overlay[local]
class ReturnKind extends TReturnKind {
/** Gets a textual representation of this element. */
string toString() { result = "return" }

View File

@@ -1,3 +1,6 @@
overlay[local?]
module;
private import python
private import DataFlowPublic
private import semmle.python.essa.SsaCompute
@@ -39,6 +42,7 @@ predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos)
//--------
// Nodes
//--------
overlay[local]
predicate isExpressionNode(ControlFlowNode node) { node.getNode() instanceof Expr }
// =============================================================================
@@ -111,6 +115,7 @@ class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode {
* func = foo if <cond> else bar
* func(1, 2, 3)
*/
overlay[local]
class SynthStarArgsElementParameterNode extends ParameterNodeImpl,
TSynthStarArgsElementParameterNode
{
@@ -241,6 +246,7 @@ private predicate dictSplatParameterNodeClearStep(ParameterNode n, DictionaryEle
* (c) since the synthesized nodes are hidden, the reported data-flow paths will be
* collapsed anyway.
*/
overlay[local]
class SynthDictSplatParameterNode extends ParameterNodeImpl, TSynthDictSplatParameterNode {
DataFlowCallable callable;

View File

@@ -1,6 +1,8 @@
/**
* Provides Python-specific definitions for use in the data flow library.
*/
overlay[local]
module;
private import python
private import DataFlowPrivate
@@ -22,6 +24,7 @@ private import semmle.python.frameworks.data.ModelsAsData
* - Module variable nodes: These represent global variables and act as canonical targets for reads and writes of these.
* - Synthetic nodes: These handle flow in various special cases.
*/
overlay[local]
newtype TNode =
/** A node corresponding to a control flow node. */
TCfgNode(ControlFlowNode node) {
@@ -157,6 +160,7 @@ private import semmle.python.internal.CachedStages
* An element, viewed as a node in a data flow graph. Either an SSA variable
* (`EssaNode`) or a control flow node (`CfgNode`).
*/
overlay[local]
class Node extends TNode {
/** Gets a textual representation of this element. */
cached
@@ -324,6 +328,7 @@ class ScopeEntryDefinitionNode extends Node, TScopeEntryDefinitionNode {
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
overlay[local]
class ParameterNode extends Node instanceof ParameterNodeImpl {
/** Gets the parameter corresponding to this node, if any. */
final Parameter getParameter() { result = super.getParameter() }
@@ -345,6 +350,7 @@ class LocalSourceParameterNode extends ExtractedParameterNode, LocalSourceNode {
ExtractedParameterNode parameterNode(Parameter p) { result.getParameter() = p }
/** A data flow node that represents a call argument. */
overlay[global]
abstract class ArgumentNode extends Node {
/** Holds if this argument occurs at the given position in the given call. */
abstract predicate argumentOf(DataFlowCall call, ArgumentPosition pos);
@@ -383,6 +389,7 @@ private Node implicitArgumentNode() {
/**
* A data flow node that represents a call argument found in the source code.
*/
overlay[global]
class ExtractedArgumentNode extends ArgumentNode {
ExtractedArgumentNode() {
this = getCallArgApproximation()
@@ -469,6 +476,7 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
GlobalVariable getVariable() { result = var }
/** Gets a node that reads this variable. */
overlay[global]
Node getARead() {
result = this.getALocalRead()
or
@@ -500,10 +508,12 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
override Location getLocation() { result = mod.getLocation() }
}
overlay[global]
private ModuleVariableNode import_star_read(Node n) {
resolved_import_star_module(result.getModule(), result.getVariable().getId(), n)
}
overlay[global]
pragma[nomagic]
private predicate resolved_import_star_module(Module m, string name, Node n) {
exists(NameNode nn | nn = n.asCfgNode() |
@@ -625,6 +635,7 @@ signature predicate guardChecksSig(GuardNode g, ControlFlowNode node, boolean br
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
overlay[global]
module BarrierGuard<guardChecksSig/3 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
@@ -652,6 +663,7 @@ private module WithParam<ParamSig P> {
*/
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
/** Gets a node that is safely guarded by the given guard check with parameter `param`. */
overlay[global]
ExprNode getABarrierNode(P param) {
exists(GuardNode g, EssaDefinition def, ControlFlowNode node, boolean branch |
AdjacentUses::useOfDef(def, node) and
@@ -671,6 +683,7 @@ module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guar
module ExternalBarrierGuard {
private import semmle.python.ApiGraphs
overlay[global]
private predicate guardCheck(GuardNode g, ControlFlowNode node, boolean branch, string kind) {
exists(API::CallNode call, API::Node parameter |
parameter = call.getAParameter() and
@@ -689,6 +702,7 @@ module ExternalBarrierGuard {
*
* INTERNAL: Do not use.
*/
overlay[global]
ExprNode getAnExternalBarrierNode(string kind) {
result = ParameterizedBarrierGuard<string, guardCheck/4>::getABarrierNode(kind)
}
@@ -698,6 +712,7 @@ module ExternalBarrierGuard {
* Algebraic datatype for tracking data content associated with values.
* Content can be collection elements or object attributes.
*/
overlay[local]
newtype TContent =
/** An element of a list. */
TListElementContent() or
@@ -769,6 +784,7 @@ newtype TContent =
* If the value is a collection, it can have elements,
* if it is an object, it can have attribute values.
*/
overlay[local]
class Content extends TContent {
/** Gets a textual representation of this element. */
string toString() { result = "Content" }

View File

@@ -1,6 +1,8 @@
/**
* Provides classes and predicates for defining flow summaries.
*/
overlay[local]
module;
private import python
private import codeql.dataflow.internal.FlowSummaryImpl
@@ -99,6 +101,7 @@ module Input implements InputSig<Location, DataFlowImplSpecific::PythonDataFlow>
private import Make<Location, DataFlowImplSpecific::PythonDataFlow, Input> as Impl
private module StepsInput implements Impl::Private::StepsInputSig {
overlay[global]
DataFlowCall getACall(Public::SummarizedCallable sc) {
result =
TPotentialLibraryCall([

View File

@@ -1,4 +1,6 @@
/** Provides predicates for reasoning about uses of `import *` in Python. */
overlay[local]
module;
private import python
private import semmle.python.dataflow.new.internal.Builtins
@@ -11,6 +13,7 @@ module ImportStar {
* Holds if `n` is an access of a variable called `name` (which is _not_ the name of a
* built-in, and which is _not_ a global defined in the enclosing module) inside the scope `s`.
*/
overlay[local]
cached
predicate namePossiblyDefinedInImportStar(NameNode n, string name, Scope s) {
n.isLoad() and
@@ -61,6 +64,7 @@ module ImportStar {
* Holds if `n` may refer to a global variable of the same name in the module `m`, accessible
* from the scope of `n` by a chain of `import *` imports.
*/
overlay[global]
cached
predicate importStarResolvesTo(NameNode n, Module m) {
m = getStarImported+(n.getEnclosingModule()) and
@@ -71,6 +75,7 @@ module ImportStar {
/**
* Gets a module that is imported from `m` via `import *`.
*/
overlay[global]
cached
Module getStarImported(Module m) {
exists(ImportStar i, DataFlow::CfgNode imported_module |
@@ -92,6 +97,7 @@ module ImportStar {
*
* this would return the data-flow nodes corresponding to `foo.bar` and `quux`.
*/
overlay[local]
cached
ControlFlowNode potentialImportStarBase(Scope s) {
result = any(ImportStarNode n | n.getScope() = s).getModule()

View File

@@ -166,6 +166,8 @@
*
* `c`: [ListElementContent]
*/
overlay[local]
module;
private import python
private import DataFlowPublic

View File

@@ -5,6 +5,8 @@
* Note that unlike `TypeTracker.qll`, this library only performs
* local tracking within a function.
*/
overlay[local]
module;
private import python
import DataFlowPublic
@@ -77,6 +79,7 @@ class LocalSourceNode extends Node {
}
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */
overlay[caller]
pragma[inline]
predicate flowsTo(Node nodeTo) { Cached::hasLocalSource(nodeTo, this) }
@@ -149,6 +152,7 @@ class LocalSourceNode extends Node {
*
* See `TypeTracker` for more details about how to use this.
*/
overlay[global]
pragma[inline]
LocalSourceNode track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) }
@@ -157,6 +161,7 @@ class LocalSourceNode extends Node {
*
* See `TypeBackTracker` for more details about how to use this.
*/
overlay[global]
pragma[inline]
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t = t2.step(result, this) }
}
@@ -210,6 +215,7 @@ private module FutureWork {
*
* See `TypeTracker` for more details about how to use this.
*/
overlay[global]
pragma[inline]
TypeTrackingNode track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) }
@@ -218,6 +224,7 @@ private module FutureWork {
*
* See `TypeBackTracker` for more details about how to use this.
*/
overlay[global]
pragma[inline]
TypeTrackingNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) }
}

View File

@@ -50,6 +50,8 @@
* keyword arguments using the `__match_args__` attribute on the class. We do not
* currently model this.
*/
overlay[local]
module;
private import python
private import DataFlowPublic

View File

@@ -202,11 +202,18 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
*/
predicate returnStep(Node nodeFrom, LocalSourceNode nodeTo) {
exists(DataFlowPrivate::ExtractedDataFlowCall call |
nodeFrom.(DataFlowPrivate::ReturnNode).getEnclosingCallable() = call.getCallable() and
returnNodeEnclosingCallable(nodeFrom) = call.getCallable() and
nodeTo.(DataFlowPublic::CfgNode).getNode() = call.getNode()
)
}
pragma[nomagic]
private DataFlowDispatch::DataFlowCallable returnNodeEnclosingCallable(
DataFlowPrivate::ReturnNode returnNode
) {
result = returnNode.getEnclosingCallable()
}
/**
* Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`.
*/

View File

@@ -1,4 +1,6 @@
/** Provides logic related to captured variables. */
overlay[local]
module;
private import python
private import DataFlowPublic

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
/*
* Classification of variables. These should be non-overlapping and complete.

View File

@@ -1,6 +1,8 @@
/**
* Library for SSA representation (Static Single Assignment form).
*/
overlay[local]
module;
import python
private import SsaCompute

View File

@@ -88,6 +88,8 @@
* ```
* and thus it falls out that `g3` must be `1`.
*/
overlay[local]
module;
import python
private import semmle.python.internal.CachedStages

View File

@@ -2,6 +2,8 @@
* Provides classes and predicates for determining the uses and definitions of
* variables for ESSA form.
*/
overlay[local]
module;
import python
private import semmle.python.internal.CachedStages

View File

@@ -2,6 +2,8 @@
* Provides classes modeling security-relevant aspects of the `flask` PyPI package.
* See https://flask.palletsprojects.com/en/1.1.x/.
*/
overlay[local?]
module;
private import python
private import semmle.python.dataflow.new.DataFlow

View File

@@ -24,6 +24,18 @@ private import semmle.python.frameworks.data.ModelsAsData
* - https://requests.readthedocs.io/en/latest/
*/
module Requests {
/** Join-order helper for `OutgoingRequestCall`. */
pragma[nomagic]
private API::Node sessionInstance() {
exists(API::Node moduleExporting |
moduleExporting in [
API::moduleImport("requests"), //
API::moduleImport("requests").getMember("sessions")
] and
result = moduleExporting.getMember(["Session", "session"]).getReturn()
)
}
/**
* An outgoing HTTP request, from the `requests` library.
*
@@ -37,15 +49,7 @@ module Requests {
(
this = API::moduleImport("requests").getMember(methodName).getACall()
or
exists(API::Node moduleExporting, API::Node sessionInstance |
moduleExporting in [
API::moduleImport("requests"), //
API::moduleImport("requests").getMember("sessions")
] and
sessionInstance = moduleExporting.getMember(["Session", "session"]).getReturn()
|
this = sessionInstance.getMember(methodName).getACall()
)
this = sessionInstance().getMember(methodName).getACall()
)
}

View File

@@ -2,6 +2,8 @@
* Provides classes modeling security-relevant aspects of the standard libraries.
* Note: some modeling is done internally in the dataflow/taint tracking implementation.
*/
overlay[local?]
module;
private import python
private import semmle.python.dataflow.new.DataFlow

View File

@@ -8,6 +8,8 @@
* The package name refers to the top-level module the import comes from, and not a PyPI package.
* So for `from foo.bar import baz`, the package will be `foo`.
*/
overlay[local?]
module;
private import python
private import internal.ApiGraphModels as Shared

View File

@@ -30,6 +30,7 @@ import semmle.python.dataflow.new.DataFlow::DataFlow as DataFlow
* Holds if models describing `type` may be relevant for the analysis of this database.
*/
bindingset[type]
overlay[local]
predicate isTypeUsed(string type) {
// If `type` is a path, then it is the first component that should be imported.
API::moduleImportExists(type.splitAt(".", 0))
@@ -39,6 +40,7 @@ predicate isTypeUsed(string type) {
* Holds if `type` can be obtained from an instance of `otherType` due to
* language semantics modeled by `getExtraNodeFromType`.
*/
overlay[local]
predicate hasImplicitTypeModel(string type, string otherType) { none() }
/** Gets a Python-specific interpretation of the `(type, path)` tuple after resolving the first `n` access path tokens. */

View File

@@ -3,6 +3,8 @@
*
* Provides helper class for defining additional API graph edges.
*/
overlay[local]
module;
private import python
private import semmle.python.dataflow.new.DataFlow

View File

@@ -35,6 +35,7 @@ module Stages {
* Computes predicates based on the AST.
* These include SSA and basic-blocks.
*/
overlay[local]
cached
module AST {
/**
@@ -176,6 +177,7 @@ module Stages {
* Always holds.
* Ensures that a predicate is evaluated as part of the DataFlow stage.
*/
overlay[local]
cached
predicate ref() { 1 = 1 }

View File

@@ -397,6 +397,12 @@ private predicate neither_class_nor_static_method(Function f) {
)
}
/** Join-order helper for `missing_imported_module`. */
pragma[nomagic]
private predicate module_has_syntaxerror(Module m) {
exists(SyntaxError se | se.getFile() = m.getFile())
}
predicate missing_imported_module(ControlFlowNode imp, Context ctx, string name) {
ctx.isImport() and
imp.(ImportExprNode).getNode().getAnImportedModuleName() = name and
@@ -404,9 +410,9 @@ predicate missing_imported_module(ControlFlowNode imp, Context ctx, string name)
not exists(Module m | m.getName() = name) and
not exists(Builtin b | b.isModule() and b.getName() = name)
or
exists(Module m, SyntaxError se |
exists(Module m |
m.getName() = name and
se.getFile() = m.getFile()
module_has_syntaxerror(m)
)
)
or

View File

@@ -1,3 +1,6 @@
overlay[local?]
module;
import python
private import LegacyPointsTo

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import python
/**

View File

@@ -3,8 +3,10 @@
import python
import semmle.python.dataflow.new.DataFlow
final class FinalAstNode = AstNode;
/** A looping construct. */
abstract class Loop extends AstNode {
abstract class Loop extends FinalAstNode {
/**
* Gets a loop variable of this loop.
* For example, `x` and `y` in `for x,y in pairs: print(x+y)`
@@ -13,9 +15,9 @@ abstract class Loop extends AstNode {
}
/** A `for` loop. */
private class ForLoop extends Loop, For {
private class ForLoop extends Loop instanceof For {
override Variable getALoopVariable() {
this.getTarget() = result.getAnAccess().getParentNode*() and
this.(For).getTarget() = result.getAnAccess().getParentNode*() and
result.getScope() = this.getScope()
}
}

View File

@@ -59,7 +59,9 @@ predicate ok_to_fail(ImportExpr ie) {
os_specific_import(ie) != get_os()
}
class VersionTest extends ControlFlowNode {
final class FinalControlFlowNode = ControlFlowNode;
class VersionTest extends FinalControlFlowNode {
VersionTest() {
exists(string name |
name.matches("%version%") and
@@ -70,7 +72,7 @@ class VersionTest extends ControlFlowNode {
)
}
override string toString() { result = "VersionTest" }
string toString() { result = "VersionTest" }
}
/** A guard on the version of the Python interpreter */

View File

@@ -1,3 +1,6 @@
overlay[local?]
module;
private import python
private import semmle.python.dataflow.new.FlowSummary
private import semmle.python.ApiGraphs

View File

@@ -1,3 +1,6 @@
overlay[local?]
module;
private import python
private import semmle.python.dataflow.new.FlowSummary
private import semmle.python.ApiGraphs

View File

@@ -2,6 +2,7 @@ import python
import semmle.python.frameworks.data.internal.ApiGraphModels as ApiGraphModels
import semmle.python.frameworks.data.ModelsAsData
overlay[local]
class IsTesting extends ApiGraphModels::TestAllModels {
IsTesting() { this = this }
}