mirror of
https://github.com/github/codeql.git
synced 2026-06-23 21:57:01 +02:00
Compare commits
44 Commits
yoff/pytho
...
copilot/sw
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cae623d669 | ||
|
|
326fa74b21 | ||
|
|
138a1c3c99 | ||
|
|
13bf978f64 | ||
|
|
449732a5fe | ||
|
|
f5eef7d3d7 | ||
|
|
28afda1726 | ||
|
|
db8b2cff07 | ||
|
|
3cd6a279d0 | ||
|
|
0f6bccf208 | ||
|
|
7039942a66 | ||
|
|
2453482003 | ||
|
|
de96f6ceac | ||
|
|
c37f235031 | ||
|
|
8908dc4a6e | ||
|
|
53a6afa218 | ||
|
|
0dfa9d72b1 | ||
|
|
6997936a83 | ||
|
|
8debf965ac | ||
|
|
8099b255af | ||
|
|
68a4131523 | ||
|
|
b56342533e | ||
|
|
134cc48c75 | ||
|
|
016c53ccbd | ||
|
|
9b63398874 | ||
|
|
0244d809d1 | ||
|
|
d582d68afd | ||
|
|
9b35117475 | ||
|
|
642e567e48 | ||
|
|
8a62e874ca | ||
|
|
13d4eb6933 | ||
|
|
22ca59d190 | ||
|
|
32a6187434 | ||
|
|
f9953630a7 | ||
|
|
0deb94ac2d | ||
|
|
f8c2f2cbd9 | ||
|
|
984a880089 | ||
|
|
1c62580835 | ||
|
|
99330a65a7 | ||
|
|
fc055a8699 | ||
|
|
65513b8cd2 | ||
|
|
f0576046b1 | ||
|
|
07cf89568f | ||
|
|
42ebe56023 |
3
go/ql/consistency-queries/CfgConsistency.ql
Normal file
3
go/ql/consistency-queries/CfgConsistency.ql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import go
|
||||||
|
private import semmle.go.controlflow.ControlFlowGraphShared
|
||||||
|
import GoCfg::ControlFlow::Consistency
|
||||||
4
go/ql/lib/change-notes/2026-03-30-shared-cfg-library.md
Normal file
4
go/ql/lib/change-notes/2026-03-30-shared-cfg-library.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: fix
|
||||||
|
---
|
||||||
|
* The Go control flow graph implementation has been migrated to use the shared CFG library. This is an internal change with no user-visible API changes.
|
||||||
53
go/ql/lib/printCfg.ql
Normal file
53
go/ql/lib/printCfg.ql
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* @name Print CFG
|
||||||
|
* @description Produces a representation of a file's Control Flow Graph.
|
||||||
|
* This query is used by the VS Code extension.
|
||||||
|
* @id go/print-cfg
|
||||||
|
* @kind graph
|
||||||
|
* @tags ide-contextual-queries/print-cfg
|
||||||
|
*/
|
||||||
|
|
||||||
|
import go
|
||||||
|
import semmle.go.controlflow.ControlFlowGraph
|
||||||
|
private import semmle.go.controlflow.ControlFlowGraphShared
|
||||||
|
|
||||||
|
external string selectedSourceFile();
|
||||||
|
|
||||||
|
private predicate selectedSourceFileAlias = selectedSourceFile/0;
|
||||||
|
|
||||||
|
external int selectedSourceLine();
|
||||||
|
|
||||||
|
private predicate selectedSourceLineAlias = selectedSourceLine/0;
|
||||||
|
|
||||||
|
external int selectedSourceColumn();
|
||||||
|
|
||||||
|
private predicate selectedSourceColumnAlias = selectedSourceColumn/0;
|
||||||
|
|
||||||
|
module ViewCfgQueryInput implements GoCfg::ControlFlow::ViewCfgQueryInputSig<File> {
|
||||||
|
predicate selectedSourceFile = selectedSourceFileAlias/0;
|
||||||
|
|
||||||
|
predicate selectedSourceLine = selectedSourceLineAlias/0;
|
||||||
|
|
||||||
|
predicate selectedSourceColumn = selectedSourceColumnAlias/0;
|
||||||
|
|
||||||
|
predicate cfgScopeSpan(
|
||||||
|
CfgScope scope, File file, int startLine, int startColumn, int endLine, int endColumn
|
||||||
|
) {
|
||||||
|
file = scope.getFile() and
|
||||||
|
scope.getLocation().getStartLine() = startLine and
|
||||||
|
scope.getLocation().getStartColumn() = startColumn and
|
||||||
|
exists(Location loc |
|
||||||
|
loc.getEndLine() = endLine and
|
||||||
|
loc.getEndColumn() = endColumn and
|
||||||
|
loc = scope.(FuncDef).getBody().getLocation()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
file = scope.(File) and
|
||||||
|
startLine = 1 and
|
||||||
|
startColumn = 1 and
|
||||||
|
endLine = file.getNumberOfLines() and
|
||||||
|
endColumn = 999999
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import GoCfg::ControlFlow::ViewCfgQuery<File, ViewCfgQueryInput>
|
||||||
@@ -431,7 +431,7 @@ private class HeuristicLoggerFunction extends Method {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate mayReturnNormally() { logFunctionPrefix != "Fatal" }
|
override predicate mustNotReturnNormally() { logFunctionPrefix = "Fatal" }
|
||||||
|
|
||||||
override predicate mustPanic() { logFunctionPrefix = "Panic" }
|
override predicate mustPanic() { logFunctionPrefix = "Panic" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Provides queries to pretty-print a Go AST as a graph.
|
* Provides queries to pretty-print a Go AST as a graph.
|
||||||
*/
|
*/
|
||||||
overlay[local]
|
overlay[local?]
|
||||||
module;
|
module;
|
||||||
|
|
||||||
import go
|
import go
|
||||||
|
|||||||
@@ -437,11 +437,12 @@ class Function extends ValueEntity, @functionobject {
|
|||||||
* This predicate is an over-approximation: it may hold for functions that can never
|
* This predicate is an over-approximation: it may hold for functions that can never
|
||||||
* return normally, but it never fails to hold for functions that can.
|
* return normally, but it never fails to hold for functions that can.
|
||||||
*
|
*
|
||||||
* Note this is declared here and not in `DeclaredFunction` so that library models can override this
|
* Library models should not override this predicate; override `mustNotReturnNormally`
|
||||||
* by extending `Function` rather than having to remember to extend `DeclaredFunction`.
|
* instead, so that the control-flow graph construction can take the model into account.
|
||||||
*/
|
*/
|
||||||
predicate mayReturnNormally() {
|
predicate mayReturnNormally() {
|
||||||
not this.mustPanic() and
|
not this.mustPanic() and
|
||||||
|
not this.mustNotReturnNormally() and
|
||||||
(ControlFlow::mayReturnNormally(this.getFuncDecl()) or not exists(this.getBody()))
|
(ControlFlow::mayReturnNormally(this.getFuncDecl()) or not exists(this.getBody()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,6 +462,16 @@ class Function extends ValueEntity, @functionobject {
|
|||||||
*/
|
*/
|
||||||
predicate mustPanic() { none() }
|
predicate mustPanic() { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if calling this function never returns normally (for example because it
|
||||||
|
* always panics, exits the process, or loops forever).
|
||||||
|
*
|
||||||
|
* Unlike `mayReturnNormally`, this predicate must be defined without reference to
|
||||||
|
* the control-flow graph, so that it can be used during CFG construction to
|
||||||
|
* suppress normal-flow successors of calls to this function.
|
||||||
|
*/
|
||||||
|
predicate mustNotReturnNormally() { none() }
|
||||||
|
|
||||||
/** Gets the number of parameters of this function. */
|
/** Gets the number of parameters of this function. */
|
||||||
int getNumParameter() { result = this.getType().(SignatureType).getNumParameter() }
|
int getNumParameter() { result = this.getType().(SignatureType).getNumParameter() }
|
||||||
|
|
||||||
|
|||||||
@@ -761,7 +761,7 @@ class CaseClause extends @caseclause, Stmt, ScopeNode {
|
|||||||
*
|
*
|
||||||
* Note that the default clause does not have any expressions.
|
* Note that the default clause does not have any expressions.
|
||||||
*/
|
*/
|
||||||
Expr getAnExpr() { result = this.getAChildExpr() }
|
Expr getAnExpr() { result = this.getExpr(_) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of expressions of this `case` clause.
|
* Gets the number of expressions of this `case` clause.
|
||||||
|
|||||||
@@ -5,66 +5,27 @@ overlay[local]
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
import go
|
import go
|
||||||
private import ControlFlowGraphImpl
|
private import ControlFlowGraphShared
|
||||||
private import codeql.controlflow.BasicBlock as BB
|
|
||||||
private import codeql.controlflow.SuccessorType
|
|
||||||
|
|
||||||
private module Input implements BB::InputSig<Location> {
|
/** A basic block in the control-flow graph. */
|
||||||
/** A delineated part of the AST with its own CFG. */
|
class BasicBlock = GoCfg::Cfg::BasicBlock;
|
||||||
class CfgScope = ControlFlow::Root;
|
|
||||||
|
|
||||||
/** The class of control flow nodes. */
|
/** An entry basic block. */
|
||||||
class Node = ControlFlowNode;
|
class EntryBasicBlock = GoCfg::Cfg::EntryBasicBlock;
|
||||||
|
|
||||||
/** Gets the CFG scope in which this node occurs. */
|
|
||||||
CfgScope nodeGetCfgScope(Node node) { node.getRoot() = result }
|
|
||||||
|
|
||||||
/** Gets an immediate successor of this node. */
|
|
||||||
Node nodeGetASuccessor(Node node, SuccessorType t) {
|
|
||||||
result = node.getASuccessor() and
|
|
||||||
(
|
|
||||||
not result instanceof ControlFlow::ConditionGuardNode and t instanceof DirectSuccessor
|
|
||||||
or
|
|
||||||
t.(BooleanSuccessor).getValue() = result.(ControlFlow::ConditionGuardNode).getOutcome()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `node` represents an entry node to be used when calculating
|
|
||||||
* dominance.
|
|
||||||
*/
|
|
||||||
predicate nodeIsDominanceEntry(Node node) { node instanceof EntryNode }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `node` represents an exit node to be used when calculating
|
|
||||||
* post dominance.
|
|
||||||
*/
|
|
||||||
predicate nodeIsPostDominanceExit(Node node) { node instanceof ExitNode }
|
|
||||||
}
|
|
||||||
|
|
||||||
module Cfg = BB::Make<Location, Input>;
|
|
||||||
|
|
||||||
class BasicBlock = Cfg::BasicBlock;
|
|
||||||
|
|
||||||
class EntryBasicBlock = Cfg::EntryBasicBlock;
|
|
||||||
|
|
||||||
cached
|
|
||||||
private predicate reachableBB(BasicBlock bb) {
|
|
||||||
bb instanceof EntryBasicBlock
|
|
||||||
or
|
|
||||||
exists(BasicBlock predBB | predBB.getASuccessor(_) = bb | reachableBB(predBB))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A basic block that is reachable from an entry basic block.
|
* A basic block that is reachable from an entry basic block.
|
||||||
|
*
|
||||||
|
* Since the shared CFG library only creates nodes for reachable code,
|
||||||
|
* all basic blocks are reachable by construction.
|
||||||
*/
|
*/
|
||||||
class ReachableBasicBlock extends BasicBlock {
|
class ReachableBasicBlock extends BasicBlock {
|
||||||
ReachableBasicBlock() { reachableBB(this) }
|
ReachableBasicBlock() { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reachable basic block with more than one predecessor.
|
* A reachable basic block with more than one predecessor.
|
||||||
*/
|
*/
|
||||||
class ReachableJoinBlock extends ReachableBasicBlock {
|
class ReachableJoinBlock extends ReachableBasicBlock {
|
||||||
ReachableJoinBlock() { this.getFirstNode().isJoin() }
|
ReachableJoinBlock() { this.getFirstNode().(ControlFlow::Node).isJoin() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,17 @@ overlay[local]
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
import go
|
import go
|
||||||
private import ControlFlowGraphImpl
|
private import ControlFlowGraphShared
|
||||||
|
|
||||||
/** Provides helper predicates for mapping btween CFG nodes and the AST. */
|
/** Provides helper predicates for mapping between CFG nodes and the AST. */
|
||||||
module ControlFlow {
|
module ControlFlow {
|
||||||
/** A file or function with which a CFG is associated. */
|
/** A file or function with which a CFG is associated. */
|
||||||
class Root extends AstNode {
|
class Root extends AstNode {
|
||||||
Root() { exists(this.(File).getADecl()) or exists(this.(FuncDef).getBody()) }
|
Root() {
|
||||||
|
exists(this.(FuncDef).getBody())
|
||||||
|
or
|
||||||
|
exists(this.(File).getADecl())
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if `nd` belongs to this file or function. */
|
/** Holds if `nd` belongs to this file or function. */
|
||||||
predicate isRootOf(AstNode nd) {
|
predicate isRootOf(AstNode nd) {
|
||||||
@@ -29,22 +33,16 @@ module ControlFlow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node in the intra-procedural control-flow graph of a Go function or file.
|
* A node in the intra-procedural control-flow graph of a Go function.
|
||||||
*
|
*
|
||||||
* Nodes correspond to expressions and statements that compute a value or perform
|
* Nodes correspond to expressions and statements that compute a value or perform
|
||||||
* an operation (as opposed to providing syntactic structure or type information).
|
* an operation (as opposed to providing syntactic structure or type information).
|
||||||
*
|
*
|
||||||
* There are also synthetic entry and exit nodes for each Go function and file
|
* There are also synthetic entry and exit nodes for each Go function
|
||||||
* that mark the beginning and the end, respectively, of the execution of the
|
* that mark the beginning and the end, respectively, of the execution of the
|
||||||
* function and the loading of the file.
|
* function.
|
||||||
*/
|
*/
|
||||||
class Node extends TControlFlowNode {
|
class Node extends GoCfg::ControlFlowNode {
|
||||||
/** Gets a node that directly follows this one in the control-flow graph. */
|
|
||||||
Node getASuccessor() { result = CFG::succ(this) }
|
|
||||||
|
|
||||||
/** Gets a node that directly precedes this one in the control-flow graph. */
|
|
||||||
Node getAPredecessor() { this = result.getASuccessor() }
|
|
||||||
|
|
||||||
/** Holds if this is a node with more than one successor. */
|
/** Holds if this is a node with more than one successor. */
|
||||||
predicate isBranch() { strictcount(this.getASuccessor()) > 1 }
|
predicate isBranch() { strictcount(this.getASuccessor()) > 1 }
|
||||||
|
|
||||||
@@ -52,22 +50,23 @@ module ControlFlow {
|
|||||||
predicate isJoin() { strictcount(this.getAPredecessor()) > 1 }
|
predicate isJoin() { strictcount(this.getAPredecessor()) > 1 }
|
||||||
|
|
||||||
/** Holds if this is the first control-flow node in `subtree`. */
|
/** Holds if this is the first control-flow node in `subtree`. */
|
||||||
predicate isFirstNodeOf(AstNode subtree) { CFG::firstNode(subtree, this) }
|
predicate isFirstNodeOf(AstNode subtree) {
|
||||||
|
this.isBefore(subtree)
|
||||||
|
or
|
||||||
|
this.injects(subtree)
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if this node is the (unique) entry node of a function or file. */
|
/** Holds if this node is the (unique) entry node of a function. */
|
||||||
predicate isEntryNode() { this instanceof MkEntryNode }
|
predicate isEntryNode() { this instanceof GoCfg::ControlFlow::EntryNode }
|
||||||
|
|
||||||
/** Holds if this node is the (unique) exit node of a function or file. */
|
/** Holds if this node is the (unique) exit node of a function. */
|
||||||
predicate isExitNode() { this instanceof MkExitNode }
|
predicate isExitNode() { this instanceof GoCfg::ControlFlow::ExitNode }
|
||||||
|
|
||||||
/** Gets the basic block to which this node belongs. */
|
|
||||||
BasicBlock getBasicBlock() { result.getANode() = this }
|
|
||||||
|
|
||||||
/** Holds if this node dominates `dominee` in the control-flow graph. */
|
/** Holds if this node dominates `dominee` in the control-flow graph. */
|
||||||
overlay[caller?]
|
overlay[caller?]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate dominatesNode(ControlFlow::Node dominee) {
|
predicate dominatesNode(ControlFlow::Node dominee) {
|
||||||
exists(ReachableBasicBlock thisbb, ReachableBasicBlock dbb, int i, int j |
|
exists(GoCfg::Cfg::BasicBlock thisbb, GoCfg::Cfg::BasicBlock dbb, int i, int j |
|
||||||
this = thisbb.getNode(i) and dominee = dbb.getNode(j)
|
this = thisbb.getNode(i) and dominee = dbb.getNode(j)
|
||||||
|
|
|
|
||||||
thisbb.strictlyDominates(dbb)
|
thisbb.strictlyDominates(dbb)
|
||||||
@@ -76,20 +75,12 @@ module ControlFlow {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the innermost function or file to which this node belongs. */
|
/** Gets the innermost function to which this node belongs. */
|
||||||
Root getRoot() { none() }
|
Root getRoot() { result = this.getEnclosingCallable() }
|
||||||
|
|
||||||
/** Gets the file to which this node belongs. */
|
/** Gets the file to which this node belongs. */
|
||||||
File getFile() { result = this.getLocation().getFile() }
|
File getFile() { result = this.getLocation().getFile() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a textual representation of this control flow node.
|
|
||||||
*/
|
|
||||||
string toString() { result = "control-flow node" }
|
|
||||||
|
|
||||||
/** Gets the source location for this element. */
|
|
||||||
Location getLocation() { none() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: Use `getLocation()` instead.
|
* DEPRECATED: Use `getLocation()` instead.
|
||||||
*
|
*
|
||||||
@@ -113,6 +104,22 @@ module ControlFlow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A synthetic entry node for a function. */
|
||||||
|
class EntryNode extends Node instanceof GoCfg::ControlFlow::EntryNode { }
|
||||||
|
|
||||||
|
/** A synthetic exit node for a function. */
|
||||||
|
class ExitNode extends Node instanceof GoCfg::ControlFlow::ExitNode { }
|
||||||
|
|
||||||
|
private predicate isBranchConditionRoot(Expr expr) {
|
||||||
|
expr = any(LogicalBinaryExpr lbe).getLeftOperand()
|
||||||
|
or
|
||||||
|
expr = any(ForStmt fs).getCond()
|
||||||
|
or
|
||||||
|
expr = any(IfStmt is).getCond()
|
||||||
|
or
|
||||||
|
expr = any(ExpressionSwitchStmt ess | not exists(ess.getExpr())).getACase().getAnExpr()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A control-flow node that initializes or updates the value of a constant, a variable,
|
* A control-flow node that initializes or updates the value of a constant, a variable,
|
||||||
* a field, or an (array, slice, or map) element.
|
* a field, or an (array, slice, or map) element.
|
||||||
@@ -172,7 +179,7 @@ module ControlFlow {
|
|||||||
exists(IR::FieldTarget trg | trg = super.getLhs() |
|
exists(IR::FieldTarget trg | trg = super.getLhs() |
|
||||||
(
|
(
|
||||||
trg.getBase() = base or
|
trg.getBase() = base or
|
||||||
trg.getBase() = MkImplicitDeref(base.(IR::EvalInstruction).getExpr())
|
trg.getBase() = IR::implicitDerefInstruction(base.(IR::EvalInstruction).getExpr())
|
||||||
) and
|
) and
|
||||||
trg.getField() = f and
|
trg.getField() = f and
|
||||||
super.getRhs() = rhs
|
super.getRhs() = rhs
|
||||||
@@ -220,7 +227,7 @@ module ControlFlow {
|
|||||||
exists(IR::ElementTarget trg | trg = super.getLhs() |
|
exists(IR::ElementTarget trg | trg = super.getLhs() |
|
||||||
(
|
(
|
||||||
trg.getBase() = base or
|
trg.getBase() = base or
|
||||||
trg.getBase() = MkImplicitDeref(base.(IR::EvalInstruction).getExpr())
|
trg.getBase() = IR::implicitDerefInstruction(base.(IR::EvalInstruction).getExpr())
|
||||||
) and
|
) and
|
||||||
trg.getIndex() = index and
|
trg.getIndex() = index and
|
||||||
super.getRhs() = rhs
|
super.getRhs() = rhs
|
||||||
@@ -250,11 +257,19 @@ module ControlFlow {
|
|||||||
* A control-flow node recording the fact that a certain expression has a known
|
* A control-flow node recording the fact that a certain expression has a known
|
||||||
* Boolean value at this point in the program.
|
* Boolean value at this point in the program.
|
||||||
*/
|
*/
|
||||||
class ConditionGuardNode extends IR::Instruction, MkConditionGuardNode {
|
class ConditionGuardNode extends IR::Instruction {
|
||||||
Expr cond;
|
Expr cond;
|
||||||
boolean outcome;
|
boolean outcome;
|
||||||
|
|
||||||
ConditionGuardNode() { this = MkConditionGuardNode(cond, outcome) }
|
ConditionGuardNode() {
|
||||||
|
isBranchConditionRoot(cond) and
|
||||||
|
this.isAfterTrue(cond) and
|
||||||
|
outcome = true
|
||||||
|
or
|
||||||
|
isBranchConditionRoot(cond) and
|
||||||
|
this.isAfterFalse(cond) and
|
||||||
|
outcome = false
|
||||||
|
}
|
||||||
|
|
||||||
private predicate ensuresAux(Expr expr, boolean b) {
|
private predicate ensuresAux(Expr expr, boolean b) {
|
||||||
expr = cond and b = outcome
|
expr = cond and b = outcome
|
||||||
@@ -320,21 +335,17 @@ module ControlFlow {
|
|||||||
boolean getOutcome() { result = outcome }
|
boolean getOutcome() { result = outcome }
|
||||||
|
|
||||||
override Root getRoot() { result.isRootOf(cond) }
|
override Root getRoot() { result.isRootOf(cond) }
|
||||||
|
|
||||||
override string toString() { result = cond + " is " + outcome }
|
|
||||||
|
|
||||||
override Location getLocation() { result = cond.getLocation() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entry node of function or file `root`.
|
* Gets the entry node of function `root`.
|
||||||
*/
|
*/
|
||||||
Node entryNode(Root root) { result = MkEntryNode(root) }
|
EntryNode entryNode(Root root) { result.getEnclosingCallable() = root }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the exit node of function or file `root`.
|
* Gets the exit node of function `root`.
|
||||||
*/
|
*/
|
||||||
Node exitNode(Root root) { result = MkExitNode(root) }
|
ExitNode exitNode(Root root) { result.getEnclosingCallable() = root }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the function `f` may return without panicking, exiting the process, or looping forever.
|
* Holds if the function `f` may return without panicking, exiting the process, or looping forever.
|
||||||
@@ -342,7 +353,12 @@ module ControlFlow {
|
|||||||
* This is defined conservatively, and so may also hold of a function that in fact
|
* This is defined conservatively, and so may also hold of a function that in fact
|
||||||
* cannot return normally, but never fails to hold of a function that can return normally.
|
* cannot return normally, but never fails to hold of a function that can return normally.
|
||||||
*/
|
*/
|
||||||
predicate mayReturnNormally(FuncDecl f) { CFG::mayReturnNormally(f.getBody()) }
|
predicate mayReturnNormally(FuncDecl f) {
|
||||||
|
exists(GoCfg::ControlFlow::NormalExitNode exit |
|
||||||
|
exit.getEnclosingCallable() = f and
|
||||||
|
exists(exit.getAPredecessor())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `pred` is the node for the case `testExpr` in an expression
|
* Holds if `pred` is the node for the case `testExpr` in an expression
|
||||||
@@ -352,10 +368,18 @@ module ControlFlow {
|
|||||||
predicate isSwitchCaseTestPassingEdge(
|
predicate isSwitchCaseTestPassingEdge(
|
||||||
ControlFlow::Node pred, ControlFlow::Node succ, Expr switchExpr, Expr testExpr
|
ControlFlow::Node pred, ControlFlow::Node succ, Expr switchExpr, Expr testExpr
|
||||||
) {
|
) {
|
||||||
CFG::isSwitchCaseTestPassingEdge(pred, succ, switchExpr, testExpr)
|
exists(ExpressionSwitchStmt ess, CaseClause cc, int i |
|
||||||
|
ess.getExpr() = switchExpr and
|
||||||
|
cc = ess.getACase() and
|
||||||
|
testExpr = cc.getExpr(i) and
|
||||||
|
pred.isAfter(testExpr) and
|
||||||
|
succ.isFirstNodeOf(cc.getStmt(0))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ControlFlowNode = ControlFlow::Node;
|
class ControlFlowNode = ControlFlow::Node;
|
||||||
|
|
||||||
|
class CfgScope = GoCfg::CfgScope;
|
||||||
|
|
||||||
class Write = ControlFlow::WriteNode;
|
class Write = ControlFlow::WriteNode;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1854
go/ql/lib/semmle/go/controlflow/ControlFlowGraphShared.qll
Normal file
1854
go/ql/lib/semmle/go/controlflow/ControlFlowGraphShared.qll
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -200,7 +200,7 @@ private ControlFlow::Node mostRecentSideEffect(ControlFlow::Node entry, ControlF
|
|||||||
|
|
||||||
cached
|
cached
|
||||||
private ControlFlow::Node mostRecentSideEffectUnique(ControlFlow::Node node) {
|
private ControlFlow::Node mostRecentSideEffectUnique(ControlFlow::Node node) {
|
||||||
result = unique( | | mostRecentSideEffect(_, node))
|
result = unique( | | mostRecentSideEffect(getControlFlowEntry(node), node))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used to represent the "global value number" of an expression. */
|
/** Used to represent the "global value number" of an expression. */
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ module;
|
|||||||
import go
|
import go
|
||||||
private import codeql.ssa.Ssa as SsaImplCommon
|
private import codeql.ssa.Ssa as SsaImplCommon
|
||||||
private import semmle.go.controlflow.BasicBlocks as BasicBlocks
|
private import semmle.go.controlflow.BasicBlocks as BasicBlocks
|
||||||
|
private import semmle.go.controlflow.ControlFlowGraphShared
|
||||||
|
|
||||||
private class BasicBlock = BasicBlocks::BasicBlock;
|
private class BasicBlock = BasicBlocks::BasicBlock;
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ private module Internal {
|
|||||||
/** Holds if the `i`th node of `bb` in function `f` is an entry node. */
|
/** Holds if the `i`th node of `bb` in function `f` is an entry node. */
|
||||||
private predicate entryNode(FuncDef f, BasicBlock bb, int i) {
|
private predicate entryNode(FuncDef f, BasicBlock bb, int i) {
|
||||||
f = bb.getScope() and
|
f = bb.getScope() and
|
||||||
bb.getNode(i).isEntryNode()
|
bb.getNode(i).(ControlFlow::Node).isEntryNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,7 +111,7 @@ private module Internal {
|
|||||||
v.isCaptured() and
|
v.isCaptured() and
|
||||||
exists(FuncDef f |
|
exists(FuncDef f |
|
||||||
f = bb.getScope() and
|
f = bb.getScope() and
|
||||||
bb.getLastNode().isExitNode() and
|
bb.getLastNode().(ControlFlow::Node).isExitNode() and
|
||||||
i = bb.length() - 1 and
|
i = bb.length() - 1 and
|
||||||
certain = false
|
certain = false
|
||||||
|
|
|
|
||||||
@@ -126,7 +127,7 @@ private module Internal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
import Internal
|
import Internal
|
||||||
import SsaImplCommon::Make<Location, BasicBlocks::Cfg, SsaInput> as Impl
|
import SsaImplCommon::Make<Location, GoCfg::Cfg, SsaInput> as Impl
|
||||||
|
|
||||||
final class Definition = Impl::Definition;
|
final class Definition = Impl::Definition;
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ module Glog {
|
|||||||
/** Holds if this function takes a format string. */
|
/** Holds if this function takes a format string. */
|
||||||
predicate formatter() { format = "f" }
|
predicate formatter() { format = "f" }
|
||||||
|
|
||||||
override predicate mayReturnNormally() { level != "Fatal" and level != "Exit" }
|
override predicate mustNotReturnNormally() { level = "Fatal" or level = "Exit" }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StringFormatter extends StringOps::Formatting::Range instanceof GlogFunction {
|
private class StringFormatter extends StringOps::Formatting::Range instanceof GlogFunction {
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ module Logrus {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate mayReturnNormally() {
|
override predicate mustNotReturnNormally() {
|
||||||
not exists(string level, string suffix | level = ["Fatal", "Panic"] |
|
exists(string level, string suffix | level = ["Fatal", "Panic"] |
|
||||||
this.getName() = level + suffix
|
this.getName() = level + suffix
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ module Revel {
|
|||||||
|
|
||||||
private IR::EvalInstruction skipImplicitFieldReads(IR::Instruction insn) {
|
private IR::EvalInstruction skipImplicitFieldReads(IR::Instruction insn) {
|
||||||
result = insn or
|
result = insn or
|
||||||
result = skipImplicitFieldReads(insn.(IR::ImplicitFieldReadInstruction).getBase())
|
result = skipImplicitFieldReads(insn.(IR::ImplicitFieldReadInstruction).getBaseInstruction())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A call to `Controller.Render`. */
|
/** A call to `Controller.Render`. */
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ module Zap {
|
|||||||
this.hasQualifiedName(packagePath(), "SugaredLogger", "Fatal" + getSuffix())
|
this.hasQualifiedName(packagePath(), "SugaredLogger", "Fatal" + getSuffix())
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate mayReturnNormally() { none() }
|
override predicate mustNotReturnNormally() { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A Zap logging function which always panics. */
|
/** A Zap logging function which always panics. */
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ module Log {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate mayReturnNormally() { none() }
|
override predicate mustNotReturnNormally() { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A log function which must panic. */
|
/** A log function which must panic. */
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ module Os {
|
|||||||
private class Exit extends Function {
|
private class Exit extends Function {
|
||||||
Exit() { this.hasQualifiedName("os", "Exit") }
|
Exit() { this.hasQualifiedName("os", "Exit") }
|
||||||
|
|
||||||
override predicate mayReturnNormally() { none() }
|
override predicate mustNotReturnNormally() { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// These models are not implemented using Models-as-Data because they represent reverse flow.
|
// These models are not implemented using Models-as-Data because they represent reverse flow.
|
||||||
|
|||||||
@@ -14,11 +14,36 @@
|
|||||||
|
|
||||||
import go
|
import go
|
||||||
|
|
||||||
ControlFlow::Node nonGuardPredecessor(ControlFlow::Node nd) {
|
/**
|
||||||
exists(ControlFlow::Node pred | pred = nd.getAPredecessor() |
|
* Holds if `s` is reachable, that is, the control-flow graph contains a node for it.
|
||||||
if pred instanceof ControlFlow::ConditionGuardNode
|
*
|
||||||
then result = nonGuardPredecessor(pred)
|
* The shared control-flow library does not create control-flow nodes for dead code, so an
|
||||||
else result = pred
|
* unreachable statement has no first control-flow node.
|
||||||
|
*/
|
||||||
|
predicate isReachable(Stmt s) { exists(s.getFirstControlFlowNode()) }
|
||||||
|
|
||||||
|
/** Gets the statement immediately preceding `s` in a statement list, if any. */
|
||||||
|
Stmt getPreviousStmt(Stmt s) {
|
||||||
|
exists(BlockStmt b, int i | s = b.getStmt(i) and result = b.getStmt(i - 1))
|
||||||
|
or
|
||||||
|
exists(CaseClause c, int i | s = c.getStmt(i) and result = c.getStmt(i - 1))
|
||||||
|
or
|
||||||
|
exists(CommClause c, int i | s = c.getStmt(i) and result = c.getStmt(i - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `s` is unreachable but the code that would precede it in the control-flow graph is
|
||||||
|
* reachable, so that `s` is the first unreachable statement in a run of dead code.
|
||||||
|
*/
|
||||||
|
predicate firstUnreachableStmt(Stmt s) {
|
||||||
|
not isReachable(s) and
|
||||||
|
not s instanceof EmptyStmt and
|
||||||
|
(
|
||||||
|
// a statement whose preceding statement in the same list is reachable
|
||||||
|
isReachable(getPreviousStmt(s))
|
||||||
|
or
|
||||||
|
// the post statement of a `for` loop whose body is entered
|
||||||
|
exists(ForStmt f | s = f.getPost() and isReachable(f.getBody().getAStmt()))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,18 +88,13 @@ predicate allowlist(Stmt s) {
|
|||||||
forall(Expr retval | retval = ret.getAnExpr() | isAllowedReturnValue(retval))
|
forall(Expr retval | retval = ret.getAnExpr() | isAllowedReturnValue(retval))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// statements in an `if false { ... }` and similar
|
// statements deliberately made unreachable by a constant condition, such as the code
|
||||||
exists(IfStmt is, ControlFlow::ConditionGuardNode iffalse, Expr cond, boolean b |
|
// following `if true { return }`
|
||||||
iffalse.getCondition() = is.getCond() and
|
exists(getPreviousStmt(s).(IfStmt).getCond().getBoolValue())
|
||||||
iffalse = s.getFirstControlFlowNode().getAPredecessor() and
|
|
||||||
cond.getBoolValue() = b and
|
|
||||||
iffalse.ensures(DataFlow::exprNode(cond), b.booleanNot())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
from Stmt s, ControlFlow::Node fst
|
from Stmt s
|
||||||
where
|
where
|
||||||
fst = s.getFirstControlFlowNode() and
|
firstUnreachableStmt(s) and
|
||||||
not exists(nonGuardPredecessor(fst)) and
|
|
||||||
not allowlist(s)
|
not allowlist(s)
|
||||||
select s, "This statement is unreachable."
|
select s, "This statement is unreachable."
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
| main.go:23:3:23:13 | assignment to field Status | main.go:23:17:23:21 | "200" |
|
| main.go:23:3:23:21 | assign:0 ... = ... | main.go:23:17:23:21 | "200" |
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
| file://:0:0:0:0 | [summary param] -1 in Clone |
|
| file://:0:0:0:0 | [summary param] -1 in Clone |
|
||||||
| file://:0:0:0:0 | [summary param] -1 in Write |
|
| file://:0:0:0:0 | [summary param] -1 in Write |
|
||||||
| file://:0:0:0:0 | [summary param] -1 in WriteProxy |
|
| file://:0:0:0:0 | [summary param] -1 in WriteProxy |
|
||||||
| main.go:18:12:18:14 | SSA def(req) |
|
| main.go:18:103:26:1 | SSA def(req) |
|
||||||
| main.go:18:12:18:14 | argument corresponding to req |
|
| main.go:18:103:26:1 | arg:0 block statement |
|
||||||
| main.go:20:5:20:7 | req |
|
| main.go:20:5:20:7 | req |
|
||||||
| main.go:20:5:20:7 | req [postupdate] |
|
| main.go:20:5:20:7 | req [postupdate] |
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
| main.go:29:2:29:4 | assignment to err | main.go:29:9:29:31 | call to test1 |
|
| main.go:29:2:29:31 | assign:0 ... := ... | main.go:29:9:29:31 | call to test1 |
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
| main.go:10:2:12:3 | ... := ...[0] | This Pam transaction may not be secure. |
|
| main.go:10:2:12:3 | extract:0 ... := ... | This Pam transaction may not be secure. |
|
||||||
|
|||||||
@@ -8,23 +8,23 @@
|
|||||||
edges
|
edges
|
||||||
| DivideByZero.go:10:12:10:16 | selection of URL | DivideByZero.go:10:12:10:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
| DivideByZero.go:10:12:10:16 | selection of URL | DivideByZero.go:10:12:10:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
||||||
| DivideByZero.go:10:12:10:24 | call to Query | DivideByZero.go:11:27:11:32 | param1 | provenance | |
|
| DivideByZero.go:10:12:10:24 | call to Query | DivideByZero.go:11:27:11:32 | param1 | provenance | |
|
||||||
| DivideByZero.go:11:2:11:33 | ... := ...[0] | DivideByZero.go:12:16:12:20 | value | provenance | |
|
| DivideByZero.go:11:2:11:33 | extract:0 ... := ... | DivideByZero.go:12:16:12:20 | value | provenance | |
|
||||||
| DivideByZero.go:11:27:11:32 | param1 | DivideByZero.go:11:2:11:33 | ... := ...[0] | provenance | Config |
|
| DivideByZero.go:11:27:11:32 | param1 | DivideByZero.go:11:2:11:33 | extract:0 ... := ... | provenance | Config |
|
||||||
| DivideByZero.go:17:12:17:16 | selection of URL | DivideByZero.go:17:12:17:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
| DivideByZero.go:17:12:17:16 | selection of URL | DivideByZero.go:17:12:17:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
||||||
| DivideByZero.go:17:12:17:24 | call to Query | DivideByZero.go:18:11:18:24 | type conversion | provenance | |
|
| DivideByZero.go:17:12:17:24 | call to Query | DivideByZero.go:18:11:18:24 | type conversion | provenance | |
|
||||||
| DivideByZero.go:18:11:18:24 | type conversion | DivideByZero.go:19:16:19:20 | value | provenance | |
|
| DivideByZero.go:18:11:18:24 | type conversion | DivideByZero.go:19:16:19:20 | value | provenance | |
|
||||||
| DivideByZero.go:24:12:24:16 | selection of URL | DivideByZero.go:24:12:24:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
| DivideByZero.go:24:12:24:16 | selection of URL | DivideByZero.go:24:12:24:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
||||||
| DivideByZero.go:24:12:24:24 | call to Query | DivideByZero.go:25:31:25:36 | param1 | provenance | |
|
| DivideByZero.go:24:12:24:24 | call to Query | DivideByZero.go:25:31:25:36 | param1 | provenance | |
|
||||||
| DivideByZero.go:25:2:25:45 | ... := ...[0] | DivideByZero.go:26:16:26:20 | value | provenance | |
|
| DivideByZero.go:25:2:25:45 | extract:0 ... := ... | DivideByZero.go:26:16:26:20 | value | provenance | |
|
||||||
| DivideByZero.go:25:31:25:36 | param1 | DivideByZero.go:25:2:25:45 | ... := ...[0] | provenance | Config |
|
| DivideByZero.go:25:31:25:36 | param1 | DivideByZero.go:25:2:25:45 | extract:0 ... := ... | provenance | Config |
|
||||||
| DivideByZero.go:31:12:31:16 | selection of URL | DivideByZero.go:31:12:31:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
| DivideByZero.go:31:12:31:16 | selection of URL | DivideByZero.go:31:12:31:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
||||||
| DivideByZero.go:31:12:31:24 | call to Query | DivideByZero.go:32:33:32:38 | param1 | provenance | |
|
| DivideByZero.go:31:12:31:24 | call to Query | DivideByZero.go:32:33:32:38 | param1 | provenance | |
|
||||||
| DivideByZero.go:32:2:32:43 | ... := ...[0] | DivideByZero.go:33:16:33:20 | value | provenance | |
|
| DivideByZero.go:32:2:32:43 | extract:0 ... := ... | DivideByZero.go:33:16:33:20 | value | provenance | |
|
||||||
| DivideByZero.go:32:33:32:38 | param1 | DivideByZero.go:32:2:32:43 | ... := ...[0] | provenance | Config |
|
| DivideByZero.go:32:33:32:38 | param1 | DivideByZero.go:32:2:32:43 | extract:0 ... := ... | provenance | Config |
|
||||||
| DivideByZero.go:38:12:38:16 | selection of URL | DivideByZero.go:38:12:38:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
| DivideByZero.go:38:12:38:16 | selection of URL | DivideByZero.go:38:12:38:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
||||||
| DivideByZero.go:38:12:38:24 | call to Query | DivideByZero.go:39:32:39:37 | param1 | provenance | |
|
| DivideByZero.go:38:12:38:24 | call to Query | DivideByZero.go:39:32:39:37 | param1 | provenance | |
|
||||||
| DivideByZero.go:39:2:39:46 | ... := ...[0] | DivideByZero.go:40:16:40:20 | value | provenance | |
|
| DivideByZero.go:39:2:39:46 | extract:0 ... := ... | DivideByZero.go:40:16:40:20 | value | provenance | |
|
||||||
| DivideByZero.go:39:32:39:37 | param1 | DivideByZero.go:39:2:39:46 | ... := ...[0] | provenance | Config |
|
| DivideByZero.go:39:32:39:37 | param1 | DivideByZero.go:39:2:39:46 | extract:0 ... := ... | provenance | Config |
|
||||||
| DivideByZero.go:54:12:54:16 | selection of URL | DivideByZero.go:54:12:54:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
| DivideByZero.go:54:12:54:16 | selection of URL | DivideByZero.go:54:12:54:24 | call to Query | provenance | Src:MaD:1 MaD:2 |
|
||||||
| DivideByZero.go:54:12:54:24 | call to Query | DivideByZero.go:55:11:55:24 | type conversion | provenance | |
|
| DivideByZero.go:54:12:54:24 | call to Query | DivideByZero.go:55:11:55:24 | type conversion | provenance | |
|
||||||
| DivideByZero.go:55:11:55:24 | type conversion | DivideByZero.go:57:17:57:21 | value | provenance | |
|
| DivideByZero.go:55:11:55:24 | type conversion | DivideByZero.go:57:17:57:21 | value | provenance | |
|
||||||
@@ -34,7 +34,7 @@ models
|
|||||||
nodes
|
nodes
|
||||||
| DivideByZero.go:10:12:10:16 | selection of URL | semmle.label | selection of URL |
|
| DivideByZero.go:10:12:10:16 | selection of URL | semmle.label | selection of URL |
|
||||||
| DivideByZero.go:10:12:10:24 | call to Query | semmle.label | call to Query |
|
| DivideByZero.go:10:12:10:24 | call to Query | semmle.label | call to Query |
|
||||||
| DivideByZero.go:11:2:11:33 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| DivideByZero.go:11:2:11:33 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| DivideByZero.go:11:27:11:32 | param1 | semmle.label | param1 |
|
| DivideByZero.go:11:27:11:32 | param1 | semmle.label | param1 |
|
||||||
| DivideByZero.go:12:16:12:20 | value | semmle.label | value |
|
| DivideByZero.go:12:16:12:20 | value | semmle.label | value |
|
||||||
| DivideByZero.go:17:12:17:16 | selection of URL | semmle.label | selection of URL |
|
| DivideByZero.go:17:12:17:16 | selection of URL | semmle.label | selection of URL |
|
||||||
@@ -43,17 +43,17 @@ nodes
|
|||||||
| DivideByZero.go:19:16:19:20 | value | semmle.label | value |
|
| DivideByZero.go:19:16:19:20 | value | semmle.label | value |
|
||||||
| DivideByZero.go:24:12:24:16 | selection of URL | semmle.label | selection of URL |
|
| DivideByZero.go:24:12:24:16 | selection of URL | semmle.label | selection of URL |
|
||||||
| DivideByZero.go:24:12:24:24 | call to Query | semmle.label | call to Query |
|
| DivideByZero.go:24:12:24:24 | call to Query | semmle.label | call to Query |
|
||||||
| DivideByZero.go:25:2:25:45 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| DivideByZero.go:25:2:25:45 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| DivideByZero.go:25:31:25:36 | param1 | semmle.label | param1 |
|
| DivideByZero.go:25:31:25:36 | param1 | semmle.label | param1 |
|
||||||
| DivideByZero.go:26:16:26:20 | value | semmle.label | value |
|
| DivideByZero.go:26:16:26:20 | value | semmle.label | value |
|
||||||
| DivideByZero.go:31:12:31:16 | selection of URL | semmle.label | selection of URL |
|
| DivideByZero.go:31:12:31:16 | selection of URL | semmle.label | selection of URL |
|
||||||
| DivideByZero.go:31:12:31:24 | call to Query | semmle.label | call to Query |
|
| DivideByZero.go:31:12:31:24 | call to Query | semmle.label | call to Query |
|
||||||
| DivideByZero.go:32:2:32:43 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| DivideByZero.go:32:2:32:43 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| DivideByZero.go:32:33:32:38 | param1 | semmle.label | param1 |
|
| DivideByZero.go:32:33:32:38 | param1 | semmle.label | param1 |
|
||||||
| DivideByZero.go:33:16:33:20 | value | semmle.label | value |
|
| DivideByZero.go:33:16:33:20 | value | semmle.label | value |
|
||||||
| DivideByZero.go:38:12:38:16 | selection of URL | semmle.label | selection of URL |
|
| DivideByZero.go:38:12:38:16 | selection of URL | semmle.label | selection of URL |
|
||||||
| DivideByZero.go:38:12:38:24 | call to Query | semmle.label | call to Query |
|
| DivideByZero.go:38:12:38:24 | call to Query | semmle.label | call to Query |
|
||||||
| DivideByZero.go:39:2:39:46 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| DivideByZero.go:39:2:39:46 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| DivideByZero.go:39:32:39:37 | param1 | semmle.label | param1 |
|
| DivideByZero.go:39:32:39:37 | param1 | semmle.label | param1 |
|
||||||
| DivideByZero.go:40:16:40:20 | value | semmle.label | value |
|
| DivideByZero.go:40:16:40:20 | value | semmle.label | value |
|
||||||
| DivideByZero.go:54:12:54:16 | selection of URL | semmle.label | selection of URL |
|
| DivideByZero.go:54:12:54:16 | selection of URL | semmle.label | selection of URL |
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ edges
|
|||||||
| Dsn.go:28:102:28:109 | index expression | Dsn.go:28:11:28:110 | []type{args} [array] | provenance | |
|
| Dsn.go:28:102:28:109 | index expression | Dsn.go:28:11:28:110 | []type{args} [array] | provenance | |
|
||||||
| Dsn.go:28:102:28:109 | index expression | Dsn.go:28:11:28:110 | call to Sprintf | provenance | FunctionModel |
|
| Dsn.go:28:102:28:109 | index expression | Dsn.go:28:11:28:110 | call to Sprintf | provenance | FunctionModel |
|
||||||
| Dsn.go:63:9:63:11 | cfg [postupdate] [pointer] | Dsn.go:67:102:67:104 | cfg [pointer] | provenance | |
|
| Dsn.go:63:9:63:11 | cfg [postupdate] [pointer] | Dsn.go:67:102:67:104 | cfg [pointer] | provenance | |
|
||||||
| Dsn.go:63:9:63:11 | implicit dereference [postupdate] | Dsn.go:63:9:63:11 | cfg [postupdate] [pointer] | provenance | |
|
| Dsn.go:63:9:63:11 | implicit-deref cfg [postupdate] | Dsn.go:63:9:63:11 | cfg [postupdate] [pointer] | provenance | |
|
||||||
| Dsn.go:63:9:63:11 | implicit dereference [postupdate] | Dsn.go:67:102:67:108 | selection of dsn | provenance | |
|
| Dsn.go:63:9:63:11 | implicit-deref cfg [postupdate] | Dsn.go:67:102:67:108 | selection of dsn | provenance | |
|
||||||
| Dsn.go:63:19:63:25 | selection of Args | Dsn.go:63:19:63:29 | slice expression | provenance | Src:MaD:1 |
|
| Dsn.go:63:19:63:25 | selection of Args | Dsn.go:63:19:63:29 | slice expression | provenance | Src:MaD:1 |
|
||||||
| Dsn.go:63:19:63:29 | slice expression | Dsn.go:63:9:63:11 | implicit dereference [postupdate] | provenance | FunctionModel |
|
| Dsn.go:63:19:63:29 | slice expression | Dsn.go:63:9:63:11 | implicit-deref cfg [postupdate] | provenance | FunctionModel |
|
||||||
| Dsn.go:67:11:67:109 | []type{args} [array] | Dsn.go:67:11:67:109 | call to Sprintf | provenance | MaD:2 |
|
| Dsn.go:67:11:67:109 | []type{args} [array] | Dsn.go:67:11:67:109 | call to Sprintf | provenance | MaD:2 |
|
||||||
| Dsn.go:67:11:67:109 | call to Sprintf | Dsn.go:68:29:68:33 | dbDSN | provenance | |
|
| Dsn.go:67:11:67:109 | call to Sprintf | Dsn.go:68:29:68:33 | dbDSN | provenance | |
|
||||||
| Dsn.go:67:102:67:104 | cfg [pointer] | Dsn.go:67:102:67:104 | implicit dereference | provenance | |
|
| Dsn.go:67:102:67:104 | cfg [pointer] | Dsn.go:67:102:67:104 | implicit-deref cfg | provenance | |
|
||||||
| Dsn.go:67:102:67:104 | implicit dereference | Dsn.go:67:102:67:108 | selection of dsn | provenance | |
|
| Dsn.go:67:102:67:104 | implicit-deref cfg | Dsn.go:67:102:67:108 | selection of dsn | provenance | |
|
||||||
| Dsn.go:67:102:67:108 | selection of dsn | Dsn.go:67:11:67:109 | []type{args} [array] | provenance | |
|
| Dsn.go:67:102:67:108 | selection of dsn | Dsn.go:67:11:67:109 | []type{args} [array] | provenance | |
|
||||||
| Dsn.go:67:102:67:108 | selection of dsn | Dsn.go:67:11:67:109 | call to Sprintf | provenance | FunctionModel |
|
| Dsn.go:67:102:67:108 | selection of dsn | Dsn.go:67:11:67:109 | call to Sprintf | provenance | FunctionModel |
|
||||||
models
|
models
|
||||||
@@ -28,13 +28,13 @@ nodes
|
|||||||
| Dsn.go:28:102:28:109 | index expression | semmle.label | index expression |
|
| Dsn.go:28:102:28:109 | index expression | semmle.label | index expression |
|
||||||
| Dsn.go:29:29:29:33 | dbDSN | semmle.label | dbDSN |
|
| Dsn.go:29:29:29:33 | dbDSN | semmle.label | dbDSN |
|
||||||
| Dsn.go:63:9:63:11 | cfg [postupdate] [pointer] | semmle.label | cfg [postupdate] [pointer] |
|
| Dsn.go:63:9:63:11 | cfg [postupdate] [pointer] | semmle.label | cfg [postupdate] [pointer] |
|
||||||
| Dsn.go:63:9:63:11 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
|
| Dsn.go:63:9:63:11 | implicit-deref cfg [postupdate] | semmle.label | implicit-deref cfg [postupdate] |
|
||||||
| Dsn.go:63:19:63:25 | selection of Args | semmle.label | selection of Args |
|
| Dsn.go:63:19:63:25 | selection of Args | semmle.label | selection of Args |
|
||||||
| Dsn.go:63:19:63:29 | slice expression | semmle.label | slice expression |
|
| Dsn.go:63:19:63:29 | slice expression | semmle.label | slice expression |
|
||||||
| Dsn.go:67:11:67:109 | []type{args} [array] | semmle.label | []type{args} [array] |
|
| Dsn.go:67:11:67:109 | []type{args} [array] | semmle.label | []type{args} [array] |
|
||||||
| Dsn.go:67:11:67:109 | call to Sprintf | semmle.label | call to Sprintf |
|
| Dsn.go:67:11:67:109 | call to Sprintf | semmle.label | call to Sprintf |
|
||||||
| Dsn.go:67:102:67:104 | cfg [pointer] | semmle.label | cfg [pointer] |
|
| Dsn.go:67:102:67:104 | cfg [pointer] | semmle.label | cfg [pointer] |
|
||||||
| Dsn.go:67:102:67:104 | implicit dereference | semmle.label | implicit dereference |
|
| Dsn.go:67:102:67:104 | implicit-deref cfg | semmle.label | implicit-deref cfg |
|
||||||
| Dsn.go:67:102:67:108 | selection of dsn | semmle.label | selection of dsn |
|
| Dsn.go:67:102:67:108 | selection of dsn | semmle.label | selection of dsn |
|
||||||
| Dsn.go:68:29:68:33 | dbDSN | semmle.label | dbDSN |
|
| Dsn.go:68:29:68:33 | dbDSN | semmle.label | dbDSN |
|
||||||
subpaths
|
subpaths
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ edges
|
|||||||
| builtin.go:112:21:112:31 | call to Referer | builtin.go:115:15:115:28 | untrustedInput | provenance | Src:MaD:8 |
|
| builtin.go:112:21:112:31 | call to Referer | builtin.go:115:15:115:28 | untrustedInput | provenance | Src:MaD:8 |
|
||||||
| builtin.go:130:21:130:31 | call to Referer | builtin.go:133:38:133:51 | untrustedInput | provenance | Src:MaD:8 |
|
| builtin.go:130:21:130:31 | call to Referer | builtin.go:133:38:133:51 | untrustedInput | provenance | Src:MaD:8 |
|
||||||
| builtin.go:151:16:151:36 | call to FormValue | builtin.go:154:13:154:22 | unsafehost | provenance | Src:MaD:7 |
|
| builtin.go:151:16:151:36 | call to FormValue | builtin.go:154:13:154:22 | unsafehost | provenance | Src:MaD:7 |
|
||||||
| builtin.go:154:2:154:4 | implicit dereference [postupdate] | builtin.go:154:2:154:4 | url [postupdate] | provenance | |
|
| builtin.go:154:2:154:4 | implicit-deref url [postupdate] | builtin.go:154:2:154:4 | url [postupdate] | provenance | |
|
||||||
| builtin.go:154:2:154:4 | url [postupdate] | builtin.go:156:21:156:23 | url | provenance | |
|
| builtin.go:154:2:154:4 | url [postupdate] | builtin.go:156:21:156:23 | url | provenance | |
|
||||||
| builtin.go:154:13:154:22 | unsafehost | builtin.go:154:2:154:4 | implicit dereference [postupdate] | provenance | Config |
|
| builtin.go:154:13:154:22 | unsafehost | builtin.go:154:2:154:4 | implicit-deref url [postupdate] | provenance | Config |
|
||||||
| builtin.go:154:13:154:22 | unsafehost | builtin.go:154:2:154:4 | url [postupdate] | provenance | Config |
|
| builtin.go:154:13:154:22 | unsafehost | builtin.go:154:2:154:4 | url [postupdate] | provenance | Config |
|
||||||
| builtin.go:156:21:156:23 | url | builtin.go:156:21:156:32 | call to String | provenance | MaD:12 |
|
| builtin.go:156:21:156:23 | url | builtin.go:156:21:156:32 | call to String | provenance | MaD:12 |
|
||||||
| new-tests.go:26:26:26:30 | &... [postupdate] | new-tests.go:31:48:31:56 | selection of word | provenance | Src:MaD:3 |
|
| new-tests.go:26:26:26:30 | &... [postupdate] | new-tests.go:31:48:31:56 | selection of word | provenance | Src:MaD:3 |
|
||||||
@@ -43,8 +43,8 @@ edges
|
|||||||
| new-tests.go:35:49:35:57 | selection of word | new-tests.go:35:12:35:58 | call to Sprintf | provenance | FunctionModel |
|
| new-tests.go:35:49:35:57 | selection of word | new-tests.go:35:12:35:58 | call to Sprintf | provenance | FunctionModel |
|
||||||
| new-tests.go:39:18:39:30 | call to Param | new-tests.go:47:11:47:46 | ...+... | provenance | Src:MaD:1 |
|
| new-tests.go:39:18:39:30 | call to Param | new-tests.go:47:11:47:46 | ...+... | provenance | Src:MaD:1 |
|
||||||
| new-tests.go:49:18:49:30 | call to Query | new-tests.go:50:11:50:46 | ...+... | provenance | Src:MaD:2 |
|
| new-tests.go:49:18:49:30 | call to Query | new-tests.go:50:11:50:46 | ...+... | provenance | Src:MaD:2 |
|
||||||
| new-tests.go:62:2:62:39 | ... := ...[0] | new-tests.go:63:17:63:23 | reqBody | provenance | |
|
| new-tests.go:62:2:62:39 | extract:0 ... := ... | new-tests.go:63:17:63:23 | reqBody | provenance | |
|
||||||
| new-tests.go:62:31:62:38 | selection of Body | new-tests.go:62:2:62:39 | ... := ...[0] | provenance | Src:MaD:6 MaD:13 |
|
| new-tests.go:62:31:62:38 | selection of Body | new-tests.go:62:2:62:39 | extract:0 ... := ... | provenance | Src:MaD:6 MaD:13 |
|
||||||
| new-tests.go:63:17:63:23 | reqBody | new-tests.go:63:26:63:30 | &... [postupdate] | provenance | MaD:10 |
|
| new-tests.go:63:17:63:23 | reqBody | new-tests.go:63:26:63:30 | &... [postupdate] | provenance | MaD:10 |
|
||||||
| new-tests.go:63:26:63:30 | &... [postupdate] | new-tests.go:68:48:68:56 | selection of word | provenance | |
|
| new-tests.go:63:26:63:30 | &... [postupdate] | new-tests.go:68:48:68:56 | selection of word | provenance | |
|
||||||
| new-tests.go:63:26:63:30 | &... [postupdate] | new-tests.go:69:48:69:56 | selection of safe | provenance | |
|
| new-tests.go:63:26:63:30 | &... [postupdate] | new-tests.go:69:48:69:56 | selection of safe | provenance | |
|
||||||
@@ -95,7 +95,7 @@ nodes
|
|||||||
| builtin.go:130:21:130:31 | call to Referer | semmle.label | call to Referer |
|
| builtin.go:130:21:130:31 | call to Referer | semmle.label | call to Referer |
|
||||||
| builtin.go:133:38:133:51 | untrustedInput | semmle.label | untrustedInput |
|
| builtin.go:133:38:133:51 | untrustedInput | semmle.label | untrustedInput |
|
||||||
| builtin.go:151:16:151:36 | call to FormValue | semmle.label | call to FormValue |
|
| builtin.go:151:16:151:36 | call to FormValue | semmle.label | call to FormValue |
|
||||||
| builtin.go:154:2:154:4 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
|
| builtin.go:154:2:154:4 | implicit-deref url [postupdate] | semmle.label | implicit-deref url [postupdate] |
|
||||||
| builtin.go:154:2:154:4 | url [postupdate] | semmle.label | url [postupdate] |
|
| builtin.go:154:2:154:4 | url [postupdate] | semmle.label | url [postupdate] |
|
||||||
| builtin.go:154:13:154:22 | unsafehost | semmle.label | unsafehost |
|
| builtin.go:154:13:154:22 | unsafehost | semmle.label | unsafehost |
|
||||||
| builtin.go:156:21:156:23 | url | semmle.label | url |
|
| builtin.go:156:21:156:23 | url | semmle.label | url |
|
||||||
@@ -114,7 +114,7 @@ nodes
|
|||||||
| new-tests.go:47:11:47:46 | ...+... | semmle.label | ...+... |
|
| new-tests.go:47:11:47:46 | ...+... | semmle.label | ...+... |
|
||||||
| new-tests.go:49:18:49:30 | call to Query | semmle.label | call to Query |
|
| new-tests.go:49:18:49:30 | call to Query | semmle.label | call to Query |
|
||||||
| new-tests.go:50:11:50:46 | ...+... | semmle.label | ...+... |
|
| new-tests.go:50:11:50:46 | ...+... | semmle.label | ...+... |
|
||||||
| new-tests.go:62:2:62:39 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| new-tests.go:62:2:62:39 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| new-tests.go:62:31:62:38 | selection of Body | semmle.label | selection of Body |
|
| new-tests.go:62:31:62:38 | selection of Body | semmle.label | selection of Body |
|
||||||
| new-tests.go:63:17:63:23 | reqBody | semmle.label | reqBody |
|
| new-tests.go:63:17:63:23 | reqBody | semmle.label | reqBody |
|
||||||
| new-tests.go:63:26:63:30 | &... [postupdate] | semmle.label | &... [postupdate] |
|
| new-tests.go:63:26:63:30 | &... [postupdate] | semmle.label | &... [postupdate] |
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ edges
|
|||||||
| WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | provenance | |
|
| WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | provenance | |
|
||||||
| WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | provenance | |
|
| WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | provenance | |
|
||||||
| WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | provenance | |
|
| WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | provenance | |
|
||||||
| WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | WrongUsageOfUnsafe.go:236:21:236:23 | SSA def(req) | provenance | |
|
| WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | WrongUsageOfUnsafe.go:236:53:245:1 | SSA def(req) | provenance | |
|
||||||
| WrongUsageOfUnsafe.go:236:21:236:23 | SSA def(req) | WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | provenance | |
|
| WrongUsageOfUnsafe.go:236:53:245:1 | SSA def(req) | WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | provenance | |
|
||||||
| WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | provenance | |
|
| WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | provenance | |
|
||||||
| WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | provenance | |
|
| WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | provenance | |
|
||||||
| WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | provenance | |
|
| WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | provenance | |
|
||||||
@@ -51,7 +51,7 @@ nodes
|
|||||||
| WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | semmle.label | type conversion |
|
| WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | semmle.label | type conversion |
|
||||||
| WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | semmle.label | type conversion |
|
| WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | semmle.label | type conversion |
|
||||||
| WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | semmle.label | type conversion |
|
| WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | semmle.label | type conversion |
|
||||||
| WrongUsageOfUnsafe.go:236:21:236:23 | SSA def(req) | semmle.label | SSA def(req) |
|
| WrongUsageOfUnsafe.go:236:53:245:1 | SSA def(req) | semmle.label | SSA def(req) |
|
||||||
| WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | semmle.label | type conversion |
|
| WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | semmle.label | type conversion |
|
||||||
| WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | semmle.label | type conversion |
|
| WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | semmle.label | type conversion |
|
||||||
| WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | semmle.label | type conversion |
|
| WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | semmle.label | type conversion |
|
||||||
|
|||||||
@@ -1,64 +1,156 @@
|
|||||||
nodes
|
nodes
|
||||||
edges
|
edges
|
||||||
| conversions.go:0:0:0:0 | entry | conversions.go:3:1:3:15 | skip |
|
| conversions.go:0:0:0:0 | After conversions.go | conversions.go:0:0:0:0 | Normal Exit |
|
||||||
| conversions.go:3:1:3:15 | skip | conversions.go:5:6:5:8 | skip |
|
| conversions.go:0:0:0:0 | Entry | conversions.go:0:0:0:0 | conversions.go |
|
||||||
| conversions.go:5:1:5:29 | entry | conversions.go:5:10:5:10 | argument corresponding to _ |
|
| conversions.go:0:0:0:0 | Normal Exit | conversions.go:0:0:0:0 | Exit |
|
||||||
| conversions.go:5:1:5:29 | function declaration | conversions.go:7:6:7:9 | skip |
|
| conversions.go:0:0:0:0 | conversions.go | conversions.go:3:1:3:15 | import declaration |
|
||||||
| conversions.go:5:6:5:8 | skip | conversions.go:5:1:5:29 | function declaration |
|
| conversions.go:3:1:3:15 | After import declaration | conversions.go:5:1:5:29 | Before function declaration |
|
||||||
| conversions.go:5:10:5:10 | argument corresponding to _ | conversions.go:5:10:5:10 | initialization of _ |
|
| conversions.go:3:1:3:15 | import declaration | conversions.go:3:8:3:15 | import specifier |
|
||||||
| conversions.go:5:10:5:10 | initialization of _ | conversions.go:5:28:5:29 | skip |
|
| conversions.go:3:8:3:15 | import specifier | conversions.go:3:1:3:15 | After import declaration |
|
||||||
| conversions.go:5:28:5:29 | skip | conversions.go:5:1:5:29 | exit |
|
| conversions.go:5:1:5:29 | After function declaration | conversions.go:7:1:26:1 | Before function declaration |
|
||||||
| conversions.go:7:1:26:1 | entry | conversions.go:8:6:8:6 | skip |
|
| conversions.go:5:1:5:29 | Before function declaration | conversions.go:5:1:5:29 | function declaration |
|
||||||
| conversions.go:7:1:26:1 | function declaration | conversions.go:0:0:0:0 | exit |
|
| conversions.go:5:1:5:29 | Entry | conversions.go:5:28:5:29 | block statement |
|
||||||
| conversions.go:7:6:7:9 | skip | conversions.go:7:1:26:1 | function declaration |
|
| conversions.go:5:1:5:29 | Normal Exit | conversions.go:5:1:5:29 | Exit |
|
||||||
| conversions.go:8:6:8:6 | assignment to a | conversions.go:10:2:10:2 | skip |
|
| conversions.go:5:1:5:29 | function declaration | conversions.go:5:1:5:29 | After function declaration |
|
||||||
| conversions.go:8:6:8:6 | skip | conversions.go:8:6:8:6 | zero value for a |
|
| conversions.go:5:28:5:29 | After block statement | conversions.go:5:1:5:29 | Normal Exit |
|
||||||
| conversions.go:8:6:8:6 | zero value for a | conversions.go:8:6:8:6 | assignment to a |
|
| conversions.go:5:28:5:29 | arg:0 block statement | conversions.go:5:28:5:29 | param-init:0 block statement |
|
||||||
| conversions.go:10:2:10:2 | assignment to b | conversions.go:11:2:11:4 | use |
|
| conversions.go:5:28:5:29 | block statement | conversions.go:5:28:5:29 | arg:0 block statement |
|
||||||
| conversions.go:10:2:10:2 | skip | conversions.go:10:7:10:16 | selection of Add |
|
| conversions.go:5:28:5:29 | param-init:0 block statement | conversions.go:5:28:5:29 | After block statement |
|
||||||
| conversions.go:10:7:10:16 | selection of Add | conversions.go:10:18:10:18 | a |
|
| conversions.go:7:1:26:1 | After function declaration | conversions.go:0:0:0:0 | After conversions.go |
|
||||||
| conversions.go:10:7:10:23 | call to Add | conversions.go:10:2:10:2 | assignment to b |
|
| conversions.go:7:1:26:1 | Before function declaration | conversions.go:7:1:26:1 | function declaration |
|
||||||
| conversions.go:10:18:10:18 | a | conversions.go:10:21:10:22 | 10 |
|
| conversions.go:7:1:26:1 | Entry | conversions.go:7:13:26:1 | block statement |
|
||||||
| conversions.go:10:21:10:22 | 10 | conversions.go:10:7:10:23 | call to Add |
|
| conversions.go:7:1:26:1 | Exceptional Exit | conversions.go:7:1:26:1 | Exit |
|
||||||
| conversions.go:11:2:11:4 | use | conversions.go:11:6:11:6 | b |
|
| conversions.go:7:1:26:1 | Normal Exit | conversions.go:7:1:26:1 | Exit |
|
||||||
| conversions.go:11:2:11:7 | call to use | conversions.go:7:1:26:1 | exit |
|
| conversions.go:7:1:26:1 | function declaration | conversions.go:7:1:26:1 | After function declaration |
|
||||||
| conversions.go:11:2:11:7 | call to use | conversions.go:13:6:13:8 | skip |
|
| conversions.go:7:13:26:1 | After block statement | conversions.go:7:1:26:1 | Normal Exit |
|
||||||
| conversions.go:11:6:11:6 | b | conversions.go:11:2:11:7 | call to use |
|
| conversions.go:7:13:26:1 | block statement | conversions.go:8:2:8:21 | declaration statement |
|
||||||
| conversions.go:13:6:13:8 | assignment to arr | conversions.go:14:2:14:6 | skip |
|
| conversions.go:8:2:8:21 | After declaration statement | conversions.go:10:2:10:23 | ... := ... |
|
||||||
| conversions.go:13:6:13:8 | skip | conversions.go:13:6:13:8 | zero value for arr |
|
| conversions.go:8:2:8:21 | After variable declaration | conversions.go:8:2:8:21 | After declaration statement |
|
||||||
| conversions.go:13:6:13:8 | zero value for arr | conversions.go:13:6:13:8 | assignment to arr |
|
| conversions.go:8:2:8:21 | declaration statement | conversions.go:8:2:8:21 | variable declaration |
|
||||||
| conversions.go:14:2:14:6 | assignment to slice | conversions.go:17:2:17:4 | skip |
|
| conversions.go:8:2:8:21 | variable declaration | conversions.go:8:6:8:21 | value declaration specifier |
|
||||||
| conversions.go:14:2:14:6 | skip | conversions.go:14:11:14:22 | selection of Slice |
|
| conversions.go:8:6:8:21 | After value declaration specifier | conversions.go:8:2:8:21 | After variable declaration |
|
||||||
| conversions.go:14:11:14:22 | selection of Slice | conversions.go:14:24:14:26 | arr |
|
| conversions.go:8:6:8:21 | assign:0 value declaration specifier | conversions.go:8:6:8:21 | After value declaration specifier |
|
||||||
| conversions.go:14:11:14:31 | call to Slice | conversions.go:14:2:14:6 | assignment to slice |
|
| conversions.go:8:6:8:21 | value declaration specifier | conversions.go:8:6:8:21 | zero-init:0 value declaration specifier |
|
||||||
| conversions.go:14:24:14:26 | arr | conversions.go:14:29:14:30 | 20 |
|
| conversions.go:8:6:8:21 | zero-init:0 value declaration specifier | conversions.go:8:6:8:21 | assign:0 value declaration specifier |
|
||||||
| conversions.go:14:29:14:30 | 20 | conversions.go:14:11:14:31 | call to Slice |
|
| conversions.go:10:2:10:23 | ... := ... | conversions.go:10:7:10:23 | Before call to Add |
|
||||||
| conversions.go:17:2:17:4 | assignment to ptr | conversions.go:18:2:18:4 | use |
|
| conversions.go:10:2:10:23 | After ... := ... | conversions.go:11:2:11:7 | expression statement |
|
||||||
| conversions.go:17:2:17:4 | skip | conversions.go:17:20:17:24 | slice |
|
| conversions.go:10:2:10:23 | assign:0 ... := ... | conversions.go:10:2:10:23 | After ... := ... |
|
||||||
| conversions.go:17:9:17:25 | type conversion | conversions.go:7:1:26:1 | exit |
|
| conversions.go:10:7:10:16 | After selection of Add | conversions.go:10:18:10:18 | Before a |
|
||||||
| conversions.go:17:9:17:25 | type conversion | conversions.go:17:2:17:4 | assignment to ptr |
|
| conversions.go:10:7:10:16 | Before selection of Add | conversions.go:10:7:10:16 | selection of Add |
|
||||||
| conversions.go:17:20:17:24 | slice | conversions.go:17:9:17:25 | type conversion |
|
| conversions.go:10:7:10:16 | selection of Add | conversions.go:10:7:10:16 | After selection of Add |
|
||||||
| conversions.go:18:2:18:4 | use | conversions.go:18:6:18:8 | ptr |
|
| conversions.go:10:7:10:23 | After call to Add | conversions.go:10:2:10:23 | assign:0 ... := ... |
|
||||||
| conversions.go:18:2:18:9 | call to use | conversions.go:7:1:26:1 | exit |
|
| conversions.go:10:7:10:23 | Before call to Add | conversions.go:10:7:10:16 | Before selection of Add |
|
||||||
| conversions.go:18:2:18:9 | call to use | conversions.go:21:2:21:4 | skip |
|
| conversions.go:10:7:10:23 | call to Add | conversions.go:10:7:10:23 | After call to Add |
|
||||||
| conversions.go:18:6:18:8 | ptr | conversions.go:18:2:18:9 | call to use |
|
| conversions.go:10:18:10:18 | After a | conversions.go:10:21:10:22 | Before 10 |
|
||||||
| conversions.go:21:2:21:4 | assignment to str | conversions.go:22:2:22:6 | skip |
|
| conversions.go:10:18:10:18 | Before a | conversions.go:10:18:10:18 | a |
|
||||||
| conversions.go:21:2:21:4 | skip | conversions.go:21:9:21:18 | "a string" |
|
| conversions.go:10:18:10:18 | a | conversions.go:10:18:10:18 | After a |
|
||||||
| conversions.go:21:9:21:18 | "a string" | conversions.go:21:2:21:4 | assignment to str |
|
| conversions.go:10:21:10:22 | 10 | conversions.go:10:21:10:22 | After 10 |
|
||||||
| conversions.go:22:2:22:6 | assignment to bytes | conversions.go:23:2:23:4 | use |
|
| conversions.go:10:21:10:22 | After 10 | conversions.go:10:7:10:23 | call to Add |
|
||||||
| conversions.go:22:2:22:6 | skip | conversions.go:22:18:22:20 | str |
|
| conversions.go:10:21:10:22 | Before 10 | conversions.go:10:21:10:22 | 10 |
|
||||||
| conversions.go:22:11:22:21 | type conversion | conversions.go:22:2:22:6 | assignment to bytes |
|
| conversions.go:11:2:11:4 | After use | conversions.go:11:6:11:6 | Before b |
|
||||||
| conversions.go:22:18:22:20 | str | conversions.go:22:11:22:21 | type conversion |
|
| conversions.go:11:2:11:4 | Before use | conversions.go:11:2:11:4 | use |
|
||||||
| conversions.go:23:2:23:4 | use | conversions.go:23:6:23:10 | bytes |
|
| conversions.go:11:2:11:4 | use | conversions.go:11:2:11:4 | After use |
|
||||||
| conversions.go:23:2:23:11 | call to use | conversions.go:7:1:26:1 | exit |
|
| conversions.go:11:2:11:7 | After call to use | conversions.go:11:2:11:7 | After expression statement |
|
||||||
| conversions.go:23:2:23:11 | call to use | conversions.go:24:2:24:6 | skip |
|
| conversions.go:11:2:11:7 | After expression statement | conversions.go:13:2:13:13 | declaration statement |
|
||||||
| conversions.go:23:6:23:10 | bytes | conversions.go:23:2:23:11 | call to use |
|
| conversions.go:11:2:11:7 | Before call to use | conversions.go:11:2:11:4 | Before use |
|
||||||
| conversions.go:24:2:24:6 | assignment to runes | conversions.go:25:2:25:4 | use |
|
| conversions.go:11:2:11:7 | call to use | conversions.go:7:1:26:1 | Exceptional Exit |
|
||||||
| conversions.go:24:2:24:6 | skip | conversions.go:24:18:24:20 | str |
|
| conversions.go:11:2:11:7 | call to use | conversions.go:11:2:11:7 | After call to use |
|
||||||
| conversions.go:24:11:24:21 | type conversion | conversions.go:24:2:24:6 | assignment to runes |
|
| conversions.go:11:2:11:7 | expression statement | conversions.go:11:2:11:7 | Before call to use |
|
||||||
| conversions.go:24:18:24:20 | str | conversions.go:24:11:24:21 | type conversion |
|
| conversions.go:11:6:11:6 | After b | conversions.go:11:2:11:7 | call to use |
|
||||||
| conversions.go:25:2:25:4 | use | conversions.go:25:6:25:10 | runes |
|
| conversions.go:11:6:11:6 | Before b | conversions.go:11:6:11:6 | b |
|
||||||
| conversions.go:25:2:25:11 | call to use | conversions.go:7:1:26:1 | exit |
|
| conversions.go:11:6:11:6 | b | conversions.go:11:6:11:6 | After b |
|
||||||
| conversions.go:25:6:25:10 | runes | conversions.go:25:2:25:11 | call to use |
|
| conversions.go:13:2:13:13 | After declaration statement | conversions.go:14:2:14:31 | ... := ... |
|
||||||
|
| conversions.go:13:2:13:13 | After variable declaration | conversions.go:13:2:13:13 | After declaration statement |
|
||||||
|
| conversions.go:13:2:13:13 | declaration statement | conversions.go:13:2:13:13 | variable declaration |
|
||||||
|
| conversions.go:13:2:13:13 | variable declaration | conversions.go:13:6:13:13 | value declaration specifier |
|
||||||
|
| conversions.go:13:6:13:13 | After value declaration specifier | conversions.go:13:2:13:13 | After variable declaration |
|
||||||
|
| conversions.go:13:6:13:13 | assign:0 value declaration specifier | conversions.go:13:6:13:13 | After value declaration specifier |
|
||||||
|
| conversions.go:13:6:13:13 | value declaration specifier | conversions.go:13:6:13:13 | zero-init:0 value declaration specifier |
|
||||||
|
| conversions.go:13:6:13:13 | zero-init:0 value declaration specifier | conversions.go:13:6:13:13 | assign:0 value declaration specifier |
|
||||||
|
| conversions.go:14:2:14:31 | ... := ... | conversions.go:14:11:14:31 | Before call to Slice |
|
||||||
|
| conversions.go:14:2:14:31 | After ... := ... | conversions.go:17:2:17:25 | ... := ... |
|
||||||
|
| conversions.go:14:2:14:31 | assign:0 ... := ... | conversions.go:14:2:14:31 | After ... := ... |
|
||||||
|
| conversions.go:14:11:14:22 | After selection of Slice | conversions.go:14:24:14:26 | Before arr |
|
||||||
|
| conversions.go:14:11:14:22 | Before selection of Slice | conversions.go:14:11:14:22 | selection of Slice |
|
||||||
|
| conversions.go:14:11:14:22 | selection of Slice | conversions.go:14:11:14:22 | After selection of Slice |
|
||||||
|
| conversions.go:14:11:14:31 | After call to Slice | conversions.go:14:2:14:31 | assign:0 ... := ... |
|
||||||
|
| conversions.go:14:11:14:31 | Before call to Slice | conversions.go:14:11:14:22 | Before selection of Slice |
|
||||||
|
| conversions.go:14:11:14:31 | call to Slice | conversions.go:14:11:14:31 | After call to Slice |
|
||||||
|
| conversions.go:14:24:14:26 | After arr | conversions.go:14:29:14:30 | Before 20 |
|
||||||
|
| conversions.go:14:24:14:26 | Before arr | conversions.go:14:24:14:26 | arr |
|
||||||
|
| conversions.go:14:24:14:26 | arr | conversions.go:14:24:14:26 | After arr |
|
||||||
|
| conversions.go:14:29:14:30 | 20 | conversions.go:14:29:14:30 | After 20 |
|
||||||
|
| conversions.go:14:29:14:30 | After 20 | conversions.go:14:11:14:31 | call to Slice |
|
||||||
|
| conversions.go:14:29:14:30 | Before 20 | conversions.go:14:29:14:30 | 20 |
|
||||||
|
| conversions.go:17:2:17:25 | ... := ... | conversions.go:17:9:17:25 | Before type conversion |
|
||||||
|
| conversions.go:17:2:17:25 | After ... := ... | conversions.go:18:2:18:9 | expression statement |
|
||||||
|
| conversions.go:17:2:17:25 | assign:0 ... := ... | conversions.go:17:2:17:25 | After ... := ... |
|
||||||
|
| conversions.go:17:9:17:25 | After type conversion | conversions.go:17:2:17:25 | assign:0 ... := ... |
|
||||||
|
| conversions.go:17:9:17:25 | Before type conversion | conversions.go:17:20:17:24 | Before slice |
|
||||||
|
| conversions.go:17:9:17:25 | type conversion | conversions.go:7:1:26:1 | Exceptional Exit |
|
||||||
|
| conversions.go:17:9:17:25 | type conversion | conversions.go:17:9:17:25 | After type conversion |
|
||||||
|
| conversions.go:17:20:17:24 | After slice | conversions.go:17:9:17:25 | type conversion |
|
||||||
|
| conversions.go:17:20:17:24 | Before slice | conversions.go:17:20:17:24 | slice |
|
||||||
|
| conversions.go:17:20:17:24 | slice | conversions.go:17:20:17:24 | After slice |
|
||||||
|
| conversions.go:18:2:18:4 | After use | conversions.go:18:6:18:8 | Before ptr |
|
||||||
|
| conversions.go:18:2:18:4 | Before use | conversions.go:18:2:18:4 | use |
|
||||||
|
| conversions.go:18:2:18:4 | use | conversions.go:18:2:18:4 | After use |
|
||||||
|
| conversions.go:18:2:18:9 | After call to use | conversions.go:18:2:18:9 | After expression statement |
|
||||||
|
| conversions.go:18:2:18:9 | After expression statement | conversions.go:21:2:21:18 | ... := ... |
|
||||||
|
| conversions.go:18:2:18:9 | Before call to use | conversions.go:18:2:18:4 | Before use |
|
||||||
|
| conversions.go:18:2:18:9 | call to use | conversions.go:7:1:26:1 | Exceptional Exit |
|
||||||
|
| conversions.go:18:2:18:9 | call to use | conversions.go:18:2:18:9 | After call to use |
|
||||||
|
| conversions.go:18:2:18:9 | expression statement | conversions.go:18:2:18:9 | Before call to use |
|
||||||
|
| conversions.go:18:6:18:8 | After ptr | conversions.go:18:2:18:9 | call to use |
|
||||||
|
| conversions.go:18:6:18:8 | Before ptr | conversions.go:18:6:18:8 | ptr |
|
||||||
|
| conversions.go:18:6:18:8 | ptr | conversions.go:18:6:18:8 | After ptr |
|
||||||
|
| conversions.go:21:2:21:18 | ... := ... | conversions.go:21:9:21:18 | Before "a string" |
|
||||||
|
| conversions.go:21:2:21:18 | After ... := ... | conversions.go:22:2:22:21 | ... := ... |
|
||||||
|
| conversions.go:21:2:21:18 | assign:0 ... := ... | conversions.go:21:2:21:18 | After ... := ... |
|
||||||
|
| conversions.go:21:9:21:18 | "a string" | conversions.go:21:9:21:18 | After "a string" |
|
||||||
|
| conversions.go:21:9:21:18 | After "a string" | conversions.go:21:2:21:18 | assign:0 ... := ... |
|
||||||
|
| conversions.go:21:9:21:18 | Before "a string" | conversions.go:21:9:21:18 | "a string" |
|
||||||
|
| conversions.go:22:2:22:21 | ... := ... | conversions.go:22:11:22:21 | Before type conversion |
|
||||||
|
| conversions.go:22:2:22:21 | After ... := ... | conversions.go:23:2:23:11 | expression statement |
|
||||||
|
| conversions.go:22:2:22:21 | assign:0 ... := ... | conversions.go:22:2:22:21 | After ... := ... |
|
||||||
|
| conversions.go:22:11:22:21 | After type conversion | conversions.go:22:2:22:21 | assign:0 ... := ... |
|
||||||
|
| conversions.go:22:11:22:21 | Before type conversion | conversions.go:22:18:22:20 | Before str |
|
||||||
|
| conversions.go:22:11:22:21 | type conversion | conversions.go:22:11:22:21 | After type conversion |
|
||||||
|
| conversions.go:22:18:22:20 | After str | conversions.go:22:11:22:21 | type conversion |
|
||||||
|
| conversions.go:22:18:22:20 | Before str | conversions.go:22:18:22:20 | str |
|
||||||
|
| conversions.go:22:18:22:20 | str | conversions.go:22:18:22:20 | After str |
|
||||||
|
| conversions.go:23:2:23:4 | After use | conversions.go:23:6:23:10 | Before bytes |
|
||||||
|
| conversions.go:23:2:23:4 | Before use | conversions.go:23:2:23:4 | use |
|
||||||
|
| conversions.go:23:2:23:4 | use | conversions.go:23:2:23:4 | After use |
|
||||||
|
| conversions.go:23:2:23:11 | After call to use | conversions.go:23:2:23:11 | After expression statement |
|
||||||
|
| conversions.go:23:2:23:11 | After expression statement | conversions.go:24:2:24:21 | ... := ... |
|
||||||
|
| conversions.go:23:2:23:11 | Before call to use | conversions.go:23:2:23:4 | Before use |
|
||||||
|
| conversions.go:23:2:23:11 | call to use | conversions.go:7:1:26:1 | Exceptional Exit |
|
||||||
|
| conversions.go:23:2:23:11 | call to use | conversions.go:23:2:23:11 | After call to use |
|
||||||
|
| conversions.go:23:2:23:11 | expression statement | conversions.go:23:2:23:11 | Before call to use |
|
||||||
|
| conversions.go:23:6:23:10 | After bytes | conversions.go:23:2:23:11 | call to use |
|
||||||
|
| conversions.go:23:6:23:10 | Before bytes | conversions.go:23:6:23:10 | bytes |
|
||||||
|
| conversions.go:23:6:23:10 | bytes | conversions.go:23:6:23:10 | After bytes |
|
||||||
|
| conversions.go:24:2:24:21 | ... := ... | conversions.go:24:11:24:21 | Before type conversion |
|
||||||
|
| conversions.go:24:2:24:21 | After ... := ... | conversions.go:25:2:25:11 | expression statement |
|
||||||
|
| conversions.go:24:2:24:21 | assign:0 ... := ... | conversions.go:24:2:24:21 | After ... := ... |
|
||||||
|
| conversions.go:24:11:24:21 | After type conversion | conversions.go:24:2:24:21 | assign:0 ... := ... |
|
||||||
|
| conversions.go:24:11:24:21 | Before type conversion | conversions.go:24:18:24:20 | Before str |
|
||||||
|
| conversions.go:24:11:24:21 | type conversion | conversions.go:24:11:24:21 | After type conversion |
|
||||||
|
| conversions.go:24:18:24:20 | After str | conversions.go:24:11:24:21 | type conversion |
|
||||||
|
| conversions.go:24:18:24:20 | Before str | conversions.go:24:18:24:20 | str |
|
||||||
|
| conversions.go:24:18:24:20 | str | conversions.go:24:18:24:20 | After str |
|
||||||
|
| conversions.go:25:2:25:4 | After use | conversions.go:25:6:25:10 | Before runes |
|
||||||
|
| conversions.go:25:2:25:4 | Before use | conversions.go:25:2:25:4 | use |
|
||||||
|
| conversions.go:25:2:25:4 | use | conversions.go:25:2:25:4 | After use |
|
||||||
|
| conversions.go:25:2:25:11 | After call to use | conversions.go:25:2:25:11 | After expression statement |
|
||||||
|
| conversions.go:25:2:25:11 | After expression statement | conversions.go:7:13:26:1 | After block statement |
|
||||||
|
| conversions.go:25:2:25:11 | Before call to use | conversions.go:25:2:25:4 | Before use |
|
||||||
|
| conversions.go:25:2:25:11 | call to use | conversions.go:7:1:26:1 | Exceptional Exit |
|
||||||
|
| conversions.go:25:2:25:11 | call to use | conversions.go:25:2:25:11 | After call to use |
|
||||||
|
| conversions.go:25:2:25:11 | expression statement | conversions.go:25:2:25:11 | Before call to use |
|
||||||
|
| conversions.go:25:6:25:10 | After runes | conversions.go:25:2:25:11 | call to use |
|
||||||
|
| conversions.go:25:6:25:10 | Before runes | conversions.go:25:6:25:10 | runes |
|
||||||
|
| conversions.go:25:6:25:10 | runes | conversions.go:25:6:25:10 | After runes |
|
||||||
#select
|
#select
|
||||||
| |
|
| |
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
| test.go:9:2:9:16 | ... := ...[0] | test.go:9:13:9:16 | <-... | 0 | file://:0:0:0:0 | bool |
|
| test.go:9:2:9:16 | extract:0 ... := ... | test.go:9:13:9:16 | <-... | 0 | file://:0:0:0:0 | bool |
|
||||||
| test.go:9:2:9:16 | ... := ...[1] | test.go:9:13:9:16 | <-... | 1 | file://:0:0:0:0 | bool |
|
| test.go:9:2:9:16 | extract:1 ... := ... | test.go:9:13:9:16 | <-... | 1 | file://:0:0:0:0 | bool |
|
||||||
| test.go:15:2:15:20 | ... := ...[0] | test.go:15:13:15:20 | index expression | 0 | file://:0:0:0:0 | string |
|
| test.go:15:2:15:20 | extract:0 ... := ... | test.go:15:13:15:20 | index expression | 0 | file://:0:0:0:0 | string |
|
||||||
| test.go:15:2:15:20 | ... := ...[1] | test.go:15:13:15:20 | index expression | 1 | file://:0:0:0:0 | bool |
|
| test.go:15:2:15:20 | extract:1 ... := ... | test.go:15:13:15:20 | index expression | 1 | file://:0:0:0:0 | bool |
|
||||||
| test.go:21:2:21:22 | ... := ...[0] | test.go:21:13:21:22 | type assertion | 0 | file://:0:0:0:0 | string |
|
| test.go:21:2:21:22 | extract:0 ... := ... | test.go:21:13:21:22 | type assertion | 0 | file://:0:0:0:0 | string |
|
||||||
| test.go:21:2:21:22 | ... := ...[1] | test.go:21:13:21:22 | type assertion | 1 | file://:0:0:0:0 | bool |
|
| test.go:21:2:21:22 | extract:1 ... := ... | test.go:21:13:21:22 | type assertion | 1 | file://:0:0:0:0 | bool |
|
||||||
| test.go:29:2:29:7 | call to f[0] | test.go:29:4:29:6 | call to g | 0 | file://:0:0:0:0 | int |
|
|
||||||
| test.go:29:2:29:7 | call to f[1] | test.go:29:4:29:6 | call to g | 1 | file://:0:0:0:0 | int |
|
|
||||||
| test.go:33:2:33:7 | call to f[0] | test.go:33:4:33:6 | call to v | 0 | file://:0:0:0:0 | int |
|
|
||||||
| test.go:33:2:33:7 | call to f[1] | test.go:33:4:33:6 | call to v | 1 | file://:0:0:0:0 | int |
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
| main.go:6:2:6:2 | x | main.go:24:2:24:9 | increment statement |
|
| main.go:6:2:6:2 | x | main.go:24:2:24:9 | increment statement |
|
||||||
| main.go:13:7:13:10 | recv | main.go:13:7:13:10 | initialization of recv |
|
| main.go:13:7:13:10 | recv | main.go:13:27:15:1 | param-init:-1 block statement |
|
||||||
| main.go:17:10:17:10 | x | main.go:17:10:17:10 | initialization of x |
|
| main.go:17:10:17:10 | x | main.go:17:32:21:1 | param-init:0 block statement |
|
||||||
| main.go:17:26:17:26 | y | main.go:17:26:17:26 | initialization of y |
|
| main.go:17:26:17:26 | y | main.go:17:32:21:1 | param-init:1 block statement |
|
||||||
| main.go:23:7:23:10 | recv | main.go:23:7:23:10 | initialization of recv |
|
| main.go:23:7:23:10 | recv | main.go:23:23:25:1 | param-init:-1 block statement |
|
||||||
| types.go:33:22:33:22 | a | types.go:33:22:33:22 | initialization of a |
|
| types.go:33:22:33:22 | a | types.go:33:34:35:1 | param-init:0 block statement |
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ func logSomething(entry *logrus.Entry) {
|
|||||||
entry.Traceln(text) // $ logger=text
|
entry.Traceln(text) // $ logger=text
|
||||||
}
|
}
|
||||||
|
|
||||||
func logrusCalls() {
|
func logrusCalls(selector int) {
|
||||||
err := errors.New("Error")
|
err := errors.New("Error")
|
||||||
var fields logrus.Fields = nil
|
var fields logrus.Fields = nil
|
||||||
var fn logrus.LogFunction = nil
|
var fn logrus.LogFunction = nil
|
||||||
@@ -28,10 +28,14 @@ func logrusCalls() {
|
|||||||
logSomething(tmp)
|
logSomething(tmp)
|
||||||
|
|
||||||
logrus.Error(text) // $ logger=text
|
logrus.Error(text) // $ logger=text
|
||||||
logrus.Fatalf(fmt, text) // $ logger=fmt logger=text
|
|
||||||
logrus.Panicln(text) // $ logger=text
|
|
||||||
logrus.Infof(fmt, text) // $ logger=fmt logger=text
|
logrus.Infof(fmt, text) // $ logger=fmt logger=text
|
||||||
|
if selector == 0 {
|
||||||
|
logrus.Fatalf(fmt, text) // $ logger=fmt logger=text
|
||||||
|
} else if selector == 1 {
|
||||||
|
logrus.Panicln(text) // $ logger=text
|
||||||
|
} else if selector == 2 {
|
||||||
logrus.FatalFn(fn) // $ logger=fn
|
logrus.FatalFn(fn) // $ logger=fn
|
||||||
|
}
|
||||||
|
|
||||||
// components corresponding to the format specifier "%T" are not considered vulnerable
|
// components corresponding to the format specifier "%T" are not considered vulnerable
|
||||||
logrus.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
logrus.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ var v []byte
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
glogTest(len(v))
|
glogTest(len(v))
|
||||||
stdlib()
|
stdlib(len(v))
|
||||||
slogTest()
|
slogTest()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,37 +4,69 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func stdlib() {
|
func stdlib(selector int) {
|
||||||
var logger log.Logger
|
var logger log.Logger
|
||||||
logger.SetPrefix("prefix: ")
|
logger.SetPrefix("prefix: ")
|
||||||
|
switch selector {
|
||||||
|
case 0:
|
||||||
logger.Fatal(text) // $ logger=text
|
logger.Fatal(text) // $ logger=text
|
||||||
|
case 1:
|
||||||
logger.Fatalf(fmt, text) // $ logger=fmt logger=text
|
logger.Fatalf(fmt, text) // $ logger=fmt logger=text
|
||||||
|
case 2:
|
||||||
logger.Fatalln(text) // $ logger=text
|
logger.Fatalln(text) // $ logger=text
|
||||||
|
case 3:
|
||||||
logger.Panic(text) // $ logger=text
|
logger.Panic(text) // $ logger=text
|
||||||
|
case 4:
|
||||||
logger.Panicf(fmt, text) // $ logger=fmt logger=text
|
logger.Panicf(fmt, text) // $ logger=fmt logger=text
|
||||||
|
case 5:
|
||||||
logger.Panicln(text) // $ logger=text
|
logger.Panicln(text) // $ logger=text
|
||||||
|
case 6:
|
||||||
logger.Print(text) // $ logger=text
|
logger.Print(text) // $ logger=text
|
||||||
|
case 7:
|
||||||
logger.Printf(fmt, text) // $ logger=fmt logger=text
|
logger.Printf(fmt, text) // $ logger=fmt logger=text
|
||||||
|
case 8:
|
||||||
logger.Println(text) // $ logger=text
|
logger.Println(text) // $ logger=text
|
||||||
|
}
|
||||||
|
|
||||||
// components corresponding to the format specifier "%T" are not considered vulnerable
|
// components corresponding to the format specifier "%T" are not considered vulnerable
|
||||||
|
switch selector {
|
||||||
|
case 9:
|
||||||
logger.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
logger.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
||||||
|
case 10:
|
||||||
logger.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
logger.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
||||||
|
case 11:
|
||||||
logger.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
logger.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
||||||
|
}
|
||||||
|
|
||||||
log.SetPrefix("prefix: ")
|
log.SetPrefix("prefix: ")
|
||||||
|
switch selector {
|
||||||
|
case 12:
|
||||||
log.Fatal(text) // $ logger=text
|
log.Fatal(text) // $ logger=text
|
||||||
|
case 13:
|
||||||
log.Fatalf(fmt, text) // $ logger=fmt logger=text
|
log.Fatalf(fmt, text) // $ logger=fmt logger=text
|
||||||
|
case 14:
|
||||||
log.Fatalln(text) // $ logger=text
|
log.Fatalln(text) // $ logger=text
|
||||||
|
case 15:
|
||||||
log.Panic(text) // $ logger=text
|
log.Panic(text) // $ logger=text
|
||||||
|
case 16:
|
||||||
log.Panicf(fmt, text) // $ logger=fmt logger=text
|
log.Panicf(fmt, text) // $ logger=fmt logger=text
|
||||||
|
case 17:
|
||||||
log.Panicln(text) // $ logger=text
|
log.Panicln(text) // $ logger=text
|
||||||
|
case 18:
|
||||||
log.Print(text) // $ logger=text
|
log.Print(text) // $ logger=text
|
||||||
|
case 19:
|
||||||
log.Printf(fmt, text) // $ logger=fmt logger=text
|
log.Printf(fmt, text) // $ logger=fmt logger=text
|
||||||
|
case 20:
|
||||||
log.Println(text) // $ logger=text
|
log.Println(text) // $ logger=text
|
||||||
|
}
|
||||||
|
|
||||||
// components corresponding to the format specifier "%T" are not considered vulnerable
|
// components corresponding to the format specifier "%T" are not considered vulnerable
|
||||||
|
switch selector {
|
||||||
|
case 21:
|
||||||
log.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
log.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
||||||
|
case 22:
|
||||||
log.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
log.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
||||||
|
case 23:
|
||||||
log.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
log.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
|||||||
|
| epilogues.go:115:6:115:22 | epiRecoverUnnamed | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.epiRecoverUnnamed |
|
||||||
| file://:0:0:0:0 | Exit | os.Exit |
|
| file://:0:0:0:0 | Exit | os.Exit |
|
||||||
| file://:0:0:0:0 | Fatal | log.Fatal |
|
| file://:0:0:0:0 | Fatal | log.Fatal |
|
||||||
| file://:0:0:0:0 | Fatal | log.Logger.Fatal |
|
| file://:0:0:0:0 | Fatal | log.Logger.Fatal |
|
||||||
@@ -18,4 +19,3 @@
|
|||||||
| stmts7.go:10:6:10:15 | canRecover | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.canRecover |
|
| stmts7.go:10:6:10:15 | canRecover | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.canRecover |
|
||||||
| stmts.go:10:6:10:10 | test5 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.test5 |
|
| stmts.go:10:6:10:10 | test5 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.test5 |
|
||||||
| stmts.go:46:6:46:10 | test6 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.test6 |
|
| stmts.go:46:6:46:10 | test6 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.test6 |
|
||||||
| stmts.go:112:6:112:10 | test9 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph.test9 |
|
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// epiLogger has methods with both pointer and value receivers, used to check
|
||||||
|
// that the receiver and arguments of a deferred call are evaluated at the
|
||||||
|
// `defer` statement rather than in the function epilogue.
|
||||||
|
type epiLogger struct {
|
||||||
|
prefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *epiLogger) log(msg string, code int) {
|
||||||
|
fmt.Println(l.prefix, msg, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l epiLogger) logValue(msg string) {
|
||||||
|
fmt.Println(l.prefix, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// epiRecover recovers from a panic. It is used as a deferred function so we can
|
||||||
|
// check that control flow returns to the result-read nodes and the normal exit
|
||||||
|
// node after recovering.
|
||||||
|
func epiRecover() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Println("recovered:", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// epiPlain has no named result variable and a single `return` with a child
|
||||||
|
// expression.
|
||||||
|
func epiPlain(x int) int {
|
||||||
|
return x * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// epiVoid has no named result variable and no `return` statement at all.
|
||||||
|
func epiVoid() {
|
||||||
|
fmt.Println("void")
|
||||||
|
}
|
||||||
|
|
||||||
|
// epiNamedMixed has named result variables and a mix of a bare `return` (no
|
||||||
|
// child expressions) and a `return` with child expressions.
|
||||||
|
func epiNamedMixed(x int) (result int, err error) {
|
||||||
|
if x < 0 {
|
||||||
|
result = -x
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// epiNamedBareOnly has a named result variable and only a bare `return`.
|
||||||
|
func epiNamedBareOnly(x int) (n int) {
|
||||||
|
n = x + 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// epiDeferReceiverArgs has a deferred call with a (pointer) receiver and
|
||||||
|
// arguments that are expressions, so we can check the receiver `l` and the
|
||||||
|
// arguments `"count"` and `len(items)` are evaluated at the `defer` statement.
|
||||||
|
func epiDeferReceiverArgs(l *epiLogger, items []int) {
|
||||||
|
defer l.log("count", len(items))
|
||||||
|
fmt.Println("processing", len(items))
|
||||||
|
}
|
||||||
|
|
||||||
|
// epiDeferValueReceiver has deferred calls with a value receiver and an
|
||||||
|
// address-of receiver, both with arguments evaluated at the `defer` statement.
|
||||||
|
func epiDeferValueReceiver(prefix string) {
|
||||||
|
l := epiLogger{prefix: prefix}
|
||||||
|
defer l.logValue("bye")
|
||||||
|
defer (&l).log("ptr", 7)
|
||||||
|
fmt.Println("body")
|
||||||
|
}
|
||||||
|
|
||||||
|
// epiDeferFuncLit has a deferred function literal with parameters, so we can
|
||||||
|
// check that the arguments `"done"` and `x+1` are evaluated at the `defer`
|
||||||
|
// statement and that control flow enters the function literal body when it is
|
||||||
|
// invoked at the function epilogue.
|
||||||
|
func epiDeferFuncLit(x int) {
|
||||||
|
defer func(label string, n int) {
|
||||||
|
fmt.Println(label, n)
|
||||||
|
}("done", x+1)
|
||||||
|
fmt.Println("body", x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// epiRecoverNamed has a named result variable and a deferred closure containing
|
||||||
|
// `recover()`. After recovering on the panic path, control flow should return
|
||||||
|
// to the result-read nodes and the normal exit node.
|
||||||
|
func epiRecoverNamed(x int) (result int) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
result = -1
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if x < 0 {
|
||||||
|
panic("neg")
|
||||||
|
}
|
||||||
|
result = x * x
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// epiRecoverNamedBare has named result variables, a deferred function
|
||||||
|
// containing `recover()`, and only bare `return` statements.
|
||||||
|
func epiRecoverNamedBare(x int) (ok bool, n int) {
|
||||||
|
defer epiRecover()
|
||||||
|
if x == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n = x
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// epiRecoverUnnamed has no named result variables and a deferred function
|
||||||
|
// containing `recover()`; after recovering, control flow should reach the
|
||||||
|
// normal exit node directly (there are no result-read nodes).
|
||||||
|
func epiRecoverUnnamed() {
|
||||||
|
defer epiRecover()
|
||||||
|
panic("boom")
|
||||||
|
}
|
||||||
@@ -4,9 +4,9 @@ invalidModelRow
|
|||||||
| test.go:40:8:40:15 | call to Src2 | qltest |
|
| test.go:40:8:40:15 | call to Src2 | qltest |
|
||||||
| test.go:40:8:40:15 | call to Src2 | qltest-w-subtypes |
|
| test.go:40:8:40:15 | call to Src2 | qltest-w-subtypes |
|
||||||
| test.go:41:8:41:16 | call to Src2 | qltest-w-subtypes |
|
| test.go:41:8:41:16 | call to Src2 | qltest-w-subtypes |
|
||||||
| test.go:42:2:42:21 | ... = ...[0] | qltest |
|
| test.go:42:2:42:21 | extract:0 ... = ... | qltest |
|
||||||
| test.go:42:2:42:21 | ... = ...[1] | qltest-w-subtypes |
|
| test.go:42:2:42:21 | extract:1 ... = ... | qltest-w-subtypes |
|
||||||
| test.go:43:2:43:22 | ... = ...[1] | qltest-w-subtypes |
|
| test.go:43:2:43:22 | extract:1 ... = ... | qltest-w-subtypes |
|
||||||
| test.go:44:11:44:13 | arg [postupdate] | qltest-arg |
|
| test.go:44:11:44:13 | arg [postupdate] | qltest-arg |
|
||||||
| test.go:59:9:59:16 | call to Src1 | qltest |
|
| test.go:59:9:59:16 | call to Src1 | qltest |
|
||||||
| test.go:102:46:102:53 | call to Src1 | qltest |
|
| test.go:102:46:102:53 | call to Src1 | qltest |
|
||||||
@@ -22,4 +22,4 @@ invalidModelRow
|
|||||||
| test.go:187:24:187:31 | call to Src1 | qltest |
|
| test.go:187:24:187:31 | call to Src1 | qltest |
|
||||||
| test.go:191:24:191:31 | call to Src1 | qltest |
|
| test.go:191:24:191:31 | call to Src1 | qltest |
|
||||||
| test.go:209:10:209:28 | selection of SourceVariable | qltest |
|
| test.go:209:10:209:28 | selection of SourceVariable | qltest |
|
||||||
| test.go:216:15:216:17 | SSA def(src) | qltest |
|
| test.go:216:37:218:1 | SSA def(src) | qltest |
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
invalidModelRow
|
invalidModelRow
|
||||||
#select
|
#select
|
||||||
| test.go:17:23:17:25 | arg | test.go:17:10:17:26 | call to StepArgRes |
|
| test.go:17:23:17:25 | arg | test.go:17:10:17:26 | call to StepArgRes |
|
||||||
| test.go:18:27:18:29 | arg | test.go:18:2:18:30 | ... = ...[1] |
|
| test.go:18:27:18:29 | arg | test.go:18:2:18:30 | extract:1 ... = ... |
|
||||||
| test.go:19:15:19:17 | arg | test.go:19:20:19:23 | arg1 [postupdate] |
|
| test.go:19:15:19:17 | arg | test.go:19:20:19:23 | arg1 [postupdate] |
|
||||||
| test.go:21:16:21:18 | arg | test.go:21:2:21:2 | t [postupdate] |
|
| test.go:21:16:21:18 | arg | test.go:21:2:21:2 | t [postupdate] |
|
||||||
| test.go:22:10:22:10 | t | test.go:22:10:22:24 | call to StepQualRes |
|
| test.go:22:10:22:10 | t | test.go:22:10:22:24 | call to StepQualRes |
|
||||||
| test.go:23:2:23:2 | t | test.go:23:16:23:18 | arg [postupdate] |
|
| test.go:23:2:23:2 | t | test.go:23:16:23:18 | arg [postupdate] |
|
||||||
| test.go:24:32:24:34 | arg | test.go:24:10:24:35 | call to StepArgResNoQual |
|
| test.go:24:32:24:34 | arg | test.go:24:10:24:35 | call to StepArgResNoQual |
|
||||||
| test.go:61:25:61:27 | src | test.go:61:12:61:28 | call to StepArgRes |
|
| test.go:61:25:61:27 | src | test.go:61:12:61:28 | call to StepArgRes |
|
||||||
| test.go:64:29:64:31 | src | test.go:64:2:64:32 | ... := ...[1] |
|
| test.go:64:29:64:31 | src | test.go:64:2:64:32 | extract:1 ... := ... |
|
||||||
| test.go:68:15:68:17 | src | test.go:68:20:68:25 | taint3 [postupdate] |
|
| test.go:68:15:68:17 | src | test.go:68:20:68:25 | taint3 [postupdate] |
|
||||||
| test.go:76:21:76:23 | src | test.go:76:2:76:7 | taint4 [postupdate] |
|
| test.go:76:21:76:23 | src | test.go:76:2:76:7 | taint4 [postupdate] |
|
||||||
| test.go:79:13:79:25 | type assertion | test.go:79:12:79:40 | call to StepQualRes |
|
| test.go:79:13:79:25 | type assertion | test.go:79:12:79:40 | call to StepQualRes |
|
||||||
|
|||||||
@@ -1,42 +1,40 @@
|
|||||||
| main.go:6:2:6:5 | 1 | main.go:14:7:14:7 | 1 |
|
| main.go:6:2:6:5 | implicit-one increment statement | main.go:14:7:14:7 | 1 |
|
||||||
| main.go:10:2:10:2 | SSA def(x) | main.go:10:7:10:7 | 0 |
|
| main.go:10:2:10:7 | SSA def(x) | main.go:10:7:10:7 | 0 |
|
||||||
| main.go:10:7:10:7 | 0 | main.go:10:7:10:7 | 0 |
|
| main.go:10:7:10:7 | 0 | main.go:10:7:10:7 | 0 |
|
||||||
| main.go:11:6:11:6 | SSA def(y) | main.go:10:7:10:7 | 0 |
|
| main.go:11:6:11:10 | SSA def(y) | main.go:10:7:10:7 | 0 |
|
||||||
| main.go:11:6:11:6 | zero value for y | main.go:10:7:10:7 | 0 |
|
| main.go:11:6:11:10 | zero-init:0 value declaration specifier | main.go:10:7:10:7 | 0 |
|
||||||
| main.go:12:2:12:18 | call to Println | main.go:12:2:12:18 | call to Println |
|
| main.go:12:2:12:18 | call to Println | main.go:12:2:12:18 | call to Println |
|
||||||
| main.go:12:14:12:14 | x | main.go:10:7:10:7 | 0 |
|
| main.go:12:14:12:14 | x | main.go:10:7:10:7 | 0 |
|
||||||
| main.go:12:17:12:17 | y | main.go:10:7:10:7 | 0 |
|
| main.go:12:17:12:17 | y | main.go:10:7:10:7 | 0 |
|
||||||
| main.go:14:2:14:2 | SSA def(z) | main.go:14:7:14:7 | 1 |
|
| main.go:14:2:14:7 | SSA def(z) | main.go:14:7:14:7 | 1 |
|
||||||
| main.go:14:7:14:7 | 1 | main.go:14:7:14:7 | 1 |
|
| main.go:14:7:14:7 | 1 | main.go:14:7:14:7 | 1 |
|
||||||
| main.go:15:2:15:9 | call to bump | main.go:15:2:15:9 | call to bump |
|
| main.go:15:2:15:9 | call to bump | main.go:15:2:15:9 | call to bump |
|
||||||
| main.go:16:2:16:21 | call to Println | main.go:16:2:16:21 | call to Println |
|
| main.go:16:2:16:21 | call to Println | main.go:16:2:16:21 | call to Println |
|
||||||
| main.go:16:14:16:14 | x | main.go:10:7:10:7 | 0 |
|
| main.go:16:14:16:14 | x | main.go:10:7:10:7 | 0 |
|
||||||
| main.go:16:17:16:17 | y | main.go:10:7:10:7 | 0 |
|
| main.go:16:17:16:17 | y | main.go:10:7:10:7 | 0 |
|
||||||
| main.go:18:2:18:3 | SSA def(ss) | main.go:18:8:18:24 | call to make |
|
| main.go:18:2:18:24 | SSA def(ss) | main.go:18:8:18:24 | call to make |
|
||||||
| main.go:18:8:18:24 | call to make | main.go:18:8:18:24 | call to make |
|
| main.go:18:8:18:24 | call to make | main.go:18:8:18:24 | call to make |
|
||||||
| main.go:18:23:18:23 | 3 | main.go:18:23:18:23 | 3 |
|
| main.go:18:23:18:23 | 3 | main.go:18:23:18:23 | 3 |
|
||||||
| main.go:19:5:19:5 | 2 | main.go:19:5:19:5 | 2 |
|
| main.go:19:5:19:5 | 2 | main.go:19:5:19:5 | 2 |
|
||||||
| main.go:19:10:19:24 | "Hello, world!" | main.go:19:10:19:24 | "Hello, world!" |
|
| main.go:19:10:19:24 | "Hello, world!" | main.go:19:10:19:24 | "Hello, world!" |
|
||||||
| main.go:20:2:20:16 | call to Println | main.go:20:2:20:16 | call to Println |
|
| main.go:20:2:20:16 | call to Println | main.go:20:2:20:16 | call to Println |
|
||||||
| main.go:23:14:23:16 | implicit read of res | main.go:24:8:24:8 | 4 |
|
| main.go:23:23:26:1 | result-read:0 block statement | main.go:24:8:24:8 | 4 |
|
||||||
| main.go:23:14:23:16 | zero value for res | main.go:10:7:10:7 | 0 |
|
| main.go:24:2:24:8 | SSA def(res) | main.go:24:8:24:8 | 4 |
|
||||||
| main.go:24:2:24:4 | SSA def(res) | main.go:24:8:24:8 | 4 |
|
|
||||||
| main.go:24:8:24:8 | 4 | main.go:24:8:24:8 | 4 |
|
| main.go:24:8:24:8 | 4 | main.go:24:8:24:8 | 4 |
|
||||||
| main.go:28:15:28:17 | implicit read of res | main.go:30:9:30:9 | 6 |
|
| main.go:28:24:31:1 | result-read:0 block statement | main.go:29:8:29:8 | 5 |
|
||||||
| main.go:28:15:28:17 | zero value for res | main.go:10:7:10:7 | 0 |
|
| main.go:29:2:29:8 | SSA def(res) | main.go:29:8:29:8 | 5 |
|
||||||
| main.go:29:8:29:8 | 5 | main.go:29:8:29:8 | 5 |
|
| main.go:29:8:29:8 | 5 | main.go:29:8:29:8 | 5 |
|
||||||
| main.go:30:9:30:9 | 6 | main.go:30:9:30:9 | 6 |
|
| main.go:30:9:30:9 | 6 | main.go:30:9:30:9 | 6 |
|
||||||
| main.go:30:9:30:9 | SSA def(res) | main.go:30:9:30:9 | 6 |
|
| main.go:34:2:34:8 | SSA def(res) | main.go:34:8:34:8 | 7 |
|
||||||
| main.go:33:15:33:17 | zero value for res | main.go:10:7:10:7 | 0 |
|
|
||||||
| main.go:34:8:34:8 | 7 | main.go:34:8:34:8 | 7 |
|
| main.go:34:8:34:8 | 7 | main.go:34:8:34:8 | 7 |
|
||||||
| main.go:35:8:37:4 | function call | main.go:35:8:37:4 | function call |
|
| main.go:35:8:37:4 | function call | main.go:35:8:37:4 | function call |
|
||||||
| main.go:36:3:36:5 | SSA def(res) | main.go:36:9:36:9 | 8 |
|
| main.go:36:3:36:9 | SSA def(res) | main.go:36:9:36:9 | 8 |
|
||||||
| main.go:36:9:36:9 | 8 | main.go:36:9:36:9 | 8 |
|
| main.go:36:9:36:9 | 8 | main.go:36:9:36:9 | 8 |
|
||||||
| main.go:38:9:38:9 | 9 | main.go:38:9:38:9 | 9 |
|
| main.go:38:9:38:9 | 9 | main.go:38:9:38:9 | 9 |
|
||||||
| main.go:38:9:38:9 | SSA def(res) | main.go:38:9:38:9 | 9 |
|
|
||||||
| regressions.go:5:11:5:31 | call to Sizeof | regressions.go:5:11:5:31 | call to Sizeof |
|
| regressions.go:5:11:5:31 | call to Sizeof | regressions.go:5:11:5:31 | call to Sizeof |
|
||||||
|
| regressions.go:5:25:5:30 | call to test | regressions.go:5:25:5:30 | call to test |
|
||||||
| regressions.go:7:11:7:15 | false | regressions.go:7:11:7:15 | false |
|
| regressions.go:7:11:7:15 | false | regressions.go:7:11:7:15 | false |
|
||||||
| regressions.go:9:11:9:12 | !... | regressions.go:11:11:11:14 | true |
|
| regressions.go:9:12:9:12 | d | regressions.go:7:11:7:15 | false |
|
||||||
| regressions.go:11:11:11:14 | true | regressions.go:11:11:11:14 | true |
|
| regressions.go:11:11:11:14 | true | regressions.go:11:11:11:14 | true |
|
||||||
| regressions.go:30:9:30:22 | call to getPayload | regressions.go:30:9:30:22 | call to getPayload |
|
| regressions.go:30:9:30:22 | call to getPayload | regressions.go:30:9:30:22 | call to getPayload |
|
||||||
| regressions.go:30:26:30:39 | call to getPayload | regressions.go:30:26:30:39 | call to getPayload |
|
| regressions.go:30:26:30:39 | call to getPayload | regressions.go:30:26:30:39 | call to getPayload |
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
| tst.go:19:10:19:14 | index expression | tst.go:19:10:19:11 | xs | tst.go:19:13:19:13 | 1 |
|
| tst.go:19:10:19:14 | index expression | tst.go:19:10:19:11 | xs | tst.go:19:13:19:13 | 1 |
|
||||||
| tst.go:20:10:20:14 | index expression | tst.go:20:10:20:11 | implicit dereference | tst.go:20:13:20:13 | 1 |
|
| tst.go:20:10:20:14 | index expression | tst.go:20:10:20:11 | implicit-deref ps | tst.go:20:13:20:13 | 1 |
|
||||||
| tst.go:20:10:20:14 | index expression | tst.go:20:10:20:11 | ps | tst.go:20:13:20:13 | 1 |
|
| tst.go:20:10:20:14 | index expression | tst.go:20:10:20:11 | ps | tst.go:20:13:20:13 | 1 |
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
| tst.go:8:8:8:10 | selection of f | tst.go:8:8:8:8 | implicit dereference | tst.go:4:2:4:2 | f |
|
| tst.go:8:8:8:10 | selection of f | tst.go:8:8:8:8 | implicit-deref t | tst.go:4:2:4:2 | f |
|
||||||
| tst.go:8:8:8:10 | selection of f | tst.go:8:8:8:8 | t | tst.go:4:2:4:2 | f |
|
| tst.go:8:8:8:10 | selection of f | tst.go:8:8:8:8 | t | tst.go:4:2:4:2 | f |
|
||||||
| tst.go:13:9:13:11 | selection of f | tst.go:13:9:13:9 | t | tst.go:4:2:4:2 | f |
|
| tst.go:13:9:13:11 | selection of f | tst.go:13:9:13:9 | t | tst.go:4:2:4:2 | f |
|
||||||
| tst.go:17:8:17:10 | selection of f | tst.go:17:8:17:8 | x | tst.go:4:2:4:2 | f |
|
| tst.go:17:8:17:10 | selection of f | tst.go:17:8:17:8 | x | tst.go:4:2:4:2 | f |
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
| tst.go:9:9:9:13 | selection of get | tst.go:9:9:9:9 | implicit dereference | tst.go:12:12:12:14 | get |
|
| tst.go:9:9:9:13 | selection of get | tst.go:9:9:9:9 | implicit-deref t | tst.go:12:12:12:14 | get |
|
||||||
| tst.go:9:9:9:13 | selection of get | tst.go:9:9:9:9 | t | tst.go:12:12:12:14 | get |
|
| tst.go:9:9:9:13 | selection of get | tst.go:9:9:9:9 | t | tst.go:12:12:12:14 | get |
|
||||||
| tst.go:18:2:18:7 | selection of bump | tst.go:18:2:18:2 | x | tst.go:7:13:7:16 | bump |
|
| tst.go:18:2:18:7 | selection of bump | tst.go:18:2:18:2 | x | tst.go:7:13:7:16 | bump |
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
| tst.go:19:2:19:6 | assignment to element | tst.go:19:2:19:3 | xs [postupdate] | tst.go:19:5:19:5 | 0 | tst.go:19:10:19:14 | index expression |
|
| tst.go:19:2:19:14 | assign:0 ... = ... | tst.go:19:2:19:3 | xs [postupdate] | tst.go:19:5:19:5 | 0 | tst.go:19:10:19:14 | index expression |
|
||||||
| tst.go:20:2:20:6 | assignment to element | tst.go:20:2:20:3 | implicit dereference [postupdate] | tst.go:20:5:20:5 | 0 | tst.go:20:10:20:14 | index expression |
|
| tst.go:20:2:20:14 | assign:0 ... = ... | tst.go:20:2:20:3 | implicit-deref ps [postupdate] | tst.go:20:5:20:5 | 0 | tst.go:20:10:20:14 | index expression |
|
||||||
| tst.go:20:2:20:6 | assignment to element | tst.go:20:2:20:3 | ps [postupdate] | tst.go:20:5:20:5 | 0 | tst.go:20:10:20:14 | index expression |
|
| tst.go:20:2:20:14 | assign:0 ... = ... | tst.go:20:2:20:3 | ps [postupdate] | tst.go:20:5:20:5 | 0 | tst.go:20:10:20:14 | index expression |
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
| tst.go:8:2:8:4 | assignment to field f | tst.go:8:2:8:2 | implicit dereference [postupdate] | tst.go:4:2:4:2 | f | tst.go:8:8:8:14 | ...+... |
|
| tst.go:8:2:8:14 | assign:0 ... = ... | tst.go:8:2:8:2 | implicit-deref t [postupdate] | tst.go:4:2:4:2 | f | tst.go:8:8:8:14 | ...+... |
|
||||||
| tst.go:8:2:8:4 | assignment to field f | tst.go:8:2:8:2 | t [postupdate] | tst.go:4:2:4:2 | f | tst.go:8:8:8:14 | ...+... |
|
| tst.go:8:2:8:14 | assign:0 ... = ... | tst.go:8:2:8:2 | t [postupdate] | tst.go:4:2:4:2 | f | tst.go:8:8:8:14 | ...+... |
|
||||||
| tst.go:17:2:17:4 | assignment to field f | tst.go:17:2:17:2 | x [postupdate] | tst.go:4:2:4:2 | f | tst.go:17:8:17:14 | ...+... |
|
| tst.go:17:2:17:14 | assign:0 ... = ... | tst.go:17:2:17:2 | x [postupdate] | tst.go:4:2:4:2 | f | tst.go:17:8:17:14 | ...+... |
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
| test.go:34:16:34:20 | param | test.go:33:11:33:27 | call to QueryParams | test.go:34:16:34:20 | param | Cross-site scripting vulnerability due to $@. | test.go:33:11:33:27 | call to QueryParams | user-provided value | test.go:0:0:0:0 | test.go | |
|
| test.go:34:16:34:20 | param | test.go:33:11:33:27 | call to QueryParams | test.go:34:16:34:20 | param | Cross-site scripting vulnerability due to $@. | test.go:33:11:33:27 | call to QueryParams | user-provided value | test.go:0:0:0:0 | test.go | |
|
||||||
| test.go:40:16:40:19 | qstr | test.go:39:10:39:26 | call to QueryString | test.go:40:16:40:19 | qstr | Cross-site scripting vulnerability due to $@. | test.go:39:10:39:26 | call to QueryString | user-provided value | test.go:0:0:0:0 | test.go | |
|
| test.go:40:16:40:19 | qstr | test.go:39:10:39:26 | call to QueryString | test.go:40:16:40:19 | qstr | Cross-site scripting vulnerability due to $@. | test.go:39:10:39:26 | call to QueryString | user-provided value | test.go:0:0:0:0 | test.go | |
|
||||||
| test.go:46:16:46:18 | val | test.go:45:9:45:34 | call to FormValue | test.go:46:16:46:18 | val | Cross-site scripting vulnerability due to $@. | test.go:45:9:45:34 | call to FormValue | user-provided value | test.go:0:0:0:0 | test.go | |
|
| test.go:46:16:46:18 | val | test.go:45:9:45:34 | call to FormValue | test.go:46:16:46:18 | val | Cross-site scripting vulnerability due to $@. | test.go:45:9:45:34 | call to FormValue | user-provided value | test.go:0:0:0:0 | test.go | |
|
||||||
| test.go:52:16:52:37 | index expression | test.go:51:2:51:30 | ... := ...[0] | test.go:52:16:52:37 | index expression | Cross-site scripting vulnerability due to $@. | test.go:51:2:51:30 | ... := ...[0] | user-provided value | test.go:0:0:0:0 | test.go | |
|
| test.go:52:16:52:37 | index expression | test.go:51:2:51:30 | extract:0 ... := ... | test.go:52:16:52:37 | index expression | Cross-site scripting vulnerability due to $@. | test.go:51:2:51:30 | extract:0 ... := ... | user-provided value | test.go:0:0:0:0 | test.go | |
|
||||||
| test.go:61:20:61:25 | buffer | test.go:57:2:57:46 | ... := ...[0] | test.go:61:20:61:25 | buffer | Cross-site scripting vulnerability due to $@. | test.go:57:2:57:46 | ... := ...[0] | user-provided value | test.go:0:0:0:0 | test.go | |
|
| test.go:61:20:61:25 | buffer | test.go:57:2:57:46 | extract:0 ... := ... | test.go:61:20:61:25 | buffer | Cross-site scripting vulnerability due to $@. | test.go:57:2:57:46 | extract:0 ... := ... | user-provided value | test.go:0:0:0:0 | test.go | |
|
||||||
| test.go:67:16:67:41 | index expression | test.go:66:2:66:31 | ... := ...[0] | test.go:67:16:67:41 | index expression | Cross-site scripting vulnerability due to $@. | test.go:66:2:66:31 | ... := ...[0] | user-provided value | test.go:0:0:0:0 | test.go | |
|
| test.go:67:16:67:41 | index expression | test.go:66:2:66:31 | extract:0 ... := ... | test.go:67:16:67:41 | index expression | Cross-site scripting vulnerability due to $@. | test.go:66:2:66:31 | extract:0 ... := ... | user-provided value | test.go:0:0:0:0 | test.go | |
|
||||||
| test.go:77:20:77:25 | buffer | test.go:72:2:72:31 | ... := ...[0] | test.go:77:20:77:25 | buffer | Cross-site scripting vulnerability due to $@. | test.go:72:2:72:31 | ... := ...[0] | user-provided value | test.go:0:0:0:0 | test.go | |
|
| test.go:77:20:77:25 | buffer | test.go:72:2:72:31 | extract:0 ... := ... | test.go:77:20:77:25 | buffer | Cross-site scripting vulnerability due to $@. | test.go:72:2:72:31 | extract:0 ... := ... | user-provided value | test.go:0:0:0:0 | test.go | |
|
||||||
| test.go:83:16:83:24 | selection of Value | test.go:82:2:82:32 | ... := ...[0] | test.go:83:16:83:24 | selection of Value | Cross-site scripting vulnerability due to $@. | test.go:82:2:82:32 | ... := ...[0] | user-provided value | test.go:0:0:0:0 | test.go | |
|
| test.go:83:16:83:24 | selection of Value | test.go:82:2:82:32 | extract:0 ... := ... | test.go:83:16:83:24 | selection of Value | Cross-site scripting vulnerability due to $@. | test.go:82:2:82:32 | extract:0 ... := ... | user-provided value | test.go:0:0:0:0 | test.go | |
|
||||||
| test.go:89:16:89:31 | selection of Value | test.go:88:13:88:25 | call to Cookies | test.go:89:16:89:31 | selection of Value | Cross-site scripting vulnerability due to $@. | test.go:88:13:88:25 | call to Cookies | user-provided value | test.go:0:0:0:0 | test.go | |
|
| test.go:89:16:89:31 | selection of Value | test.go:88:13:88:25 | call to Cookies | test.go:89:16:89:31 | selection of Value | Cross-site scripting vulnerability due to $@. | test.go:88:13:88:25 | call to Cookies | user-provided value | test.go:0:0:0:0 | test.go | |
|
||||||
| test.go:100:16:100:21 | selection of s | test.go:99:11:99:15 | &... [postupdate] | test.go:100:16:100:21 | selection of s | Cross-site scripting vulnerability due to $@. | test.go:99:11:99:15 | &... [postupdate] | user-provided value | test.go:0:0:0:0 | test.go | |
|
| test.go:100:16:100:21 | selection of s | test.go:99:11:99:15 | &... [postupdate] | test.go:100:16:100:21 | selection of s | Cross-site scripting vulnerability due to $@. | test.go:99:11:99:15 | &... [postupdate] | user-provided value | test.go:0:0:0:0 | test.go | |
|
||||||
| test.go:114:16:114:42 | type assertion | test.go:113:21:113:42 | call to Param | test.go:114:16:114:42 | type assertion | Cross-site scripting vulnerability due to $@. | test.go:113:21:113:42 | call to Param | user-provided value | test.go:0:0:0:0 | test.go | |
|
| test.go:114:16:114:42 | type assertion | test.go:113:21:113:42 | call to Param | test.go:114:16:114:42 | type assertion | Cross-site scripting vulnerability due to $@. | test.go:113:21:113:42 | call to Param | user-provided value | test.go:0:0:0:0 | test.go | |
|
||||||
@@ -25,23 +25,23 @@ edges
|
|||||||
| test.go:33:11:33:27 | call to QueryParams | test.go:34:16:34:20 | param | provenance | Src:MaD:11 |
|
| test.go:33:11:33:27 | call to QueryParams | test.go:34:16:34:20 | param | provenance | Src:MaD:11 |
|
||||||
| test.go:39:10:39:26 | call to QueryString | test.go:40:16:40:19 | qstr | provenance | Src:MaD:12 |
|
| test.go:39:10:39:26 | call to QueryString | test.go:40:16:40:19 | qstr | provenance | Src:MaD:12 |
|
||||||
| test.go:45:9:45:34 | call to FormValue | test.go:46:16:46:18 | val | provenance | Src:MaD:6 |
|
| test.go:45:9:45:34 | call to FormValue | test.go:46:16:46:18 | val | provenance | Src:MaD:6 |
|
||||||
| test.go:51:2:51:30 | ... := ...[0] | test.go:52:16:52:37 | index expression | provenance | Src:MaD:5 |
|
| test.go:51:2:51:30 | extract:0 ... := ... | test.go:52:16:52:37 | index expression | provenance | Src:MaD:5 |
|
||||||
| test.go:57:2:57:46 | ... := ...[0] | test.go:58:13:58:22 | fileHeader | provenance | Src:MaD:4 |
|
| test.go:57:2:57:46 | extract:0 ... := ... | test.go:58:13:58:22 | fileHeader | provenance | Src:MaD:4 |
|
||||||
| test.go:58:2:58:29 | ... := ...[0] | test.go:60:2:60:5 | file | provenance | |
|
| test.go:58:2:58:29 | extract:0 ... := ... | test.go:60:2:60:5 | file | provenance | |
|
||||||
| test.go:58:13:58:22 | fileHeader | test.go:58:2:58:29 | ... := ...[0] | provenance | MaD:17 |
|
| test.go:58:13:58:22 | fileHeader | test.go:58:2:58:29 | extract:0 ... := ... | provenance | MaD:17 |
|
||||||
| test.go:60:2:60:5 | file | test.go:60:12:60:17 | buffer [postupdate] | provenance | MaD:15 |
|
| test.go:60:2:60:5 | file | test.go:60:12:60:17 | buffer [postupdate] | provenance | MaD:15 |
|
||||||
| test.go:60:2:60:5 | file | test.go:60:12:60:17 | buffer [postupdate] | provenance | MaD:16 |
|
| test.go:60:2:60:5 | file | test.go:60:12:60:17 | buffer [postupdate] | provenance | MaD:16 |
|
||||||
| test.go:60:2:60:5 | file | test.go:60:12:60:17 | buffer [postupdate] | provenance | MaD:18 |
|
| test.go:60:2:60:5 | file | test.go:60:12:60:17 | buffer [postupdate] | provenance | MaD:18 |
|
||||||
| test.go:60:12:60:17 | buffer [postupdate] | test.go:61:20:61:25 | buffer | provenance | |
|
| test.go:60:12:60:17 | buffer [postupdate] | test.go:61:20:61:25 | buffer | provenance | |
|
||||||
| test.go:66:2:66:31 | ... := ...[0] | test.go:67:16:67:41 | index expression | provenance | Src:MaD:7 |
|
| test.go:66:2:66:31 | extract:0 ... := ... | test.go:67:16:67:41 | index expression | provenance | Src:MaD:7 |
|
||||||
| test.go:72:2:72:31 | ... := ...[0] | test.go:74:13:74:22 | fileHeader | provenance | Src:MaD:7 |
|
| test.go:72:2:72:31 | extract:0 ... := ... | test.go:74:13:74:22 | fileHeader | provenance | Src:MaD:7 |
|
||||||
| test.go:74:2:74:29 | ... := ...[0] | test.go:76:2:76:5 | file | provenance | |
|
| test.go:74:2:74:29 | extract:0 ... := ... | test.go:76:2:76:5 | file | provenance | |
|
||||||
| test.go:74:13:74:22 | fileHeader | test.go:74:2:74:29 | ... := ...[0] | provenance | MaD:17 |
|
| test.go:74:13:74:22 | fileHeader | test.go:74:2:74:29 | extract:0 ... := ... | provenance | MaD:17 |
|
||||||
| test.go:76:2:76:5 | file | test.go:76:12:76:17 | buffer [postupdate] | provenance | MaD:15 |
|
| test.go:76:2:76:5 | file | test.go:76:12:76:17 | buffer [postupdate] | provenance | MaD:15 |
|
||||||
| test.go:76:2:76:5 | file | test.go:76:12:76:17 | buffer [postupdate] | provenance | MaD:16 |
|
| test.go:76:2:76:5 | file | test.go:76:12:76:17 | buffer [postupdate] | provenance | MaD:16 |
|
||||||
| test.go:76:2:76:5 | file | test.go:76:12:76:17 | buffer [postupdate] | provenance | MaD:18 |
|
| test.go:76:2:76:5 | file | test.go:76:12:76:17 | buffer [postupdate] | provenance | MaD:18 |
|
||||||
| test.go:76:12:76:17 | buffer [postupdate] | test.go:77:20:77:25 | buffer | provenance | |
|
| test.go:76:12:76:17 | buffer [postupdate] | test.go:77:20:77:25 | buffer | provenance | |
|
||||||
| test.go:82:2:82:32 | ... := ...[0] | test.go:83:16:83:24 | selection of Value | provenance | Src:MaD:2 |
|
| test.go:82:2:82:32 | extract:0 ... := ... | test.go:83:16:83:24 | selection of Value | provenance | Src:MaD:2 |
|
||||||
| test.go:88:13:88:25 | call to Cookies | test.go:89:16:89:31 | selection of Value | provenance | Src:MaD:3 |
|
| test.go:88:13:88:25 | call to Cookies | test.go:89:16:89:31 | selection of Value | provenance | Src:MaD:3 |
|
||||||
| test.go:99:11:99:15 | &... [postupdate] | test.go:100:16:100:21 | selection of s | provenance | Src:MaD:1 |
|
| test.go:99:11:99:15 | &... [postupdate] | test.go:100:16:100:21 | selection of s | provenance | Src:MaD:1 |
|
||||||
| test.go:113:2:113:4 | ctx [postupdate] | test.go:114:16:114:18 | ctx | provenance | |
|
| test.go:113:2:113:4 | ctx [postupdate] | test.go:114:16:114:18 | ctx | provenance | |
|
||||||
@@ -88,23 +88,23 @@ nodes
|
|||||||
| test.go:40:16:40:19 | qstr | semmle.label | qstr |
|
| test.go:40:16:40:19 | qstr | semmle.label | qstr |
|
||||||
| test.go:45:9:45:34 | call to FormValue | semmle.label | call to FormValue |
|
| test.go:45:9:45:34 | call to FormValue | semmle.label | call to FormValue |
|
||||||
| test.go:46:16:46:18 | val | semmle.label | val |
|
| test.go:46:16:46:18 | val | semmle.label | val |
|
||||||
| test.go:51:2:51:30 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| test.go:51:2:51:30 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| test.go:52:16:52:37 | index expression | semmle.label | index expression |
|
| test.go:52:16:52:37 | index expression | semmle.label | index expression |
|
||||||
| test.go:57:2:57:46 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| test.go:57:2:57:46 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| test.go:58:2:58:29 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| test.go:58:2:58:29 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| test.go:58:13:58:22 | fileHeader | semmle.label | fileHeader |
|
| test.go:58:13:58:22 | fileHeader | semmle.label | fileHeader |
|
||||||
| test.go:60:2:60:5 | file | semmle.label | file |
|
| test.go:60:2:60:5 | file | semmle.label | file |
|
||||||
| test.go:60:12:60:17 | buffer [postupdate] | semmle.label | buffer [postupdate] |
|
| test.go:60:12:60:17 | buffer [postupdate] | semmle.label | buffer [postupdate] |
|
||||||
| test.go:61:20:61:25 | buffer | semmle.label | buffer |
|
| test.go:61:20:61:25 | buffer | semmle.label | buffer |
|
||||||
| test.go:66:2:66:31 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| test.go:66:2:66:31 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| test.go:67:16:67:41 | index expression | semmle.label | index expression |
|
| test.go:67:16:67:41 | index expression | semmle.label | index expression |
|
||||||
| test.go:72:2:72:31 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| test.go:72:2:72:31 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| test.go:74:2:74:29 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| test.go:74:2:74:29 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| test.go:74:13:74:22 | fileHeader | semmle.label | fileHeader |
|
| test.go:74:13:74:22 | fileHeader | semmle.label | fileHeader |
|
||||||
| test.go:76:2:76:5 | file | semmle.label | file |
|
| test.go:76:2:76:5 | file | semmle.label | file |
|
||||||
| test.go:76:12:76:17 | buffer [postupdate] | semmle.label | buffer [postupdate] |
|
| test.go:76:12:76:17 | buffer [postupdate] | semmle.label | buffer [postupdate] |
|
||||||
| test.go:77:20:77:25 | buffer | semmle.label | buffer |
|
| test.go:77:20:77:25 | buffer | semmle.label | buffer |
|
||||||
| test.go:82:2:82:32 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| test.go:82:2:82:32 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| test.go:83:16:83:24 | selection of Value | semmle.label | selection of Value |
|
| test.go:83:16:83:24 | selection of Value | semmle.label | selection of Value |
|
||||||
| test.go:88:13:88:25 | call to Cookies | semmle.label | call to Cookies |
|
| test.go:88:13:88:25 | call to Cookies | semmle.label | call to Cookies |
|
||||||
| test.go:89:16:89:31 | selection of Value | semmle.label | selection of Value |
|
| test.go:89:16:89:31 | selection of Value | semmle.label | selection of Value |
|
||||||
|
|||||||
@@ -7,18 +7,18 @@
|
|||||||
| Gin.go:58:10:58:25 | call to Param |
|
| Gin.go:58:10:58:25 | call to Param |
|
||||||
| Gin.go:62:10:62:34 | call to GetStringSlice |
|
| Gin.go:62:10:62:34 | call to GetStringSlice |
|
||||||
| Gin.go:66:10:66:29 | call to GetString |
|
| Gin.go:66:10:66:29 | call to GetString |
|
||||||
| Gin.go:70:3:70:28 | ... := ...[0] |
|
| Gin.go:70:3:70:28 | extract:0 ... := ... |
|
||||||
| Gin.go:74:10:74:23 | call to ClientIP |
|
| Gin.go:74:10:74:23 | call to ClientIP |
|
||||||
| Gin.go:78:10:78:26 | call to ContentType |
|
| Gin.go:78:10:78:26 | call to ContentType |
|
||||||
| Gin.go:82:3:82:29 | ... := ...[0] |
|
| Gin.go:82:3:82:29 | extract:0 ... := ... |
|
||||||
| Gin.go:86:3:86:36 | ... := ...[0] |
|
| Gin.go:86:3:86:36 | extract:0 ... := ... |
|
||||||
| Gin.go:90:3:90:31 | ... := ...[0] |
|
| Gin.go:90:3:90:31 | extract:0 ... := ... |
|
||||||
| Gin.go:94:3:94:39 | ... := ...[0] |
|
| Gin.go:94:3:94:39 | extract:0 ... := ... |
|
||||||
| Gin.go:98:3:98:34 | ... := ...[0] |
|
| Gin.go:98:3:98:34 | extract:0 ... := ... |
|
||||||
| Gin.go:102:10:102:52 | call to DefaultPostForm |
|
| Gin.go:102:10:102:52 | call to DefaultPostForm |
|
||||||
| Gin.go:106:10:106:49 | call to DefaultQuery |
|
| Gin.go:106:10:106:49 | call to DefaultQuery |
|
||||||
| Gin.go:110:3:110:37 | ... := ...[0] |
|
| Gin.go:110:3:110:37 | extract:0 ... := ... |
|
||||||
| Gin.go:114:3:114:34 | ... := ...[0] |
|
| Gin.go:114:3:114:34 | extract:0 ... := ... |
|
||||||
| Gin.go:118:10:118:32 | call to GetStringMap |
|
| Gin.go:118:10:118:32 | call to GetStringMap |
|
||||||
| Gin.go:122:10:122:38 | call to GetStringMapString |
|
| Gin.go:122:10:122:38 | call to GetStringMapString |
|
||||||
| Gin.go:126:10:126:43 | call to GetStringMapStringSlice |
|
| Gin.go:126:10:126:43 | call to GetStringMapStringSlice |
|
||||||
|
|||||||
@@ -6,18 +6,18 @@ models
|
|||||||
| 5 | Source: github.com/emicklei/go-restful; Request; true; ReadEntity; ; ; Argument[0]; remote; manual |
|
| 5 | Source: github.com/emicklei/go-restful; Request; true; ReadEntity; ; ; Argument[0]; remote; manual |
|
||||||
edges
|
edges
|
||||||
| gorestful.go:15:15:15:44 | call to QueryParameters | gorestful.go:15:15:15:47 | index expression | provenance | Src:MaD:4 Sink:MaD:1 |
|
| gorestful.go:15:15:15:44 | call to QueryParameters | gorestful.go:15:15:15:47 | index expression | provenance | Src:MaD:4 Sink:MaD:1 |
|
||||||
| gorestful.go:17:2:17:39 | ... := ...[0] | gorestful.go:18:15:18:17 | val | provenance | Src:MaD:2 Sink:MaD:1 |
|
| gorestful.go:17:2:17:39 | extract:0 ... := ... | gorestful.go:18:15:18:17 | val | provenance | Src:MaD:2 Sink:MaD:1 |
|
||||||
| gorestful.go:21:15:21:38 | call to PathParameters | gorestful.go:21:15:21:45 | index expression | provenance | Src:MaD:3 Sink:MaD:1 |
|
| gorestful.go:21:15:21:38 | call to PathParameters | gorestful.go:21:15:21:45 | index expression | provenance | Src:MaD:3 Sink:MaD:1 |
|
||||||
| gorestful.go:23:21:23:24 | &... [postupdate] | gorestful.go:24:15:24:21 | selection of cmd | provenance | Src:MaD:5 Sink:MaD:1 |
|
| gorestful.go:23:21:23:24 | &... [postupdate] | gorestful.go:24:15:24:21 | selection of cmd | provenance | Src:MaD:5 Sink:MaD:1 |
|
||||||
| gorestful_v2.go:15:15:15:44 | call to QueryParameters | gorestful_v2.go:15:15:15:47 | index expression | provenance | Src:MaD:4 Sink:MaD:1 |
|
| gorestful_v2.go:15:15:15:44 | call to QueryParameters | gorestful_v2.go:15:15:15:47 | index expression | provenance | Src:MaD:4 Sink:MaD:1 |
|
||||||
| gorestful_v2.go:17:2:17:39 | ... := ...[0] | gorestful_v2.go:18:15:18:17 | val | provenance | Src:MaD:2 Sink:MaD:1 |
|
| gorestful_v2.go:17:2:17:39 | extract:0 ... := ... | gorestful_v2.go:18:15:18:17 | val | provenance | Src:MaD:2 Sink:MaD:1 |
|
||||||
| gorestful_v2.go:21:15:21:38 | call to PathParameters | gorestful_v2.go:21:15:21:45 | index expression | provenance | Src:MaD:3 Sink:MaD:1 |
|
| gorestful_v2.go:21:15:21:38 | call to PathParameters | gorestful_v2.go:21:15:21:45 | index expression | provenance | Src:MaD:3 Sink:MaD:1 |
|
||||||
| gorestful_v2.go:23:21:23:24 | &... [postupdate] | gorestful_v2.go:24:15:24:21 | selection of cmd | provenance | Src:MaD:5 Sink:MaD:1 |
|
| gorestful_v2.go:23:21:23:24 | &... [postupdate] | gorestful_v2.go:24:15:24:21 | selection of cmd | provenance | Src:MaD:5 Sink:MaD:1 |
|
||||||
nodes
|
nodes
|
||||||
| gorestful.go:15:15:15:44 | call to QueryParameters | semmle.label | call to QueryParameters |
|
| gorestful.go:15:15:15:44 | call to QueryParameters | semmle.label | call to QueryParameters |
|
||||||
| gorestful.go:15:15:15:47 | index expression | semmle.label | index expression |
|
| gorestful.go:15:15:15:47 | index expression | semmle.label | index expression |
|
||||||
| gorestful.go:16:15:16:43 | call to QueryParameter | semmle.label | call to QueryParameter |
|
| gorestful.go:16:15:16:43 | call to QueryParameter | semmle.label | call to QueryParameter |
|
||||||
| gorestful.go:17:2:17:39 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| gorestful.go:17:2:17:39 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| gorestful.go:18:15:18:17 | val | semmle.label | val |
|
| gorestful.go:18:15:18:17 | val | semmle.label | val |
|
||||||
| gorestful.go:19:15:19:44 | call to HeaderParameter | semmle.label | call to HeaderParameter |
|
| gorestful.go:19:15:19:44 | call to HeaderParameter | semmle.label | call to HeaderParameter |
|
||||||
| gorestful.go:20:15:20:42 | call to PathParameter | semmle.label | call to PathParameter |
|
| gorestful.go:20:15:20:42 | call to PathParameter | semmle.label | call to PathParameter |
|
||||||
@@ -28,7 +28,7 @@ nodes
|
|||||||
| gorestful_v2.go:15:15:15:44 | call to QueryParameters | semmle.label | call to QueryParameters |
|
| gorestful_v2.go:15:15:15:44 | call to QueryParameters | semmle.label | call to QueryParameters |
|
||||||
| gorestful_v2.go:15:15:15:47 | index expression | semmle.label | index expression |
|
| gorestful_v2.go:15:15:15:47 | index expression | semmle.label | index expression |
|
||||||
| gorestful_v2.go:16:15:16:43 | call to QueryParameter | semmle.label | call to QueryParameter |
|
| gorestful_v2.go:16:15:16:43 | call to QueryParameter | semmle.label | call to QueryParameter |
|
||||||
| gorestful_v2.go:17:2:17:39 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| gorestful_v2.go:17:2:17:39 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| gorestful_v2.go:18:15:18:17 | val | semmle.label | val |
|
| gorestful_v2.go:18:15:18:17 | val | semmle.label | val |
|
||||||
| gorestful_v2.go:19:15:19:44 | call to HeaderParameter | semmle.label | call to HeaderParameter |
|
| gorestful_v2.go:19:15:19:44 | call to HeaderParameter | semmle.label | call to HeaderParameter |
|
||||||
| gorestful_v2.go:20:15:20:42 | call to PathParameter | semmle.label | call to PathParameter |
|
| gorestful_v2.go:20:15:20:42 | call to PathParameter | semmle.label | call to PathParameter |
|
||||||
@@ -41,14 +41,14 @@ invalidModelRow
|
|||||||
#select
|
#select
|
||||||
| gorestful.go:15:15:15:47 | index expression | gorestful.go:15:15:15:44 | call to QueryParameters | gorestful.go:15:15:15:47 | index expression | This command depends on $@. | gorestful.go:15:15:15:44 | call to QueryParameters | a user-provided value |
|
| gorestful.go:15:15:15:47 | index expression | gorestful.go:15:15:15:44 | call to QueryParameters | gorestful.go:15:15:15:47 | index expression | This command depends on $@. | gorestful.go:15:15:15:44 | call to QueryParameters | a user-provided value |
|
||||||
| gorestful.go:16:15:16:43 | call to QueryParameter | gorestful.go:16:15:16:43 | call to QueryParameter | gorestful.go:16:15:16:43 | call to QueryParameter | This command depends on $@. | gorestful.go:16:15:16:43 | call to QueryParameter | a user-provided value |
|
| gorestful.go:16:15:16:43 | call to QueryParameter | gorestful.go:16:15:16:43 | call to QueryParameter | gorestful.go:16:15:16:43 | call to QueryParameter | This command depends on $@. | gorestful.go:16:15:16:43 | call to QueryParameter | a user-provided value |
|
||||||
| gorestful.go:18:15:18:17 | val | gorestful.go:17:2:17:39 | ... := ...[0] | gorestful.go:18:15:18:17 | val | This command depends on $@. | gorestful.go:17:2:17:39 | ... := ...[0] | a user-provided value |
|
| gorestful.go:18:15:18:17 | val | gorestful.go:17:2:17:39 | extract:0 ... := ... | gorestful.go:18:15:18:17 | val | This command depends on $@. | gorestful.go:17:2:17:39 | extract:0 ... := ... | a user-provided value |
|
||||||
| gorestful.go:19:15:19:44 | call to HeaderParameter | gorestful.go:19:15:19:44 | call to HeaderParameter | gorestful.go:19:15:19:44 | call to HeaderParameter | This command depends on $@. | gorestful.go:19:15:19:44 | call to HeaderParameter | a user-provided value |
|
| gorestful.go:19:15:19:44 | call to HeaderParameter | gorestful.go:19:15:19:44 | call to HeaderParameter | gorestful.go:19:15:19:44 | call to HeaderParameter | This command depends on $@. | gorestful.go:19:15:19:44 | call to HeaderParameter | a user-provided value |
|
||||||
| gorestful.go:20:15:20:42 | call to PathParameter | gorestful.go:20:15:20:42 | call to PathParameter | gorestful.go:20:15:20:42 | call to PathParameter | This command depends on $@. | gorestful.go:20:15:20:42 | call to PathParameter | a user-provided value |
|
| gorestful.go:20:15:20:42 | call to PathParameter | gorestful.go:20:15:20:42 | call to PathParameter | gorestful.go:20:15:20:42 | call to PathParameter | This command depends on $@. | gorestful.go:20:15:20:42 | call to PathParameter | a user-provided value |
|
||||||
| gorestful.go:21:15:21:45 | index expression | gorestful.go:21:15:21:38 | call to PathParameters | gorestful.go:21:15:21:45 | index expression | This command depends on $@. | gorestful.go:21:15:21:38 | call to PathParameters | a user-provided value |
|
| gorestful.go:21:15:21:45 | index expression | gorestful.go:21:15:21:38 | call to PathParameters | gorestful.go:21:15:21:45 | index expression | This command depends on $@. | gorestful.go:21:15:21:38 | call to PathParameters | a user-provided value |
|
||||||
| gorestful.go:24:15:24:21 | selection of cmd | gorestful.go:23:21:23:24 | &... [postupdate] | gorestful.go:24:15:24:21 | selection of cmd | This command depends on $@. | gorestful.go:23:21:23:24 | &... [postupdate] | a user-provided value |
|
| gorestful.go:24:15:24:21 | selection of cmd | gorestful.go:23:21:23:24 | &... [postupdate] | gorestful.go:24:15:24:21 | selection of cmd | This command depends on $@. | gorestful.go:23:21:23:24 | &... [postupdate] | a user-provided value |
|
||||||
| gorestful_v2.go:15:15:15:47 | index expression | gorestful_v2.go:15:15:15:44 | call to QueryParameters | gorestful_v2.go:15:15:15:47 | index expression | This command depends on $@. | gorestful_v2.go:15:15:15:44 | call to QueryParameters | a user-provided value |
|
| gorestful_v2.go:15:15:15:47 | index expression | gorestful_v2.go:15:15:15:44 | call to QueryParameters | gorestful_v2.go:15:15:15:47 | index expression | This command depends on $@. | gorestful_v2.go:15:15:15:44 | call to QueryParameters | a user-provided value |
|
||||||
| gorestful_v2.go:16:15:16:43 | call to QueryParameter | gorestful_v2.go:16:15:16:43 | call to QueryParameter | gorestful_v2.go:16:15:16:43 | call to QueryParameter | This command depends on $@. | gorestful_v2.go:16:15:16:43 | call to QueryParameter | a user-provided value |
|
| gorestful_v2.go:16:15:16:43 | call to QueryParameter | gorestful_v2.go:16:15:16:43 | call to QueryParameter | gorestful_v2.go:16:15:16:43 | call to QueryParameter | This command depends on $@. | gorestful_v2.go:16:15:16:43 | call to QueryParameter | a user-provided value |
|
||||||
| gorestful_v2.go:18:15:18:17 | val | gorestful_v2.go:17:2:17:39 | ... := ...[0] | gorestful_v2.go:18:15:18:17 | val | This command depends on $@. | gorestful_v2.go:17:2:17:39 | ... := ...[0] | a user-provided value |
|
| gorestful_v2.go:18:15:18:17 | val | gorestful_v2.go:17:2:17:39 | extract:0 ... := ... | gorestful_v2.go:18:15:18:17 | val | This command depends on $@. | gorestful_v2.go:17:2:17:39 | extract:0 ... := ... | a user-provided value |
|
||||||
| gorestful_v2.go:19:15:19:44 | call to HeaderParameter | gorestful_v2.go:19:15:19:44 | call to HeaderParameter | gorestful_v2.go:19:15:19:44 | call to HeaderParameter | This command depends on $@. | gorestful_v2.go:19:15:19:44 | call to HeaderParameter | a user-provided value |
|
| gorestful_v2.go:19:15:19:44 | call to HeaderParameter | gorestful_v2.go:19:15:19:44 | call to HeaderParameter | gorestful_v2.go:19:15:19:44 | call to HeaderParameter | This command depends on $@. | gorestful_v2.go:19:15:19:44 | call to HeaderParameter | a user-provided value |
|
||||||
| gorestful_v2.go:20:15:20:42 | call to PathParameter | gorestful_v2.go:20:15:20:42 | call to PathParameter | gorestful_v2.go:20:15:20:42 | call to PathParameter | This command depends on $@. | gorestful_v2.go:20:15:20:42 | call to PathParameter | a user-provided value |
|
| gorestful_v2.go:20:15:20:42 | call to PathParameter | gorestful_v2.go:20:15:20:42 | call to PathParameter | gorestful_v2.go:20:15:20:42 | call to PathParameter | This command depends on $@. | gorestful_v2.go:20:15:20:42 | call to PathParameter | a user-provided value |
|
||||||
| gorestful_v2.go:21:15:21:45 | index expression | gorestful_v2.go:21:15:21:38 | call to PathParameters | gorestful_v2.go:21:15:21:45 | index expression | This command depends on $@. | gorestful_v2.go:21:15:21:38 | call to PathParameters | a user-provided value |
|
| gorestful_v2.go:21:15:21:45 | index expression | gorestful_v2.go:21:15:21:38 | call to PathParameters | gorestful_v2.go:21:15:21:45 | index expression | This command depends on $@. | gorestful_v2.go:21:15:21:38 | call to PathParameters | a user-provided value |
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
#select
|
#select
|
||||||
| EndToEnd.go:95:20:95:49 | call to Get | EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:49 | call to Get | This path to an untrusted URL redirection depends on a $@. | EndToEnd.go:95:20:95:27 | selection of Params | user-provided value |
|
| EndToEnd.go:95:20:95:49 | call to Get | EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:49 | call to Get | This path to an untrusted URL redirection depends on a $@. | EndToEnd.go:95:20:95:27 | selection of Params | user-provided value |
|
||||||
edges
|
edges
|
||||||
| EndToEnd.go:95:20:95:27 | implicit dereference | EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | provenance | Config |
|
| EndToEnd.go:95:20:95:27 | implicit-deref selection of Params | EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | provenance | Config |
|
||||||
| EndToEnd.go:95:20:95:27 | implicit dereference | EndToEnd.go:95:20:95:32 | selection of Form | provenance | Config |
|
| EndToEnd.go:95:20:95:27 | implicit-deref selection of Params | EndToEnd.go:95:20:95:32 | selection of Form | provenance | Config |
|
||||||
| EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:27 | implicit dereference | provenance | Src:MaD:2 Config |
|
| EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:27 | implicit-deref selection of Params | provenance | Src:MaD:2 Config |
|
||||||
| EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:32 | selection of Form | provenance | Src:MaD:2 Config |
|
| EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:32 | selection of Form | provenance | Src:MaD:2 Config |
|
||||||
| EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | EndToEnd.go:95:20:95:27 | implicit dereference | provenance | Config |
|
| EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | EndToEnd.go:95:20:95:27 | implicit-deref selection of Params | provenance | Config |
|
||||||
| EndToEnd.go:95:20:95:32 | selection of Form | EndToEnd.go:95:20:95:49 | call to Get | provenance | Config Sink:MaD:1 |
|
| EndToEnd.go:95:20:95:32 | selection of Form | EndToEnd.go:95:20:95:49 | call to Get | provenance | Config Sink:MaD:1 |
|
||||||
models
|
models
|
||||||
| 1 | Sink: group:revel; Controller; true; Redirect; ; ; Argument[0]; url-redirection; manual |
|
| 1 | Sink: group:revel; Controller; true; Redirect; ; ; Argument[0]; url-redirection; manual |
|
||||||
| 2 | Source: group:revel; Controller; true; Params; ; ; ; remote; manual |
|
| 2 | Source: group:revel; Controller; true; Params; ; ; ; remote; manual |
|
||||||
nodes
|
nodes
|
||||||
| EndToEnd.go:95:20:95:27 | implicit dereference | semmle.label | implicit dereference |
|
| EndToEnd.go:95:20:95:27 | implicit-deref selection of Params | semmle.label | implicit-deref selection of Params |
|
||||||
| EndToEnd.go:95:20:95:27 | selection of Params | semmle.label | selection of Params |
|
| EndToEnd.go:95:20:95:27 | selection of Params | semmle.label | selection of Params |
|
||||||
| EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | semmle.label | selection of Params [postupdate] |
|
| EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | semmle.label | selection of Params [postupdate] |
|
||||||
| EndToEnd.go:95:20:95:32 | selection of Form | semmle.label | selection of Form |
|
| EndToEnd.go:95:20:95:32 | selection of Form | semmle.label | selection of Form |
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
invalidModelRow
|
invalidModelRow
|
||||||
#select
|
#select
|
||||||
| crypto.go:9:14:9:31 | call to NewCipher | crypto.go:9:2:9:31 | ... := ...[0] |
|
| crypto.go:9:14:9:31 | call to NewCipher | crypto.go:9:2:9:31 | extract:0 ... := ... |
|
||||||
| crypto.go:9:14:9:31 | call to NewCipher | crypto.go:9:2:9:31 | ... := ...[1] |
|
| crypto.go:9:14:9:31 | call to NewCipher | crypto.go:9:2:9:31 | extract:1 ... := ... |
|
||||||
| crypto.go:10:15:10:34 | call to NewGCM | crypto.go:10:2:10:34 | ... := ...[0] |
|
| crypto.go:10:15:10:34 | call to NewGCM | crypto.go:10:2:10:34 | extract:0 ... := ... |
|
||||||
| crypto.go:10:15:10:34 | call to NewGCM | crypto.go:10:2:10:34 | ... := ...[1] |
|
| crypto.go:10:15:10:34 | call to NewGCM | crypto.go:10:2:10:34 | extract:1 ... := ... |
|
||||||
| crypto.go:11:18:11:57 | call to Open | crypto.go:11:2:11:57 | ... := ...[0] |
|
| crypto.go:11:18:11:57 | call to Open | crypto.go:11:2:11:57 | extract:0 ... := ... |
|
||||||
| crypto.go:11:18:11:57 | call to Open | crypto.go:11:2:11:57 | ... := ...[1] |
|
| crypto.go:11:18:11:57 | call to Open | crypto.go:11:2:11:57 | extract:1 ... := ... |
|
||||||
| crypto.go:11:42:11:51 | ciphertext | crypto.go:11:2:11:57 | ... := ...[0] |
|
| crypto.go:11:42:11:51 | ciphertext | crypto.go:11:2:11:57 | extract:0 ... := ... |
|
||||||
| io.go:14:31:14:43 | "some string" | io.go:14:13:14:44 | call to NewReader |
|
| io.go:14:31:14:43 | "some string" | io.go:14:13:14:44 | call to NewReader |
|
||||||
| io.go:16:23:16:27 | &... | io.go:16:24:16:27 | buf1 [postupdate] |
|
| io.go:16:23:16:27 | &... | io.go:16:24:16:27 | buf1 [postupdate] |
|
||||||
| io.go:16:23:16:27 | &... [postupdate] | io.go:16:24:16:27 | buf1 [postupdate] |
|
| io.go:16:23:16:27 | &... [postupdate] | io.go:16:24:16:27 | buf1 [postupdate] |
|
||||||
@@ -31,9 +31,9 @@ invalidModelRow
|
|||||||
| io.go:33:20:33:23 | buf1 | io.go:33:19:33:23 | &... |
|
| io.go:33:20:33:23 | buf1 | io.go:33:19:33:23 | &... |
|
||||||
| io.go:33:20:33:23 | buf1 [postupdate] | io.go:33:19:33:23 | &... |
|
| io.go:33:20:33:23 | buf1 [postupdate] | io.go:33:19:33:23 | &... |
|
||||||
| io.go:35:16:35:21 | reader | io.go:35:12:35:13 | w2 [postupdate] |
|
| io.go:35:16:35:21 | reader | io.go:35:12:35:13 | w2 [postupdate] |
|
||||||
| io.go:39:11:39:19 | call to Pipe | io.go:39:3:39:19 | ... := ...[0] |
|
| io.go:39:11:39:19 | call to Pipe | io.go:39:3:39:19 | extract:0 ... := ... |
|
||||||
| io.go:39:11:39:19 | call to Pipe | io.go:39:3:39:19 | ... := ...[1] |
|
| io.go:39:11:39:19 | call to Pipe | io.go:39:3:39:19 | extract:1 ... := ... |
|
||||||
| io.go:40:14:40:14 | w [postupdate] | io.go:39:3:39:19 | ... := ...[0] |
|
| io.go:40:14:40:14 | w [postupdate] | io.go:39:3:39:19 | extract:0 ... := ... |
|
||||||
| io.go:40:17:40:31 | "some string\\n" | io.go:40:14:40:14 | w [postupdate] |
|
| io.go:40:17:40:31 | "some string\\n" | io.go:40:14:40:14 | w [postupdate] |
|
||||||
| io.go:43:16:43:16 | r | io.go:43:3:43:5 | buf [postupdate] |
|
| io.go:43:16:43:16 | r | io.go:43:3:43:5 | buf [postupdate] |
|
||||||
| io.go:44:13:44:15 | buf | io.go:44:13:44:24 | call to String |
|
| io.go:44:13:44:15 | buf | io.go:44:13:44:24 | call to String |
|
||||||
@@ -74,35 +74,35 @@ invalidModelRow
|
|||||||
| io.go:101:26:101:38 | "some string" | io.go:101:8:101:39 | call to NewReader |
|
| io.go:101:26:101:38 | "some string" | io.go:101:8:101:39 | call to NewReader |
|
||||||
| io.go:102:3:102:3 | r | io.go:102:13:102:21 | selection of Stdout [postupdate] |
|
| io.go:102:3:102:3 | r | io.go:102:13:102:21 | selection of Stdout [postupdate] |
|
||||||
| io.go:108:30:108:42 | "some string" | io.go:108:12:108:43 | call to NewReader |
|
| io.go:108:30:108:42 | "some string" | io.go:108:12:108:43 | call to NewReader |
|
||||||
| io.go:109:12:109:33 | call to ReadAll | io.go:109:2:109:33 | ... := ...[0] |
|
| io.go:109:12:109:33 | call to ReadAll | io.go:109:2:109:33 | extract:0 ... := ... |
|
||||||
| io.go:109:12:109:33 | call to ReadAll | io.go:109:2:109:33 | ... := ...[1] |
|
| io.go:109:12:109:33 | call to ReadAll | io.go:109:2:109:33 | extract:1 ... := ... |
|
||||||
| io.go:109:27:109:32 | reader | io.go:109:2:109:33 | ... := ...[0] |
|
| io.go:109:27:109:32 | reader | io.go:109:2:109:33 | extract:0 ... := ... |
|
||||||
| io.go:110:18:110:20 | buf | io.go:110:2:110:10 | selection of Stdout [postupdate] |
|
| io.go:110:18:110:20 | buf | io.go:110:2:110:10 | selection of Stdout [postupdate] |
|
||||||
| main.go:11:12:11:26 | call to Marshal | main.go:11:2:11:26 | ... := ...[0] |
|
| main.go:11:12:11:26 | call to Marshal | main.go:11:2:11:26 | extract:0 ... := ... |
|
||||||
| main.go:11:12:11:26 | call to Marshal | main.go:11:2:11:26 | ... := ...[1] |
|
| main.go:11:12:11:26 | call to Marshal | main.go:11:2:11:26 | extract:1 ... := ... |
|
||||||
| main.go:11:25:11:25 | v | main.go:11:2:11:26 | ... := ...[0] |
|
| main.go:11:25:11:25 | v | main.go:11:2:11:26 | extract:0 ... := ... |
|
||||||
| main.go:13:14:13:52 | call to MarshalIndent | main.go:13:2:13:52 | ... := ...[0] |
|
| main.go:13:14:13:52 | call to MarshalIndent | main.go:13:2:13:52 | extract:0 ... := ... |
|
||||||
| main.go:13:14:13:52 | call to MarshalIndent | main.go:13:2:13:52 | ... := ...[1] |
|
| main.go:13:14:13:52 | call to MarshalIndent | main.go:13:2:13:52 | extract:1 ... := ... |
|
||||||
| main.go:13:33:13:33 | v | main.go:13:2:13:52 | ... := ...[0] |
|
| main.go:13:33:13:33 | v | main.go:13:2:13:52 | extract:0 ... := ... |
|
||||||
| main.go:13:36:13:45 | "/*JSON*/" | main.go:13:2:13:52 | ... := ...[0] |
|
| main.go:13:36:13:45 | "/*JSON*/" | main.go:13:2:13:52 | extract:0 ... := ... |
|
||||||
| main.go:13:48:13:51 | " " | main.go:13:2:13:52 | ... := ...[0] |
|
| main.go:13:48:13:51 | " " | main.go:13:2:13:52 | extract:0 ... := ... |
|
||||||
| main.go:14:25:14:25 | b | main.go:14:9:14:41 | slice literal |
|
| main.go:14:25:14:25 | b | main.go:14:9:14:41 | slice literal |
|
||||||
| main.go:14:28:14:30 | err | main.go:14:9:14:41 | slice literal |
|
| main.go:14:28:14:30 | err | main.go:14:9:14:41 | slice literal |
|
||||||
| main.go:14:33:14:34 | b2 | main.go:14:9:14:41 | slice literal |
|
| main.go:14:33:14:34 | b2 | main.go:14:9:14:41 | slice literal |
|
||||||
| main.go:14:37:14:40 | err2 | main.go:14:9:14:41 | slice literal |
|
| main.go:14:37:14:40 | err2 | main.go:14:9:14:41 | slice literal |
|
||||||
| main.go:19:18:19:42 | call to DecodeString | main.go:19:2:19:42 | ... := ...[0] |
|
| main.go:19:18:19:42 | call to DecodeString | main.go:19:2:19:42 | extract:0 ... := ... |
|
||||||
| main.go:19:18:19:42 | call to DecodeString | main.go:19:2:19:42 | ... := ...[1] |
|
| main.go:19:18:19:42 | call to DecodeString | main.go:19:2:19:42 | extract:1 ... := ... |
|
||||||
| main.go:19:35:19:41 | encoded | main.go:19:2:19:42 | ... := ...[0] |
|
| main.go:19:35:19:41 | encoded | main.go:19:2:19:42 | extract:0 ... := ... |
|
||||||
| main.go:23:25:23:31 | decoded | main.go:23:9:23:48 | slice literal |
|
| main.go:23:25:23:31 | decoded | main.go:23:9:23:48 | slice literal |
|
||||||
| main.go:23:34:23:36 | err | main.go:23:9:23:48 | slice literal |
|
| main.go:23:34:23:36 | err | main.go:23:9:23:48 | slice literal |
|
||||||
| main.go:23:39:23:47 | reEncoded | main.go:23:9:23:48 | slice literal |
|
| main.go:23:39:23:47 | reEncoded | main.go:23:9:23:48 | slice literal |
|
||||||
| main.go:28:2:28:4 | implicit dereference | main.go:28:2:28:4 | req [postupdate] |
|
| main.go:28:2:28:4 | implicit-deref req | main.go:28:2:28:4 | req [postupdate] |
|
||||||
| main.go:28:2:28:4 | implicit dereference | main.go:28:2:28:9 | selection of Body |
|
| main.go:28:2:28:4 | implicit-deref req | main.go:28:2:28:9 | selection of Body |
|
||||||
| main.go:28:2:28:4 | req | main.go:28:2:28:4 | implicit dereference |
|
| main.go:28:2:28:4 | req | main.go:28:2:28:4 | implicit-deref req |
|
||||||
| main.go:28:2:28:4 | req [postupdate] | main.go:28:2:28:4 | implicit dereference |
|
| main.go:28:2:28:4 | req [postupdate] | main.go:28:2:28:4 | implicit-deref req |
|
||||||
| main.go:28:2:28:9 | selection of Body | main.go:28:16:28:16 | b [postupdate] |
|
| main.go:28:2:28:9 | selection of Body | main.go:28:16:28:16 | b [postupdate] |
|
||||||
| main.go:34:2:34:4 | implicit dereference | main.go:34:2:34:4 | req [postupdate] |
|
| main.go:34:2:34:4 | implicit-deref req | main.go:34:2:34:4 | req [postupdate] |
|
||||||
| main.go:34:2:34:4 | implicit dereference | main.go:34:2:34:9 | selection of Body |
|
| main.go:34:2:34:4 | implicit-deref req | main.go:34:2:34:9 | selection of Body |
|
||||||
| main.go:34:2:34:4 | req | main.go:34:2:34:4 | implicit dereference |
|
| main.go:34:2:34:4 | req | main.go:34:2:34:4 | implicit-deref req |
|
||||||
| main.go:34:2:34:4 | req [postupdate] | main.go:34:2:34:4 | implicit dereference |
|
| main.go:34:2:34:4 | req [postupdate] | main.go:34:2:34:4 | implicit-deref req |
|
||||||
| main.go:34:2:34:9 | selection of Body | main.go:34:16:34:16 | b [postupdate] |
|
| main.go:34:2:34:9 | selection of Body | main.go:34:16:34:16 | b [postupdate] |
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
#select
|
#select
|
||||||
| server/main.go:30:38:30:48 | selection of Text | rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | server/main.go:30:38:30:48 | selection of Text | The $@ of this request depends on a $@. | server/main.go:30:38:30:48 | selection of Text | URL | rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | user-provided value |
|
| server/main.go:30:38:30:48 | selection of Text | rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | server/main.go:30:38:30:48 | selection of Text | The $@ of this request depends on a $@. | server/main.go:30:38:30:48 | selection of Text | URL | rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | user-provided value |
|
||||||
| server/main.go:30:38:30:48 | selection of Text | server/main.go:19:56:19:61 | SSA def(params) | server/main.go:30:38:30:48 | selection of Text | The $@ of this request depends on a $@. | server/main.go:30:38:30:48 | selection of Text | URL | server/main.go:19:56:19:61 | SSA def(params) | user-provided value |
|
| server/main.go:30:38:30:48 | selection of Text | server/main.go:19:109:38:1 | SSA def(params) | server/main.go:30:38:30:48 | selection of Text | The $@ of this request depends on a $@. | server/main.go:30:38:30:48 | selection of Text | URL | server/main.go:19:109:38:1 | SSA def(params) | user-provided value |
|
||||||
edges
|
edges
|
||||||
| client/main.go:16:35:16:78 | &... | server/main.go:19:56:19:61 | SSA def(params) | provenance | |
|
| client/main.go:16:35:16:78 | &... | server/main.go:19:109:38:1 | SSA def(params) | provenance | |
|
||||||
| client/main.go:16:35:16:78 | &... [postupdate] | client/main.go:16:35:16:78 | &... | provenance | |
|
| client/main.go:16:35:16:78 | &... [postupdate] | client/main.go:16:35:16:78 | &... | provenance | |
|
||||||
| rpc/notes/service.twirp.go:538:2:538:33 | ... := ...[0] | rpc/notes/service.twirp.go:544:27:544:29 | buf | provenance | |
|
| rpc/notes/service.twirp.go:538:2:538:33 | extract:0 ... := ... | rpc/notes/service.twirp.go:544:27:544:29 | buf | provenance | |
|
||||||
| rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | rpc/notes/service.twirp.go:538:2:538:33 | ... := ...[0] | provenance | Src:MaD:1 MaD:3 |
|
| rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | rpc/notes/service.twirp.go:538:2:538:33 | extract:0 ... := ... | provenance | Src:MaD:1 MaD:3 |
|
||||||
| rpc/notes/service.twirp.go:544:27:544:29 | buf | rpc/notes/service.twirp.go:544:32:544:41 | reqContent [postupdate] | provenance | MaD:2 |
|
| rpc/notes/service.twirp.go:544:27:544:29 | buf | rpc/notes/service.twirp.go:544:32:544:41 | reqContent [postupdate] | provenance | MaD:2 |
|
||||||
| rpc/notes/service.twirp.go:544:32:544:41 | reqContent [postupdate] | rpc/notes/service.twirp.go:574:2:577:2 | SSA def(reqContent) | provenance | |
|
| rpc/notes/service.twirp.go:544:32:544:41 | reqContent [postupdate] | rpc/notes/service.twirp.go:574:2:577:2 | SSA def(reqContent) | provenance | |
|
||||||
| rpc/notes/service.twirp.go:574:2:577:2 | SSA def(reqContent) | rpc/notes/service.twirp.go:576:35:576:44 | reqContent | provenance | |
|
| rpc/notes/service.twirp.go:574:2:577:2 | SSA def(reqContent) | rpc/notes/service.twirp.go:576:35:576:44 | reqContent | provenance | |
|
||||||
| rpc/notes/service.twirp.go:576:35:576:44 | reqContent | server/main.go:19:56:19:61 | SSA def(params) | provenance | |
|
| rpc/notes/service.twirp.go:576:35:576:44 | reqContent | server/main.go:19:109:38:1 | SSA def(params) | provenance | |
|
||||||
| server/main.go:19:56:19:61 | SSA def(params) | server/main.go:19:56:19:61 | SSA def(params) [Return] | provenance | |
|
| server/main.go:19:109:38:1 | SSA def(params) | server/main.go:19:109:38:1 | SSA def(params) [Return] | provenance | |
|
||||||
| server/main.go:19:56:19:61 | SSA def(params) | server/main.go:30:38:30:48 | selection of Text | provenance | |
|
| server/main.go:19:109:38:1 | SSA def(params) | server/main.go:30:38:30:48 | selection of Text | provenance | |
|
||||||
| server/main.go:19:56:19:61 | SSA def(params) | server/main.go:30:38:30:48 | selection of Text | provenance | |
|
| server/main.go:19:109:38:1 | SSA def(params) | server/main.go:30:38:30:48 | selection of Text | provenance | |
|
||||||
| server/main.go:19:56:19:61 | SSA def(params) [Return] | client/main.go:16:35:16:78 | &... [postupdate] | provenance | |
|
| server/main.go:19:109:38:1 | SSA def(params) [Return] | client/main.go:16:35:16:78 | &... [postupdate] | provenance | |
|
||||||
models
|
models
|
||||||
| 1 | Source: net/http; Request; true; Body; ; ; ; remote; manual |
|
| 1 | Source: net/http; Request; true; Body; ; ; ; remote; manual |
|
||||||
| 2 | Summary: google.golang.org/protobuf/proto; ; false; Unmarshal; ; ; Argument[0]; Argument[1]; taint; manual |
|
| 2 | Summary: google.golang.org/protobuf/proto; ; false; Unmarshal; ; ; Argument[0]; Argument[1]; taint; manual |
|
||||||
@@ -21,14 +21,17 @@ models
|
|||||||
nodes
|
nodes
|
||||||
| client/main.go:16:35:16:78 | &... | semmle.label | &... |
|
| client/main.go:16:35:16:78 | &... | semmle.label | &... |
|
||||||
| client/main.go:16:35:16:78 | &... [postupdate] | semmle.label | &... [postupdate] |
|
| client/main.go:16:35:16:78 | &... [postupdate] | semmle.label | &... [postupdate] |
|
||||||
| rpc/notes/service.twirp.go:538:2:538:33 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| rpc/notes/service.twirp.go:538:2:538:33 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | semmle.label | selection of Body |
|
| rpc/notes/service.twirp.go:538:25:538:32 | selection of Body | semmle.label | selection of Body |
|
||||||
| rpc/notes/service.twirp.go:544:27:544:29 | buf | semmle.label | buf |
|
| rpc/notes/service.twirp.go:544:27:544:29 | buf | semmle.label | buf |
|
||||||
| rpc/notes/service.twirp.go:544:32:544:41 | reqContent [postupdate] | semmle.label | reqContent [postupdate] |
|
| rpc/notes/service.twirp.go:544:32:544:41 | reqContent [postupdate] | semmle.label | reqContent [postupdate] |
|
||||||
| rpc/notes/service.twirp.go:574:2:577:2 | SSA def(reqContent) | semmle.label | SSA def(reqContent) |
|
| rpc/notes/service.twirp.go:574:2:577:2 | SSA def(reqContent) | semmle.label | SSA def(reqContent) |
|
||||||
| rpc/notes/service.twirp.go:576:35:576:44 | reqContent | semmle.label | reqContent |
|
| rpc/notes/service.twirp.go:576:35:576:44 | reqContent | semmle.label | reqContent |
|
||||||
| server/main.go:19:56:19:61 | SSA def(params) | semmle.label | SSA def(params) |
|
| server/main.go:19:109:38:1 | SSA def(params) | semmle.label | SSA def(params) |
|
||||||
| server/main.go:19:56:19:61 | SSA def(params) | semmle.label | SSA def(params) |
|
| server/main.go:19:109:38:1 | SSA def(params) | semmle.label | SSA def(params) |
|
||||||
| server/main.go:19:56:19:61 | SSA def(params) [Return] | semmle.label | SSA def(params) [Return] |
|
| server/main.go:19:109:38:1 | SSA def(params) [Return] | semmle.label | SSA def(params) [Return] |
|
||||||
| server/main.go:30:38:30:48 | selection of Text | semmle.label | selection of Text |
|
| server/main.go:30:38:30:48 | selection of Text | semmle.label | selection of Text |
|
||||||
subpaths
|
subpaths
|
||||||
|
testFailures
|
||||||
|
| server/main.go:19:109:38:1 | SSA def(params) | Unexpected result: Source |
|
||||||
|
| server/main.go:19:111:19:154 | comment | Missing result: Source |
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
| tests.go:61:30:61:35 | result | $@ may be nil at this dereference because $@ may not have been checked. | tests.go:59:2:59:7 | SSA def(result) | result | tests.go:59:10:59:12 | SSA def(err) | err |
|
| tests.go:61:30:61:35 | result | $@ may be nil at this dereference because $@ may not have been checked. | tests.go:59:2:59:30 | SSA def(result) | result | tests.go:59:2:59:30 | SSA def(err) | err |
|
||||||
| tests.go:243:27:243:32 | result | $@ may be nil at this dereference because $@ may not have been checked. | tests.go:241:2:241:7 | SSA def(result) | result | tests.go:241:10:241:12 | SSA def(err) | err |
|
| tests.go:243:27:243:32 | result | $@ may be nil at this dereference because $@ may not have been checked. | tests.go:241:2:241:37 | SSA def(result) | result | tests.go:241:2:241:37 | SSA def(err) | err |
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
#select
|
#select
|
||||||
| tests.go:10:8:10:8 | f | tests.go:32:5:32:78 | ... := ...[0] | tests.go:10:8:10:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:32:15:32:78 | call to OpenFile | call to OpenFile |
|
| tests.go:10:8:10:8 | f | tests.go:32:5:32:78 | extract:0 ... := ... | tests.go:10:8:10:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:32:15:32:78 | call to OpenFile | call to OpenFile |
|
||||||
| tests.go:10:8:10:8 | f | tests.go:46:5:46:76 | ... := ...[0] | tests.go:10:8:10:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:46:15:46:76 | call to OpenFile | call to OpenFile |
|
| tests.go:10:8:10:8 | f | tests.go:46:5:46:76 | extract:0 ... := ... | tests.go:10:8:10:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:46:15:46:76 | call to OpenFile | call to OpenFile |
|
||||||
| tests.go:15:3:15:3 | f | tests.go:32:5:32:78 | ... := ...[0] | tests.go:15:3:15:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:32:15:32:78 | call to OpenFile | call to OpenFile |
|
| tests.go:15:3:15:3 | f | tests.go:32:5:32:78 | extract:0 ... := ... | tests.go:15:3:15:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:32:15:32:78 | call to OpenFile | call to OpenFile |
|
||||||
| tests.go:15:3:15:3 | f | tests.go:46:5:46:76 | ... := ...[0] | tests.go:15:3:15:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:46:15:46:76 | call to OpenFile | call to OpenFile |
|
| tests.go:15:3:15:3 | f | tests.go:46:5:46:76 | extract:0 ... := ... | tests.go:15:3:15:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:46:15:46:76 | call to OpenFile | call to OpenFile |
|
||||||
| tests.go:57:3:57:3 | f | tests.go:55:5:55:78 | ... := ...[0] | tests.go:57:3:57:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:55:15:55:78 | call to OpenFile | call to OpenFile |
|
| tests.go:57:3:57:3 | f | tests.go:55:5:55:78 | extract:0 ... := ... | tests.go:57:3:57:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:55:15:55:78 | call to OpenFile | call to OpenFile |
|
||||||
| tests.go:69:3:69:3 | f | tests.go:67:5:67:76 | ... := ...[0] | tests.go:69:3:69:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:67:15:67:76 | call to OpenFile | call to OpenFile |
|
| tests.go:69:3:69:3 | f | tests.go:67:5:67:76 | extract:0 ... := ... | tests.go:69:3:69:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:67:15:67:76 | call to OpenFile | call to OpenFile |
|
||||||
| tests.go:126:9:126:9 | f | tests.go:124:5:124:78 | ... := ...[0] | tests.go:126:9:126:9 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:124:15:124:78 | call to OpenFile | call to OpenFile |
|
| tests.go:126:9:126:9 | f | tests.go:124:5:124:78 | extract:0 ... := ... | tests.go:126:9:126:9 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:124:15:124:78 | call to OpenFile | call to OpenFile |
|
||||||
| tests.go:145:3:145:3 | f | tests.go:141:5:141:78 | ... := ...[0] | tests.go:145:3:145:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:141:15:141:78 | call to OpenFile | call to OpenFile |
|
| tests.go:145:3:145:3 | f | tests.go:141:5:141:78 | extract:0 ... := ... | tests.go:145:3:145:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:141:15:141:78 | call to OpenFile | call to OpenFile |
|
||||||
| tests.go:166:8:166:8 | f | tests.go:162:2:162:74 | ... := ...[0] | tests.go:166:8:166:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:162:12:162:74 | call to OpenFile | call to OpenFile |
|
| tests.go:166:8:166:8 | f | tests.go:162:2:162:74 | extract:0 ... := ... | tests.go:166:8:166:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:162:12:162:74 | call to OpenFile | call to OpenFile |
|
||||||
edges
|
edges
|
||||||
| tests.go:9:24:9:24 | SSA def(f) | tests.go:10:8:10:8 | f | provenance | |
|
| tests.go:9:36:11:1 | SSA def(f) | tests.go:10:8:10:8 | f | provenance | |
|
||||||
| tests.go:13:32:13:32 | SSA def(f) | tests.go:14:13:16:2 | SSA def(f) | provenance | |
|
| tests.go:13:44:19:1 | SSA def(f) | tests.go:14:13:16:2 | SSA def(f) | provenance | |
|
||||||
| tests.go:14:13:16:2 | SSA def(f) | tests.go:15:3:15:3 | f | provenance | |
|
| tests.go:14:13:16:2 | SSA def(f) | tests.go:15:3:15:3 | f | provenance | |
|
||||||
| tests.go:32:5:32:78 | ... := ...[0] | tests.go:33:21:33:21 | f | provenance | Src:MaD:1 |
|
| tests.go:32:5:32:78 | extract:0 ... := ... | tests.go:33:21:33:21 | f | provenance | Src:MaD:1 |
|
||||||
| tests.go:32:5:32:78 | ... := ...[0] | tests.go:34:29:34:29 | f | provenance | Src:MaD:1 |
|
| tests.go:32:5:32:78 | extract:0 ... := ... | tests.go:34:29:34:29 | f | provenance | Src:MaD:1 |
|
||||||
| tests.go:33:21:33:21 | f | tests.go:9:24:9:24 | SSA def(f) | provenance | |
|
| tests.go:33:21:33:21 | f | tests.go:9:36:11:1 | SSA def(f) | provenance | |
|
||||||
| tests.go:34:29:34:29 | f | tests.go:13:32:13:32 | SSA def(f) | provenance | |
|
| tests.go:34:29:34:29 | f | tests.go:13:44:19:1 | SSA def(f) | provenance | |
|
||||||
| tests.go:46:5:46:76 | ... := ...[0] | tests.go:47:21:47:21 | f | provenance | Src:MaD:1 |
|
| tests.go:46:5:46:76 | extract:0 ... := ... | tests.go:47:21:47:21 | f | provenance | Src:MaD:1 |
|
||||||
| tests.go:46:5:46:76 | ... := ...[0] | tests.go:48:29:48:29 | f | provenance | Src:MaD:1 |
|
| tests.go:46:5:46:76 | extract:0 ... := ... | tests.go:48:29:48:29 | f | provenance | Src:MaD:1 |
|
||||||
| tests.go:47:21:47:21 | f | tests.go:9:24:9:24 | SSA def(f) | provenance | |
|
| tests.go:47:21:47:21 | f | tests.go:9:36:11:1 | SSA def(f) | provenance | |
|
||||||
| tests.go:48:29:48:29 | f | tests.go:13:32:13:32 | SSA def(f) | provenance | |
|
| tests.go:48:29:48:29 | f | tests.go:13:44:19:1 | SSA def(f) | provenance | |
|
||||||
| tests.go:55:5:55:78 | ... := ...[0] | tests.go:57:3:57:3 | f | provenance | Src:MaD:1 |
|
| tests.go:55:5:55:78 | extract:0 ... := ... | tests.go:57:3:57:3 | f | provenance | Src:MaD:1 |
|
||||||
| tests.go:67:5:67:76 | ... := ...[0] | tests.go:69:3:69:3 | f | provenance | Src:MaD:1 |
|
| tests.go:67:5:67:76 | extract:0 ... := ... | tests.go:69:3:69:3 | f | provenance | Src:MaD:1 |
|
||||||
| tests.go:124:5:124:78 | ... := ...[0] | tests.go:126:9:126:9 | f | provenance | Src:MaD:1 |
|
| tests.go:124:5:124:78 | extract:0 ... := ... | tests.go:126:9:126:9 | f | provenance | Src:MaD:1 |
|
||||||
| tests.go:141:5:141:78 | ... := ...[0] | tests.go:145:3:145:3 | f | provenance | Src:MaD:1 |
|
| tests.go:141:5:141:78 | extract:0 ... := ... | tests.go:145:3:145:3 | f | provenance | Src:MaD:1 |
|
||||||
| tests.go:162:2:162:74 | ... := ...[0] | tests.go:166:8:166:8 | f | provenance | Src:MaD:1 |
|
| tests.go:162:2:162:74 | extract:0 ... := ... | tests.go:166:8:166:8 | f | provenance | Src:MaD:1 |
|
||||||
models
|
models
|
||||||
| 1 | Source: os; ; false; OpenFile; ; ; ReturnValue[0]; file; manual |
|
| 1 | Source: os; ; false; OpenFile; ; ; ReturnValue[0]; file; manual |
|
||||||
nodes
|
nodes
|
||||||
| tests.go:9:24:9:24 | SSA def(f) | semmle.label | SSA def(f) |
|
| tests.go:9:36:11:1 | SSA def(f) | semmle.label | SSA def(f) |
|
||||||
| tests.go:10:8:10:8 | f | semmle.label | f |
|
| tests.go:10:8:10:8 | f | semmle.label | f |
|
||||||
| tests.go:13:32:13:32 | SSA def(f) | semmle.label | SSA def(f) |
|
| tests.go:13:44:19:1 | SSA def(f) | semmle.label | SSA def(f) |
|
||||||
| tests.go:14:13:16:2 | SSA def(f) | semmle.label | SSA def(f) |
|
| tests.go:14:13:16:2 | SSA def(f) | semmle.label | SSA def(f) |
|
||||||
| tests.go:15:3:15:3 | f | semmle.label | f |
|
| tests.go:15:3:15:3 | f | semmle.label | f |
|
||||||
| tests.go:32:5:32:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| tests.go:32:5:32:78 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| tests.go:33:21:33:21 | f | semmle.label | f |
|
| tests.go:33:21:33:21 | f | semmle.label | f |
|
||||||
| tests.go:34:29:34:29 | f | semmle.label | f |
|
| tests.go:34:29:34:29 | f | semmle.label | f |
|
||||||
| tests.go:46:5:46:76 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| tests.go:46:5:46:76 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| tests.go:47:21:47:21 | f | semmle.label | f |
|
| tests.go:47:21:47:21 | f | semmle.label | f |
|
||||||
| tests.go:48:29:48:29 | f | semmle.label | f |
|
| tests.go:48:29:48:29 | f | semmle.label | f |
|
||||||
| tests.go:55:5:55:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| tests.go:55:5:55:78 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| tests.go:57:3:57:3 | f | semmle.label | f |
|
| tests.go:57:3:57:3 | f | semmle.label | f |
|
||||||
| tests.go:67:5:67:76 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| tests.go:67:5:67:76 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| tests.go:69:3:69:3 | f | semmle.label | f |
|
| tests.go:69:3:69:3 | f | semmle.label | f |
|
||||||
| tests.go:124:5:124:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| tests.go:124:5:124:78 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| tests.go:126:9:126:9 | f | semmle.label | f |
|
| tests.go:126:9:126:9 | f | semmle.label | f |
|
||||||
| tests.go:141:5:141:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| tests.go:141:5:141:78 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| tests.go:145:3:145:3 | f | semmle.label | f |
|
| tests.go:145:3:145:3 | f | semmle.label | f |
|
||||||
| tests.go:162:2:162:74 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| tests.go:162:2:162:74 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| tests.go:166:8:166:8 | f | semmle.label | f |
|
| tests.go:166:8:166:8 | f | semmle.label | f |
|
||||||
subpaths
|
subpaths
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
| DeadStoreOfField.go:8:2:8:6 | assignment to field val | This assignment to val is useless since its value is never read. |
|
| DeadStoreOfField.go:8:2:8:10 | assign:0 ... = ... | This assignment to val is useless since its value is never read. |
|
||||||
|
|||||||
@@ -5,18 +5,18 @@
|
|||||||
| UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | UnsafeUnzipSymlink.go:112:13:112:20 | linkName | Unresolved path from an archive header, which may point outside the archive root, is used in $@. | UnsafeUnzipSymlink.go:112:13:112:20 | linkName | symlink creation |
|
| UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | UnsafeUnzipSymlink.go:112:13:112:20 | linkName | Unresolved path from an archive header, which may point outside the archive root, is used in $@. | UnsafeUnzipSymlink.go:112:13:112:20 | linkName | symlink creation |
|
||||||
| UnsafeUnzipSymlink.go:126:34:126:44 | selection of Name | UnsafeUnzipSymlink.go:126:34:126:44 | selection of Name | UnsafeUnzipSymlink.go:112:23:112:30 | fileName | Unresolved path from an archive header, which may point outside the archive root, is used in $@. | UnsafeUnzipSymlink.go:112:23:112:30 | fileName | symlink creation |
|
| UnsafeUnzipSymlink.go:126:34:126:44 | selection of Name | UnsafeUnzipSymlink.go:126:34:126:44 | selection of Name | UnsafeUnzipSymlink.go:112:23:112:30 | fileName | Unresolved path from an archive header, which may point outside the archive root, is used in $@. | UnsafeUnzipSymlink.go:112:23:112:30 | fileName | symlink creation |
|
||||||
edges
|
edges
|
||||||
| UnsafeUnzipSymlink.go:111:19:111:26 | SSA def(linkName) | UnsafeUnzipSymlink.go:112:13:112:20 | linkName | provenance | Sink:MaD:1 |
|
| UnsafeUnzipSymlink.go:111:46:113:1 | SSA def(fileName) | UnsafeUnzipSymlink.go:112:23:112:30 | fileName | provenance | Sink:MaD:1 |
|
||||||
| UnsafeUnzipSymlink.go:111:29:111:36 | SSA def(fileName) | UnsafeUnzipSymlink.go:112:23:112:30 | fileName | provenance | Sink:MaD:1 |
|
| UnsafeUnzipSymlink.go:111:46:113:1 | SSA def(linkName) | UnsafeUnzipSymlink.go:112:13:112:20 | linkName | provenance | Sink:MaD:1 |
|
||||||
| UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | UnsafeUnzipSymlink.go:111:19:111:26 | SSA def(linkName) | provenance | |
|
| UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | UnsafeUnzipSymlink.go:111:46:113:1 | SSA def(linkName) | provenance | |
|
||||||
| UnsafeUnzipSymlink.go:126:34:126:44 | selection of Name | UnsafeUnzipSymlink.go:111:29:111:36 | SSA def(fileName) | provenance | |
|
| UnsafeUnzipSymlink.go:126:34:126:44 | selection of Name | UnsafeUnzipSymlink.go:111:46:113:1 | SSA def(fileName) | provenance | |
|
||||||
models
|
models
|
||||||
| 1 | Sink: os; ; false; Symlink; ; ; Argument[0..1]; path-injection; manual |
|
| 1 | Sink: os; ; false; Symlink; ; ; Argument[0..1]; path-injection; manual |
|
||||||
nodes
|
nodes
|
||||||
| UnsafeUnzipSymlink.go:31:15:31:29 | selection of Linkname | semmle.label | selection of Linkname |
|
| UnsafeUnzipSymlink.go:31:15:31:29 | selection of Linkname | semmle.label | selection of Linkname |
|
||||||
| UnsafeUnzipSymlink.go:31:32:31:42 | selection of Name | semmle.label | selection of Name |
|
| UnsafeUnzipSymlink.go:31:32:31:42 | selection of Name | semmle.label | selection of Name |
|
||||||
| UnsafeUnzipSymlink.go:43:25:43:35 | selection of Name | semmle.label | selection of Name |
|
| UnsafeUnzipSymlink.go:43:25:43:35 | selection of Name | semmle.label | selection of Name |
|
||||||
| UnsafeUnzipSymlink.go:111:19:111:26 | SSA def(linkName) | semmle.label | SSA def(linkName) |
|
| UnsafeUnzipSymlink.go:111:46:113:1 | SSA def(fileName) | semmle.label | SSA def(fileName) |
|
||||||
| UnsafeUnzipSymlink.go:111:29:111:36 | SSA def(fileName) | semmle.label | SSA def(fileName) |
|
| UnsafeUnzipSymlink.go:111:46:113:1 | SSA def(linkName) | semmle.label | SSA def(linkName) |
|
||||||
| UnsafeUnzipSymlink.go:112:13:112:20 | linkName | semmle.label | linkName |
|
| UnsafeUnzipSymlink.go:112:13:112:20 | linkName | semmle.label | linkName |
|
||||||
| UnsafeUnzipSymlink.go:112:23:112:30 | fileName | semmle.label | fileName |
|
| UnsafeUnzipSymlink.go:112:23:112:30 | fileName | semmle.label | fileName |
|
||||||
| UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | semmle.label | selection of Linkname |
|
| UnsafeUnzipSymlink.go:126:17:126:31 | selection of Linkname | semmle.label | selection of Linkname |
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
#select
|
#select
|
||||||
| UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | Unsanitized archive entry, which may contain '..', is used in a $@. | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | file system operation |
|
| UnsafeUnzipSymlinkGood.go:72:3:72:25 | extract:0 ... := ... | UnsafeUnzipSymlinkGood.go:72:3:72:25 | extract:0 ... := ... | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | Unsanitized archive entry, which may contain '..', is used in a $@. | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | file system operation |
|
||||||
| ZipSlip.go:11:2:15:2 | range statement[1] | ZipSlip.go:11:2:15:2 | range statement[1] | ZipSlip.go:14:20:14:20 | p | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipSlip.go:14:20:14:20 | p | file system operation |
|
| ZipSlip.go:11:2:15:2 | extract:1 range statement | ZipSlip.go:11:2:15:2 | extract:1 range statement | ZipSlip.go:14:20:14:20 | p | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipSlip.go:14:20:14:20 | p | file system operation |
|
||||||
| tarslip.go:15:2:15:30 | ... := ...[0] | tarslip.go:15:2:15:30 | ... := ...[0] | tarslip.go:16:14:16:34 | call to Dir | Unsanitized archive entry, which may contain '..', is used in a $@. | tarslip.go:16:14:16:34 | call to Dir | file system operation |
|
| tarslip.go:15:2:15:30 | extract:0 ... := ... | tarslip.go:15:2:15:30 | extract:0 ... := ... | tarslip.go:16:14:16:34 | call to Dir | Unsanitized archive entry, which may contain '..', is used in a $@. | tarslip.go:16:14:16:34 | call to Dir | file system operation |
|
||||||
| tst.go:23:2:43:2 | range statement[1] | tst.go:23:2:43:2 | range statement[1] | tst.go:29:20:29:23 | path | Unsanitized archive entry, which may contain '..', is used in a $@. | tst.go:29:20:29:23 | path | file system operation |
|
| tst.go:23:2:43:2 | extract:1 range statement | tst.go:23:2:43:2 | extract:1 range statement | tst.go:29:20:29:23 | path | Unsanitized archive entry, which may contain '..', is used in a $@. | tst.go:29:20:29:23 | path | file system operation |
|
||||||
edges
|
edges
|
||||||
| UnsafeUnzipSymlinkGood.go:52:24:52:32 | SSA def(candidate) | UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | provenance | |
|
| UnsafeUnzipSymlinkGood.go:52:55:67:1 | SSA def(candidate) | UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | provenance | |
|
||||||
| UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | provenance | FunctionModel Sink:MaD:3 |
|
| UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | provenance | FunctionModel Sink:MaD:3 |
|
||||||
| UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | provenance | |
|
| UnsafeUnzipSymlinkGood.go:72:3:72:25 | extract:0 ... := ... | UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | provenance | |
|
||||||
| UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name | provenance | |
|
| UnsafeUnzipSymlinkGood.go:72:3:72:25 | extract:0 ... := ... | UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name | provenance | |
|
||||||
| UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | UnsafeUnzipSymlinkGood.go:52:24:52:32 | SSA def(candidate) | provenance | |
|
| UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | UnsafeUnzipSymlinkGood.go:52:55:67:1 | SSA def(candidate) | provenance | |
|
||||||
| UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name | UnsafeUnzipSymlinkGood.go:52:24:52:32 | SSA def(candidate) | provenance | |
|
| UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name | UnsafeUnzipSymlinkGood.go:52:55:67:1 | SSA def(candidate) | provenance | |
|
||||||
| ZipSlip.go:11:2:15:2 | range statement[1] | ZipSlip.go:12:24:12:29 | selection of Name | provenance | |
|
| ZipSlip.go:11:2:15:2 | extract:1 range statement | ZipSlip.go:12:24:12:29 | selection of Name | provenance | |
|
||||||
| ZipSlip.go:12:3:12:30 | ... := ...[0] | ZipSlip.go:14:20:14:20 | p | provenance | Sink:MaD:1 |
|
| ZipSlip.go:12:3:12:30 | extract:0 ... := ... | ZipSlip.go:14:20:14:20 | p | provenance | Sink:MaD:1 |
|
||||||
| ZipSlip.go:12:24:12:29 | selection of Name | ZipSlip.go:12:3:12:30 | ... := ...[0] | provenance | MaD:4 |
|
| ZipSlip.go:12:24:12:29 | selection of Name | ZipSlip.go:12:3:12:30 | extract:0 ... := ... | provenance | MaD:4 |
|
||||||
| tarslip.go:15:2:15:30 | ... := ...[0] | tarslip.go:16:23:16:33 | selection of Name | provenance | |
|
| tarslip.go:15:2:15:30 | extract:0 ... := ... | tarslip.go:16:23:16:33 | selection of Name | provenance | |
|
||||||
| tarslip.go:16:23:16:33 | selection of Name | tarslip.go:16:14:16:34 | call to Dir | provenance | MaD:5 Sink:MaD:2 |
|
| tarslip.go:16:23:16:33 | selection of Name | tarslip.go:16:14:16:34 | call to Dir | provenance | MaD:5 Sink:MaD:2 |
|
||||||
| tst.go:23:2:43:2 | range statement[1] | tst.go:29:20:29:23 | path | provenance | Sink:MaD:1 |
|
| tst.go:23:2:43:2 | extract:1 range statement | tst.go:29:20:29:23 | path | provenance | Sink:MaD:1 |
|
||||||
models
|
models
|
||||||
| 1 | Sink: io/ioutil; ; false; WriteFile; ; ; Argument[0]; path-injection; manual |
|
| 1 | Sink: io/ioutil; ; false; WriteFile; ; ; Argument[0]; path-injection; manual |
|
||||||
| 2 | Sink: os; ; false; MkdirAll; ; ; Argument[0]; path-injection; manual |
|
| 2 | Sink: os; ; false; MkdirAll; ; ; Argument[0]; path-injection; manual |
|
||||||
@@ -23,19 +23,19 @@ models
|
|||||||
| 4 | Summary: path/filepath; ; false; Abs; ; ; Argument[0]; ReturnValue[0]; taint; manual |
|
| 4 | Summary: path/filepath; ; false; Abs; ; ; Argument[0]; ReturnValue[0]; taint; manual |
|
||||||
| 5 | Summary: path; ; false; Dir; ; ; Argument[0]; ReturnValue; taint; manual |
|
| 5 | Summary: path; ; false; Dir; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||||
nodes
|
nodes
|
||||||
| UnsafeUnzipSymlinkGood.go:52:24:52:32 | SSA def(candidate) | semmle.label | SSA def(candidate) |
|
| UnsafeUnzipSymlinkGood.go:52:55:67:1 | SSA def(candidate) | semmle.label | SSA def(candidate) |
|
||||||
| UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | semmle.label | call to Join |
|
| UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | semmle.label | call to Join |
|
||||||
| UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | semmle.label | candidate |
|
| UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | semmle.label | candidate |
|
||||||
| UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| UnsafeUnzipSymlinkGood.go:72:3:72:25 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | semmle.label | selection of Linkname |
|
| UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | semmle.label | selection of Linkname |
|
||||||
| UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name | semmle.label | selection of Name |
|
| UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name | semmle.label | selection of Name |
|
||||||
| ZipSlip.go:11:2:15:2 | range statement[1] | semmle.label | range statement[1] |
|
| ZipSlip.go:11:2:15:2 | extract:1 range statement | semmle.label | extract:1 range statement |
|
||||||
| ZipSlip.go:12:3:12:30 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| ZipSlip.go:12:3:12:30 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| ZipSlip.go:12:24:12:29 | selection of Name | semmle.label | selection of Name |
|
| ZipSlip.go:12:24:12:29 | selection of Name | semmle.label | selection of Name |
|
||||||
| ZipSlip.go:14:20:14:20 | p | semmle.label | p |
|
| ZipSlip.go:14:20:14:20 | p | semmle.label | p |
|
||||||
| tarslip.go:15:2:15:30 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| tarslip.go:15:2:15:30 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| tarslip.go:16:14:16:34 | call to Dir | semmle.label | call to Dir |
|
| tarslip.go:16:14:16:34 | call to Dir | semmle.label | call to Dir |
|
||||||
| tarslip.go:16:23:16:33 | selection of Name | semmle.label | selection of Name |
|
| tarslip.go:16:23:16:33 | selection of Name | semmle.label | selection of Name |
|
||||||
| tst.go:23:2:43:2 | range statement[1] | semmle.label | range statement[1] |
|
| tst.go:23:2:43:2 | extract:1 range statement | semmle.label | extract:1 range statement |
|
||||||
| tst.go:29:20:29:23 | path | semmle.label | path |
|
| tst.go:29:20:29:23 | path | semmle.label | path |
|
||||||
subpaths
|
subpaths
|
||||||
|
|||||||
@@ -31,16 +31,16 @@ edges
|
|||||||
| SqlInjection.go:11:3:11:17 | call to Query | SqlInjection.go:11:3:11:29 | index expression | provenance | |
|
| SqlInjection.go:11:3:11:17 | call to Query | SqlInjection.go:11:3:11:29 | index expression | provenance | |
|
||||||
| SqlInjection.go:11:3:11:29 | index expression | SqlInjection.go:10:7:11:30 | []type{args} [array] | provenance | |
|
| SqlInjection.go:11:3:11:29 | index expression | SqlInjection.go:10:7:11:30 | []type{args} [array] | provenance | |
|
||||||
| SqlInjection.go:11:3:11:29 | index expression | SqlInjection.go:10:7:11:30 | call to Sprintf | provenance | FunctionModel |
|
| SqlInjection.go:11:3:11:29 | index expression | SqlInjection.go:10:7:11:30 | call to Sprintf | provenance | FunctionModel |
|
||||||
| issue48.go:17:2:17:33 | ... := ...[0] | issue48.go:18:17:18:17 | b | provenance | |
|
| issue48.go:17:2:17:33 | extract:0 ... := ... | issue48.go:18:17:18:17 | b | provenance | |
|
||||||
| issue48.go:17:25:17:32 | selection of Body | issue48.go:17:2:17:33 | ... := ...[0] | provenance | Src:MaD:17 MaD:24 |
|
| issue48.go:17:25:17:32 | selection of Body | issue48.go:17:2:17:33 | extract:0 ... := ... | provenance | Src:MaD:17 MaD:24 |
|
||||||
| issue48.go:18:17:18:17 | b | issue48.go:18:20:18:39 | &... [postupdate] | provenance | MaD:22 |
|
| issue48.go:18:17:18:17 | b | issue48.go:18:20:18:39 | &... [postupdate] | provenance | MaD:22 |
|
||||||
| issue48.go:18:20:18:39 | &... [postupdate] | issue48.go:21:3:21:33 | index expression | provenance | |
|
| issue48.go:18:20:18:39 | &... [postupdate] | issue48.go:21:3:21:33 | index expression | provenance | |
|
||||||
| issue48.go:20:8:21:34 | []type{args} [array] | issue48.go:20:8:21:34 | call to Sprintf | provenance | MaD:23 |
|
| issue48.go:20:8:21:34 | []type{args} [array] | issue48.go:20:8:21:34 | call to Sprintf | provenance | MaD:23 |
|
||||||
| issue48.go:20:8:21:34 | call to Sprintf | issue48.go:22:11:22:12 | q3 | provenance | Sink:MaD:1 |
|
| issue48.go:20:8:21:34 | call to Sprintf | issue48.go:22:11:22:12 | q3 | provenance | Sink:MaD:1 |
|
||||||
| issue48.go:21:3:21:33 | index expression | issue48.go:20:8:21:34 | []type{args} [array] | provenance | |
|
| issue48.go:21:3:21:33 | index expression | issue48.go:20:8:21:34 | []type{args} [array] | provenance | |
|
||||||
| issue48.go:21:3:21:33 | index expression | issue48.go:20:8:21:34 | call to Sprintf | provenance | FunctionModel |
|
| issue48.go:21:3:21:33 | index expression | issue48.go:20:8:21:34 | call to Sprintf | provenance | FunctionModel |
|
||||||
| issue48.go:27:2:27:34 | ... := ...[0] | issue48.go:28:17:28:18 | b2 | provenance | |
|
| issue48.go:27:2:27:34 | extract:0 ... := ... | issue48.go:28:17:28:18 | b2 | provenance | |
|
||||||
| issue48.go:27:26:27:33 | selection of Body | issue48.go:27:2:27:34 | ... := ...[0] | provenance | Src:MaD:17 MaD:24 |
|
| issue48.go:27:26:27:33 | selection of Body | issue48.go:27:2:27:34 | extract:0 ... := ... | provenance | Src:MaD:17 MaD:24 |
|
||||||
| issue48.go:28:17:28:18 | b2 | issue48.go:28:21:28:41 | &... [postupdate] | provenance | MaD:22 |
|
| issue48.go:28:17:28:18 | b2 | issue48.go:28:21:28:41 | &... [postupdate] | provenance | MaD:22 |
|
||||||
| issue48.go:28:21:28:41 | &... [postupdate] | issue48.go:31:3:31:31 | selection of Category | provenance | |
|
| issue48.go:28:21:28:41 | &... [postupdate] | issue48.go:31:3:31:31 | selection of Category | provenance | |
|
||||||
| issue48.go:30:8:31:32 | []type{args} [array] | issue48.go:30:8:31:32 | call to Sprintf | provenance | MaD:23 |
|
| issue48.go:30:8:31:32 | []type{args} [array] | issue48.go:30:8:31:32 | call to Sprintf | provenance | MaD:23 |
|
||||||
@@ -72,19 +72,19 @@ edges
|
|||||||
| main.go:30:13:30:39 | index expression | main.go:28:18:31:2 | struct literal [Category] | provenance | |
|
| main.go:30:13:30:39 | index expression | main.go:28:18:31:2 | struct literal [Category] | provenance | |
|
||||||
| main.go:33:7:34:23 | []type{args} [array] | main.go:33:7:34:23 | call to Sprintf | provenance | MaD:23 |
|
| main.go:33:7:34:23 | []type{args} [array] | main.go:33:7:34:23 | call to Sprintf | provenance | MaD:23 |
|
||||||
| main.go:33:7:34:23 | call to Sprintf | main.go:35:11:35:11 | q | provenance | Sink:MaD:1 |
|
| main.go:33:7:34:23 | call to Sprintf | main.go:35:11:35:11 | q | provenance | Sink:MaD:1 |
|
||||||
| main.go:34:3:34:13 | RequestData [pointer, Category] | main.go:34:3:34:13 | implicit dereference [Category] | provenance | |
|
| main.go:34:3:34:13 | RequestData [pointer, Category] | main.go:34:3:34:13 | implicit-deref RequestData [Category] | provenance | |
|
||||||
| main.go:34:3:34:13 | implicit dereference [Category] | main.go:34:3:34:22 | selection of Category | provenance | |
|
| main.go:34:3:34:13 | implicit-deref RequestData [Category] | main.go:34:3:34:22 | selection of Category | provenance | |
|
||||||
| main.go:34:3:34:22 | selection of Category | main.go:33:7:34:23 | []type{args} [array] | provenance | |
|
| main.go:34:3:34:22 | selection of Category | main.go:33:7:34:23 | []type{args} [array] | provenance | |
|
||||||
| main.go:34:3:34:22 | selection of Category | main.go:33:7:34:23 | call to Sprintf | provenance | FunctionModel |
|
| main.go:34:3:34:22 | selection of Category | main.go:33:7:34:23 | call to Sprintf | provenance | FunctionModel |
|
||||||
| main.go:40:2:40:12 | RequestData [postupdate] [pointer, Category] | main.go:43:3:43:13 | RequestData [pointer, Category] | provenance | |
|
| main.go:40:2:40:12 | RequestData [postupdate] [pointer, Category] | main.go:43:3:43:13 | RequestData [pointer, Category] | provenance | |
|
||||||
| main.go:40:2:40:12 | implicit dereference [postupdate] [Category] | main.go:40:2:40:12 | RequestData [postupdate] [pointer, Category] | provenance | |
|
| main.go:40:2:40:12 | implicit-deref RequestData [postupdate] [Category] | main.go:40:2:40:12 | RequestData [postupdate] [pointer, Category] | provenance | |
|
||||||
| main.go:40:25:40:31 | selection of URL | main.go:40:25:40:39 | call to Query | provenance | Src:MaD:21 MaD:26 |
|
| main.go:40:25:40:31 | selection of URL | main.go:40:25:40:39 | call to Query | provenance | Src:MaD:21 MaD:26 |
|
||||||
| main.go:40:25:40:39 | call to Query | main.go:40:25:40:51 | index expression | provenance | |
|
| main.go:40:25:40:39 | call to Query | main.go:40:25:40:51 | index expression | provenance | |
|
||||||
| main.go:40:25:40:51 | index expression | main.go:40:2:40:12 | implicit dereference [postupdate] [Category] | provenance | |
|
| main.go:40:25:40:51 | index expression | main.go:40:2:40:12 | implicit-deref RequestData [postupdate] [Category] | provenance | |
|
||||||
| main.go:42:7:43:23 | []type{args} [array] | main.go:42:7:43:23 | call to Sprintf | provenance | MaD:23 |
|
| main.go:42:7:43:23 | []type{args} [array] | main.go:42:7:43:23 | call to Sprintf | provenance | MaD:23 |
|
||||||
| main.go:42:7:43:23 | call to Sprintf | main.go:44:11:44:11 | q | provenance | Sink:MaD:1 |
|
| main.go:42:7:43:23 | call to Sprintf | main.go:44:11:44:11 | q | provenance | Sink:MaD:1 |
|
||||||
| main.go:43:3:43:13 | RequestData [pointer, Category] | main.go:43:3:43:13 | implicit dereference [Category] | provenance | |
|
| main.go:43:3:43:13 | RequestData [pointer, Category] | main.go:43:3:43:13 | implicit-deref RequestData [Category] | provenance | |
|
||||||
| main.go:43:3:43:13 | implicit dereference [Category] | main.go:43:3:43:22 | selection of Category | provenance | |
|
| main.go:43:3:43:13 | implicit-deref RequestData [Category] | main.go:43:3:43:22 | selection of Category | provenance | |
|
||||||
| main.go:43:3:43:22 | selection of Category | main.go:42:7:43:23 | []type{args} [array] | provenance | |
|
| main.go:43:3:43:22 | selection of Category | main.go:42:7:43:23 | []type{args} [array] | provenance | |
|
||||||
| main.go:43:3:43:22 | selection of Category | main.go:42:7:43:23 | call to Sprintf | provenance | FunctionModel |
|
| main.go:43:3:43:22 | selection of Category | main.go:42:7:43:23 | call to Sprintf | provenance | FunctionModel |
|
||||||
| main.go:49:3:49:14 | star expression [postupdate] [Category] | main.go:49:4:49:14 | RequestData [postupdate] [pointer, Category] | provenance | |
|
| main.go:49:3:49:14 | star expression [postupdate] [Category] | main.go:49:4:49:14 | RequestData [postupdate] [pointer, Category] | provenance | |
|
||||||
@@ -94,8 +94,8 @@ edges
|
|||||||
| main.go:49:28:49:54 | index expression | main.go:49:3:49:14 | star expression [postupdate] [Category] | provenance | |
|
| main.go:49:28:49:54 | index expression | main.go:49:3:49:14 | star expression [postupdate] [Category] | provenance | |
|
||||||
| main.go:51:7:52:23 | []type{args} [array] | main.go:51:7:52:23 | call to Sprintf | provenance | MaD:23 |
|
| main.go:51:7:52:23 | []type{args} [array] | main.go:51:7:52:23 | call to Sprintf | provenance | MaD:23 |
|
||||||
| main.go:51:7:52:23 | call to Sprintf | main.go:53:11:53:11 | q | provenance | Sink:MaD:1 |
|
| main.go:51:7:52:23 | call to Sprintf | main.go:53:11:53:11 | q | provenance | Sink:MaD:1 |
|
||||||
| main.go:52:3:52:13 | RequestData [pointer, Category] | main.go:52:3:52:13 | implicit dereference [Category] | provenance | |
|
| main.go:52:3:52:13 | RequestData [pointer, Category] | main.go:52:3:52:13 | implicit-deref RequestData [Category] | provenance | |
|
||||||
| main.go:52:3:52:13 | implicit dereference [Category] | main.go:52:3:52:22 | selection of Category | provenance | |
|
| main.go:52:3:52:13 | implicit-deref RequestData [Category] | main.go:52:3:52:22 | selection of Category | provenance | |
|
||||||
| main.go:52:3:52:22 | selection of Category | main.go:51:7:52:23 | []type{args} [array] | provenance | |
|
| main.go:52:3:52:22 | selection of Category | main.go:51:7:52:23 | []type{args} [array] | provenance | |
|
||||||
| main.go:52:3:52:22 | selection of Category | main.go:51:7:52:23 | call to Sprintf | provenance | FunctionModel |
|
| main.go:52:3:52:22 | selection of Category | main.go:51:7:52:23 | call to Sprintf | provenance | FunctionModel |
|
||||||
| main.go:58:3:58:14 | star expression [postupdate] [Category] | main.go:58:4:58:14 | RequestData [postupdate] [pointer, Category] | provenance | |
|
| main.go:58:3:58:14 | star expression [postupdate] [Category] | main.go:58:4:58:14 | RequestData [postupdate] [pointer, Category] | provenance | |
|
||||||
@@ -161,7 +161,7 @@ nodes
|
|||||||
| SqlInjection.go:11:3:11:17 | call to Query | semmle.label | call to Query |
|
| SqlInjection.go:11:3:11:17 | call to Query | semmle.label | call to Query |
|
||||||
| SqlInjection.go:11:3:11:29 | index expression | semmle.label | index expression |
|
| SqlInjection.go:11:3:11:29 | index expression | semmle.label | index expression |
|
||||||
| SqlInjection.go:12:11:12:11 | q | semmle.label | q |
|
| SqlInjection.go:12:11:12:11 | q | semmle.label | q |
|
||||||
| issue48.go:17:2:17:33 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| issue48.go:17:2:17:33 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| issue48.go:17:25:17:32 | selection of Body | semmle.label | selection of Body |
|
| issue48.go:17:25:17:32 | selection of Body | semmle.label | selection of Body |
|
||||||
| issue48.go:18:17:18:17 | b | semmle.label | b |
|
| issue48.go:18:17:18:17 | b | semmle.label | b |
|
||||||
| issue48.go:18:20:18:39 | &... [postupdate] | semmle.label | &... [postupdate] |
|
| issue48.go:18:20:18:39 | &... [postupdate] | semmle.label | &... [postupdate] |
|
||||||
@@ -169,7 +169,7 @@ nodes
|
|||||||
| issue48.go:20:8:21:34 | call to Sprintf | semmle.label | call to Sprintf |
|
| issue48.go:20:8:21:34 | call to Sprintf | semmle.label | call to Sprintf |
|
||||||
| issue48.go:21:3:21:33 | index expression | semmle.label | index expression |
|
| issue48.go:21:3:21:33 | index expression | semmle.label | index expression |
|
||||||
| issue48.go:22:11:22:12 | q3 | semmle.label | q3 |
|
| issue48.go:22:11:22:12 | q3 | semmle.label | q3 |
|
||||||
| issue48.go:27:2:27:34 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| issue48.go:27:2:27:34 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| issue48.go:27:26:27:33 | selection of Body | semmle.label | selection of Body |
|
| issue48.go:27:26:27:33 | selection of Body | semmle.label | selection of Body |
|
||||||
| issue48.go:28:17:28:18 | b2 | semmle.label | b2 |
|
| issue48.go:28:17:28:18 | b2 | semmle.label | b2 |
|
||||||
| issue48.go:28:21:28:41 | &... [postupdate] | semmle.label | &... [postupdate] |
|
| issue48.go:28:21:28:41 | &... [postupdate] | semmle.label | &... [postupdate] |
|
||||||
@@ -204,18 +204,18 @@ nodes
|
|||||||
| main.go:33:7:34:23 | []type{args} [array] | semmle.label | []type{args} [array] |
|
| main.go:33:7:34:23 | []type{args} [array] | semmle.label | []type{args} [array] |
|
||||||
| main.go:33:7:34:23 | call to Sprintf | semmle.label | call to Sprintf |
|
| main.go:33:7:34:23 | call to Sprintf | semmle.label | call to Sprintf |
|
||||||
| main.go:34:3:34:13 | RequestData [pointer, Category] | semmle.label | RequestData [pointer, Category] |
|
| main.go:34:3:34:13 | RequestData [pointer, Category] | semmle.label | RequestData [pointer, Category] |
|
||||||
| main.go:34:3:34:13 | implicit dereference [Category] | semmle.label | implicit dereference [Category] |
|
| main.go:34:3:34:13 | implicit-deref RequestData [Category] | semmle.label | implicit-deref RequestData [Category] |
|
||||||
| main.go:34:3:34:22 | selection of Category | semmle.label | selection of Category |
|
| main.go:34:3:34:22 | selection of Category | semmle.label | selection of Category |
|
||||||
| main.go:35:11:35:11 | q | semmle.label | q |
|
| main.go:35:11:35:11 | q | semmle.label | q |
|
||||||
| main.go:40:2:40:12 | RequestData [postupdate] [pointer, Category] | semmle.label | RequestData [postupdate] [pointer, Category] |
|
| main.go:40:2:40:12 | RequestData [postupdate] [pointer, Category] | semmle.label | RequestData [postupdate] [pointer, Category] |
|
||||||
| main.go:40:2:40:12 | implicit dereference [postupdate] [Category] | semmle.label | implicit dereference [postupdate] [Category] |
|
| main.go:40:2:40:12 | implicit-deref RequestData [postupdate] [Category] | semmle.label | implicit-deref RequestData [postupdate] [Category] |
|
||||||
| main.go:40:25:40:31 | selection of URL | semmle.label | selection of URL |
|
| main.go:40:25:40:31 | selection of URL | semmle.label | selection of URL |
|
||||||
| main.go:40:25:40:39 | call to Query | semmle.label | call to Query |
|
| main.go:40:25:40:39 | call to Query | semmle.label | call to Query |
|
||||||
| main.go:40:25:40:51 | index expression | semmle.label | index expression |
|
| main.go:40:25:40:51 | index expression | semmle.label | index expression |
|
||||||
| main.go:42:7:43:23 | []type{args} [array] | semmle.label | []type{args} [array] |
|
| main.go:42:7:43:23 | []type{args} [array] | semmle.label | []type{args} [array] |
|
||||||
| main.go:42:7:43:23 | call to Sprintf | semmle.label | call to Sprintf |
|
| main.go:42:7:43:23 | call to Sprintf | semmle.label | call to Sprintf |
|
||||||
| main.go:43:3:43:13 | RequestData [pointer, Category] | semmle.label | RequestData [pointer, Category] |
|
| main.go:43:3:43:13 | RequestData [pointer, Category] | semmle.label | RequestData [pointer, Category] |
|
||||||
| main.go:43:3:43:13 | implicit dereference [Category] | semmle.label | implicit dereference [Category] |
|
| main.go:43:3:43:13 | implicit-deref RequestData [Category] | semmle.label | implicit-deref RequestData [Category] |
|
||||||
| main.go:43:3:43:22 | selection of Category | semmle.label | selection of Category |
|
| main.go:43:3:43:22 | selection of Category | semmle.label | selection of Category |
|
||||||
| main.go:44:11:44:11 | q | semmle.label | q |
|
| main.go:44:11:44:11 | q | semmle.label | q |
|
||||||
| main.go:49:3:49:14 | star expression [postupdate] [Category] | semmle.label | star expression [postupdate] [Category] |
|
| main.go:49:3:49:14 | star expression [postupdate] [Category] | semmle.label | star expression [postupdate] [Category] |
|
||||||
@@ -226,7 +226,7 @@ nodes
|
|||||||
| main.go:51:7:52:23 | []type{args} [array] | semmle.label | []type{args} [array] |
|
| main.go:51:7:52:23 | []type{args} [array] | semmle.label | []type{args} [array] |
|
||||||
| main.go:51:7:52:23 | call to Sprintf | semmle.label | call to Sprintf |
|
| main.go:51:7:52:23 | call to Sprintf | semmle.label | call to Sprintf |
|
||||||
| main.go:52:3:52:13 | RequestData [pointer, Category] | semmle.label | RequestData [pointer, Category] |
|
| main.go:52:3:52:13 | RequestData [pointer, Category] | semmle.label | RequestData [pointer, Category] |
|
||||||
| main.go:52:3:52:13 | implicit dereference [Category] | semmle.label | implicit dereference [Category] |
|
| main.go:52:3:52:13 | implicit-deref RequestData [Category] | semmle.label | implicit-deref RequestData [Category] |
|
||||||
| main.go:52:3:52:22 | selection of Category | semmle.label | selection of Category |
|
| main.go:52:3:52:22 | selection of Category | semmle.label | selection of Category |
|
||||||
| main.go:53:11:53:11 | q | semmle.label | q |
|
| main.go:53:11:53:11 | q | semmle.label | q |
|
||||||
| main.go:58:3:58:14 | star expression [postupdate] [Category] | semmle.label | star expression [postupdate] [Category] |
|
| main.go:58:3:58:14 | star expression [postupdate] [Category] | semmle.label | star expression [postupdate] [Category] |
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
#select
|
#select
|
||||||
| StringBreak.go:15:47:15:57 | versionJSON | StringBreak.go:11:2:11:40 | ... := ...[0] | StringBreak.go:15:47:15:57 | versionJSON | If this $@ contains a single quote, it could break out of the enclosing quotes. | StringBreak.go:11:2:11:40 | ... := ...[0] | JSON value |
|
| StringBreak.go:15:47:15:57 | versionJSON | StringBreak.go:11:2:11:40 | extract:0 ... := ... | StringBreak.go:15:47:15:57 | versionJSON | If this $@ contains a single quote, it could break out of the enclosing quotes. | StringBreak.go:11:2:11:40 | extract:0 ... := ... | JSON value |
|
||||||
| StringBreakMismatched.go:18:26:18:32 | escaped | StringBreakMismatched.go:13:2:13:40 | ... := ...[0] | StringBreakMismatched.go:18:26:18:32 | escaped | If this $@ contains a single quote, it could break out of the enclosing quotes. | StringBreakMismatched.go:13:2:13:40 | ... := ...[0] | JSON value |
|
| StringBreakMismatched.go:18:26:18:32 | escaped | StringBreakMismatched.go:13:2:13:40 | extract:0 ... := ... | StringBreakMismatched.go:18:26:18:32 | escaped | If this $@ contains a single quote, it could break out of the enclosing quotes. | StringBreakMismatched.go:13:2:13:40 | extract:0 ... := ... | JSON value |
|
||||||
| StringBreakMismatched.go:30:27:30:33 | escaped | StringBreakMismatched.go:25:2:25:40 | ... := ...[0] | StringBreakMismatched.go:30:27:30:33 | escaped | If this $@ contains a double quote, it could break out of the enclosing quotes. | StringBreakMismatched.go:25:2:25:40 | ... := ...[0] | JSON value |
|
| StringBreakMismatched.go:30:27:30:33 | escaped | StringBreakMismatched.go:25:2:25:40 | extract:0 ... := ... | StringBreakMismatched.go:30:27:30:33 | escaped | If this $@ contains a double quote, it could break out of the enclosing quotes. | StringBreakMismatched.go:25:2:25:40 | extract:0 ... := ... | JSON value |
|
||||||
edges
|
edges
|
||||||
| StringBreak.go:11:2:11:40 | ... := ...[0] | StringBreak.go:15:47:15:57 | versionJSON | provenance | |
|
| StringBreak.go:11:2:11:40 | extract:0 ... := ... | StringBreak.go:15:47:15:57 | versionJSON | provenance | |
|
||||||
| StringBreakMismatched.go:13:2:13:40 | ... := ...[0] | StringBreakMismatched.go:14:29:14:47 | type conversion | provenance | |
|
| StringBreakMismatched.go:13:2:13:40 | extract:0 ... := ... | StringBreakMismatched.go:14:29:14:47 | type conversion | provenance | |
|
||||||
| StringBreakMismatched.go:14:13:14:62 | call to Replace | StringBreakMismatched.go:18:26:18:32 | escaped | provenance | |
|
| StringBreakMismatched.go:14:13:14:62 | call to Replace | StringBreakMismatched.go:18:26:18:32 | escaped | provenance | |
|
||||||
| StringBreakMismatched.go:14:29:14:47 | type conversion | StringBreakMismatched.go:14:13:14:62 | call to Replace | provenance | MaD:1 |
|
| StringBreakMismatched.go:14:29:14:47 | type conversion | StringBreakMismatched.go:14:13:14:62 | call to Replace | provenance | MaD:1 |
|
||||||
| StringBreakMismatched.go:25:2:25:40 | ... := ...[0] | StringBreakMismatched.go:26:29:26:47 | type conversion | provenance | |
|
| StringBreakMismatched.go:25:2:25:40 | extract:0 ... := ... | StringBreakMismatched.go:26:29:26:47 | type conversion | provenance | |
|
||||||
| StringBreakMismatched.go:26:13:26:61 | call to Replace | StringBreakMismatched.go:30:27:30:33 | escaped | provenance | |
|
| StringBreakMismatched.go:26:13:26:61 | call to Replace | StringBreakMismatched.go:30:27:30:33 | escaped | provenance | |
|
||||||
| StringBreakMismatched.go:26:29:26:47 | type conversion | StringBreakMismatched.go:26:13:26:61 | call to Replace | provenance | MaD:1 |
|
| StringBreakMismatched.go:26:29:26:47 | type conversion | StringBreakMismatched.go:26:13:26:61 | call to Replace | provenance | MaD:1 |
|
||||||
models
|
models
|
||||||
| 1 | Summary: strings; ; false; Replace; ; ; Argument[0]; ReturnValue; taint; manual |
|
| 1 | Summary: strings; ; false; Replace; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||||
nodes
|
nodes
|
||||||
| StringBreak.go:11:2:11:40 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| StringBreak.go:11:2:11:40 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| StringBreak.go:15:47:15:57 | versionJSON | semmle.label | versionJSON |
|
| StringBreak.go:15:47:15:57 | versionJSON | semmle.label | versionJSON |
|
||||||
| StringBreakMismatched.go:13:2:13:40 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| StringBreakMismatched.go:13:2:13:40 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| StringBreakMismatched.go:14:13:14:62 | call to Replace | semmle.label | call to Replace |
|
| StringBreakMismatched.go:14:13:14:62 | call to Replace | semmle.label | call to Replace |
|
||||||
| StringBreakMismatched.go:14:29:14:47 | type conversion | semmle.label | type conversion |
|
| StringBreakMismatched.go:14:29:14:47 | type conversion | semmle.label | type conversion |
|
||||||
| StringBreakMismatched.go:18:26:18:32 | escaped | semmle.label | escaped |
|
| StringBreakMismatched.go:18:26:18:32 | escaped | semmle.label | escaped |
|
||||||
| StringBreakMismatched.go:25:2:25:40 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| StringBreakMismatched.go:25:2:25:40 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| StringBreakMismatched.go:26:13:26:61 | call to Replace | semmle.label | call to Replace |
|
| StringBreakMismatched.go:26:13:26:61 | call to Replace | semmle.label | call to Replace |
|
||||||
| StringBreakMismatched.go:26:29:26:47 | type conversion | semmle.label | type conversion |
|
| StringBreakMismatched.go:26:29:26:47 | type conversion | semmle.label | type conversion |
|
||||||
| StringBreakMismatched.go:30:27:30:33 | escaped | semmle.label | escaped |
|
| StringBreakMismatched.go:30:27:30:33 | escaped | semmle.label | escaped |
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
#select
|
#select
|
||||||
| AllocationSizeOverflow.go:10:10:10:22 | call to len | AllocationSizeOverflow.go:6:2:6:33 | ... := ...[0] | AllocationSizeOverflow.go:10:10:10:22 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | AllocationSizeOverflow.go:11:25:11:28 | size | allocation | AllocationSizeOverflow.go:6:2:6:33 | ... := ...[0] | potentially large value |
|
| AllocationSizeOverflow.go:10:10:10:22 | call to len | AllocationSizeOverflow.go:6:2:6:33 | extract:0 ... := ... | AllocationSizeOverflow.go:10:10:10:22 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | AllocationSizeOverflow.go:11:25:11:28 | size | allocation | AllocationSizeOverflow.go:6:2:6:33 | extract:0 ... := ... | potentially large value |
|
||||||
| tst2.go:10:22:10:30 | call to len | tst2.go:9:2:9:37 | ... := ...[0] | tst2.go:10:22:10:30 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst2.go:10:22:10:32 | ...+... | allocation | tst2.go:9:2:9:37 | ... := ...[0] | potentially large value |
|
| tst2.go:10:22:10:30 | call to len | tst2.go:9:2:9:37 | extract:0 ... := ... | tst2.go:10:22:10:30 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst2.go:10:22:10:32 | ...+... | allocation | tst2.go:9:2:9:37 | extract:0 ... := ... | potentially large value |
|
||||||
| tst2.go:15:22:15:30 | call to len | tst2.go:14:2:14:29 | ... := ...[0] | tst2.go:15:22:15:30 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst2.go:15:22:15:32 | ...+... | allocation | tst2.go:14:2:14:29 | ... := ...[0] | potentially large value |
|
| tst2.go:15:22:15:30 | call to len | tst2.go:14:2:14:29 | extract:0 ... := ... | tst2.go:15:22:15:30 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst2.go:15:22:15:32 | ...+... | allocation | tst2.go:14:2:14:29 | extract:0 ... := ... | potentially large value |
|
||||||
| tst3.go:7:22:7:34 | call to len | tst3.go:6:2:6:31 | ... := ...[0] | tst3.go:7:22:7:34 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst3.go:7:22:7:36 | ...+... | allocation | tst3.go:6:2:6:31 | ... := ...[0] | potentially large value |
|
| tst3.go:7:22:7:34 | call to len | tst3.go:6:2:6:31 | extract:0 ... := ... | tst3.go:7:22:7:34 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst3.go:7:22:7:36 | ...+... | allocation | tst3.go:6:2:6:31 | extract:0 ... := ... | potentially large value |
|
||||||
| tst3.go:24:16:24:28 | call to len | tst3.go:6:2:6:31 | ... := ...[0] | tst3.go:24:16:24:28 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst3.go:27:24:27:32 | newlength | allocation | tst3.go:6:2:6:31 | ... := ...[0] | potentially large value |
|
| tst3.go:24:16:24:28 | call to len | tst3.go:6:2:6:31 | extract:0 ... := ... | tst3.go:24:16:24:28 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst3.go:27:24:27:32 | newlength | allocation | tst3.go:6:2:6:31 | extract:0 ... := ... | potentially large value |
|
||||||
| tst3.go:32:16:32:28 | call to len | tst3.go:6:2:6:31 | ... := ...[0] | tst3.go:32:16:32:28 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst3.go:36:23:36:31 | newlength | allocation | tst3.go:6:2:6:31 | ... := ...[0] | potentially large value |
|
| tst3.go:32:16:32:28 | call to len | tst3.go:6:2:6:31 | extract:0 ... := ... | tst3.go:32:16:32:28 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst3.go:36:23:36:31 | newlength | allocation | tst3.go:6:2:6:31 | extract:0 ... := ... | potentially large value |
|
||||||
| tst.go:15:22:15:34 | call to len | tst.go:14:2:14:30 | ... = ...[0] | tst.go:15:22:15:34 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst.go:15:22:15:36 | ...+... | allocation | tst.go:14:2:14:30 | ... = ...[0] | potentially large value |
|
| tst.go:15:22:15:34 | call to len | tst.go:14:2:14:30 | extract:0 ... = ... | tst.go:15:22:15:34 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst.go:15:22:15:36 | ...+... | allocation | tst.go:14:2:14:30 | extract:0 ... = ... | potentially large value |
|
||||||
| tst.go:21:22:21:34 | call to len | tst.go:20:2:20:31 | ... = ...[0] | tst.go:21:22:21:34 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst.go:21:22:21:36 | ...+... | allocation | tst.go:20:2:20:31 | ... = ...[0] | potentially large value |
|
| tst.go:21:22:21:34 | call to len | tst.go:20:2:20:31 | extract:0 ... = ... | tst.go:21:22:21:34 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst.go:21:22:21:36 | ...+... | allocation | tst.go:20:2:20:31 | extract:0 ... = ... | potentially large value |
|
||||||
| tst.go:27:26:27:38 | call to len | tst.go:26:2:26:31 | ... = ...[0] | tst.go:27:26:27:38 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst.go:27:26:27:40 | ...+... | allocation | tst.go:26:2:26:31 | ... = ...[0] | potentially large value |
|
| tst.go:27:26:27:38 | call to len | tst.go:26:2:26:31 | extract:0 ... = ... | tst.go:27:26:27:38 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst.go:27:26:27:40 | ...+... | allocation | tst.go:26:2:26:31 | extract:0 ... = ... | potentially large value |
|
||||||
| tst.go:35:22:35:34 | call to len | tst.go:34:2:34:30 | ... = ...[0] | tst.go:35:22:35:34 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst.go:35:22:35:36 | ...+... | allocation | tst.go:34:2:34:30 | ... = ...[0] | potentially large value |
|
| tst.go:35:22:35:34 | call to len | tst.go:34:2:34:30 | extract:0 ... = ... | tst.go:35:22:35:34 | call to len | This operation, which is used in an $@, involves a $@ and might overflow. | tst.go:35:22:35:36 | ...+... | allocation | tst.go:34:2:34:30 | extract:0 ... = ... | potentially large value |
|
||||||
edges
|
edges
|
||||||
| AllocationSizeOverflow.go:6:2:6:33 | ... := ...[0] | AllocationSizeOverflow.go:10:14:10:21 | jsonData | provenance | |
|
| AllocationSizeOverflow.go:6:2:6:33 | extract:0 ... := ... | AllocationSizeOverflow.go:10:14:10:21 | jsonData | provenance | |
|
||||||
| AllocationSizeOverflow.go:10:14:10:21 | jsonData | AllocationSizeOverflow.go:10:10:10:22 | call to len | provenance | Config |
|
| AllocationSizeOverflow.go:10:14:10:21 | jsonData | AllocationSizeOverflow.go:10:10:10:22 | call to len | provenance | Config |
|
||||||
| tst2.go:9:2:9:37 | ... := ...[0] | tst2.go:10:26:10:29 | data | provenance | Src:MaD:1 |
|
| tst2.go:9:2:9:37 | extract:0 ... := ... | tst2.go:10:26:10:29 | data | provenance | Src:MaD:1 |
|
||||||
| tst2.go:10:26:10:29 | data | tst2.go:10:22:10:30 | call to len | provenance | Config |
|
| tst2.go:10:26:10:29 | data | tst2.go:10:22:10:30 | call to len | provenance | Config |
|
||||||
| tst2.go:14:2:14:29 | ... := ...[0] | tst2.go:15:26:15:29 | data | provenance | |
|
| tst2.go:14:2:14:29 | extract:0 ... := ... | tst2.go:15:26:15:29 | data | provenance | |
|
||||||
| tst2.go:15:26:15:29 | data | tst2.go:15:22:15:30 | call to len | provenance | Config |
|
| tst2.go:15:26:15:29 | data | tst2.go:15:22:15:30 | call to len | provenance | Config |
|
||||||
| tst3.go:6:2:6:31 | ... := ...[0] | tst3.go:7:26:7:33 | jsonData | provenance | |
|
| tst3.go:6:2:6:31 | extract:0 ... := ... | tst3.go:7:26:7:33 | jsonData | provenance | |
|
||||||
| tst3.go:7:26:7:33 | jsonData | tst3.go:7:22:7:34 | call to len | provenance | Config |
|
| tst3.go:7:26:7:33 | jsonData | tst3.go:7:22:7:34 | call to len | provenance | Config |
|
||||||
| tst3.go:7:26:7:33 | jsonData | tst3.go:9:32:9:39 | jsonData | provenance | |
|
| tst3.go:7:26:7:33 | jsonData | tst3.go:9:32:9:39 | jsonData | provenance | |
|
||||||
| tst3.go:9:32:9:39 | jsonData | tst3.go:11:9:11:16 | jsonData | provenance | |
|
| tst3.go:9:32:9:39 | jsonData | tst3.go:11:9:11:16 | jsonData | provenance | |
|
||||||
@@ -25,27 +25,27 @@ edges
|
|||||||
| tst3.go:24:20:24:27 | jsonData | tst3.go:24:16:24:28 | call to len | provenance | Config |
|
| tst3.go:24:20:24:27 | jsonData | tst3.go:24:16:24:28 | call to len | provenance | Config |
|
||||||
| tst3.go:24:20:24:27 | jsonData | tst3.go:32:20:32:27 | jsonData | provenance | |
|
| tst3.go:24:20:24:27 | jsonData | tst3.go:32:20:32:27 | jsonData | provenance | |
|
||||||
| tst3.go:32:20:32:27 | jsonData | tst3.go:32:16:32:28 | call to len | provenance | Config |
|
| tst3.go:32:20:32:27 | jsonData | tst3.go:32:16:32:28 | call to len | provenance | Config |
|
||||||
| tst.go:14:2:14:30 | ... = ...[0] | tst.go:15:26:15:33 | jsonData | provenance | |
|
| tst.go:14:2:14:30 | extract:0 ... = ... | tst.go:15:26:15:33 | jsonData | provenance | |
|
||||||
| tst.go:15:26:15:33 | jsonData | tst.go:15:22:15:34 | call to len | provenance | Config |
|
| tst.go:15:26:15:33 | jsonData | tst.go:15:22:15:34 | call to len | provenance | Config |
|
||||||
| tst.go:20:2:20:31 | ... = ...[0] | tst.go:21:26:21:33 | jsonData | provenance | |
|
| tst.go:20:2:20:31 | extract:0 ... = ... | tst.go:21:26:21:33 | jsonData | provenance | |
|
||||||
| tst.go:21:26:21:33 | jsonData | tst.go:21:22:21:34 | call to len | provenance | Config |
|
| tst.go:21:26:21:33 | jsonData | tst.go:21:22:21:34 | call to len | provenance | Config |
|
||||||
| tst.go:26:2:26:31 | ... = ...[0] | tst.go:27:30:27:37 | jsonData | provenance | |
|
| tst.go:26:2:26:31 | extract:0 ... = ... | tst.go:27:30:27:37 | jsonData | provenance | |
|
||||||
| tst.go:27:30:27:37 | jsonData | tst.go:27:26:27:38 | call to len | provenance | Config |
|
| tst.go:27:30:27:37 | jsonData | tst.go:27:26:27:38 | call to len | provenance | Config |
|
||||||
| tst.go:34:2:34:30 | ... = ...[0] | tst.go:35:26:35:33 | jsonData | provenance | |
|
| tst.go:34:2:34:30 | extract:0 ... = ... | tst.go:35:26:35:33 | jsonData | provenance | |
|
||||||
| tst.go:35:26:35:33 | jsonData | tst.go:35:22:35:34 | call to len | provenance | Config |
|
| tst.go:35:26:35:33 | jsonData | tst.go:35:22:35:34 | call to len | provenance | Config |
|
||||||
models
|
models
|
||||||
| 1 | Source: io/ioutil; ; false; ReadFile; ; ; ReturnValue[0]; file; manual |
|
| 1 | Source: io/ioutil; ; false; ReadFile; ; ; ReturnValue[0]; file; manual |
|
||||||
nodes
|
nodes
|
||||||
| AllocationSizeOverflow.go:6:2:6:33 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| AllocationSizeOverflow.go:6:2:6:33 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| AllocationSizeOverflow.go:10:10:10:22 | call to len | semmle.label | call to len |
|
| AllocationSizeOverflow.go:10:10:10:22 | call to len | semmle.label | call to len |
|
||||||
| AllocationSizeOverflow.go:10:14:10:21 | jsonData | semmle.label | jsonData |
|
| AllocationSizeOverflow.go:10:14:10:21 | jsonData | semmle.label | jsonData |
|
||||||
| tst2.go:9:2:9:37 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| tst2.go:9:2:9:37 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| tst2.go:10:22:10:30 | call to len | semmle.label | call to len |
|
| tst2.go:10:22:10:30 | call to len | semmle.label | call to len |
|
||||||
| tst2.go:10:26:10:29 | data | semmle.label | data |
|
| tst2.go:10:26:10:29 | data | semmle.label | data |
|
||||||
| tst2.go:14:2:14:29 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| tst2.go:14:2:14:29 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| tst2.go:15:22:15:30 | call to len | semmle.label | call to len |
|
| tst2.go:15:22:15:30 | call to len | semmle.label | call to len |
|
||||||
| tst2.go:15:26:15:29 | data | semmle.label | data |
|
| tst2.go:15:26:15:29 | data | semmle.label | data |
|
||||||
| tst3.go:6:2:6:31 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| tst3.go:6:2:6:31 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| tst3.go:7:22:7:34 | call to len | semmle.label | call to len |
|
| tst3.go:7:22:7:34 | call to len | semmle.label | call to len |
|
||||||
| tst3.go:7:26:7:33 | jsonData | semmle.label | jsonData |
|
| tst3.go:7:26:7:33 | jsonData | semmle.label | jsonData |
|
||||||
| tst3.go:9:32:9:39 | jsonData | semmle.label | jsonData |
|
| tst3.go:9:32:9:39 | jsonData | semmle.label | jsonData |
|
||||||
@@ -55,16 +55,16 @@ nodes
|
|||||||
| tst3.go:24:20:24:27 | jsonData | semmle.label | jsonData |
|
| tst3.go:24:20:24:27 | jsonData | semmle.label | jsonData |
|
||||||
| tst3.go:32:16:32:28 | call to len | semmle.label | call to len |
|
| tst3.go:32:16:32:28 | call to len | semmle.label | call to len |
|
||||||
| tst3.go:32:20:32:27 | jsonData | semmle.label | jsonData |
|
| tst3.go:32:20:32:27 | jsonData | semmle.label | jsonData |
|
||||||
| tst.go:14:2:14:30 | ... = ...[0] | semmle.label | ... = ...[0] |
|
| tst.go:14:2:14:30 | extract:0 ... = ... | semmle.label | extract:0 ... = ... |
|
||||||
| tst.go:15:22:15:34 | call to len | semmle.label | call to len |
|
| tst.go:15:22:15:34 | call to len | semmle.label | call to len |
|
||||||
| tst.go:15:26:15:33 | jsonData | semmle.label | jsonData |
|
| tst.go:15:26:15:33 | jsonData | semmle.label | jsonData |
|
||||||
| tst.go:20:2:20:31 | ... = ...[0] | semmle.label | ... = ...[0] |
|
| tst.go:20:2:20:31 | extract:0 ... = ... | semmle.label | extract:0 ... = ... |
|
||||||
| tst.go:21:22:21:34 | call to len | semmle.label | call to len |
|
| tst.go:21:22:21:34 | call to len | semmle.label | call to len |
|
||||||
| tst.go:21:26:21:33 | jsonData | semmle.label | jsonData |
|
| tst.go:21:26:21:33 | jsonData | semmle.label | jsonData |
|
||||||
| tst.go:26:2:26:31 | ... = ...[0] | semmle.label | ... = ...[0] |
|
| tst.go:26:2:26:31 | extract:0 ... = ... | semmle.label | extract:0 ... = ... |
|
||||||
| tst.go:27:26:27:38 | call to len | semmle.label | call to len |
|
| tst.go:27:26:27:38 | call to len | semmle.label | call to len |
|
||||||
| tst.go:27:30:27:37 | jsonData | semmle.label | jsonData |
|
| tst.go:27:30:27:37 | jsonData | semmle.label | jsonData |
|
||||||
| tst.go:34:2:34:30 | ... = ...[0] | semmle.label | ... = ...[0] |
|
| tst.go:34:2:34:30 | extract:0 ... = ... | semmle.label | extract:0 ... = ... |
|
||||||
| tst.go:35:22:35:34 | call to len | semmle.label | call to len |
|
| tst.go:35:22:35:34 | call to len | semmle.label | call to len |
|
||||||
| tst.go:35:26:35:33 | jsonData | semmle.label | jsonData |
|
| tst.go:35:26:35:33 | jsonData | semmle.label | jsonData |
|
||||||
subpaths
|
subpaths
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
| DisabledCertificateCheck.go:10:32:10:55 | init of key-value pair | InsecureSkipVerify should not be used in production code. |
|
| DisabledCertificateCheck.go:10:32:10:55 | lit-init key-value pair | InsecureSkipVerify should not be used in production code. |
|
||||||
| main.go:9:2:9:23 | assignment to field InsecureSkipVerify | InsecureSkipVerify should not be used in production code. |
|
| main.go:9:2:9:30 | assign:0 ... = ... | InsecureSkipVerify should not be used in production code. |
|
||||||
| main.go:57:21:57:44 | init of key-value pair | InsecureSkipVerify should not be used in production code. |
|
| main.go:57:21:57:44 | lit-init key-value pair | InsecureSkipVerify should not be used in production code. |
|
||||||
| main.go:62:32:62:55 | init of key-value pair | InsecureSkipVerify should not be used in production code. |
|
| main.go:62:32:62:55 | lit-init key-value pair | InsecureSkipVerify should not be used in production code. |
|
||||||
|
|||||||
@@ -1,80 +1,85 @@
|
|||||||
#select
|
#select
|
||||||
| klog.go:23:15:23:20 | header | klog.go:21:30:21:37 | selection of Header | klog.go:23:15:23:20 | header | $@ flows to a logging call. | klog.go:21:30:21:37 | selection of Header | Sensitive data returned by HTTP request headers |
|
| klog.go:23:15:23:20 | header | klog.go:21:30:21:37 | selection of Header | klog.go:23:15:23:20 | header | $@ flows to a logging call. | klog.go:21:30:21:37 | selection of Header | Sensitive data returned by HTTP request headers |
|
||||||
| klog.go:29:13:29:41 | call to Get | klog.go:29:13:29:20 | selection of Header | klog.go:29:13:29:41 | call to Get | $@ flows to a logging call. | klog.go:29:13:29:20 | selection of Header | Sensitive data returned by HTTP request headers |
|
| klog.go:29:13:29:41 | call to Get | klog.go:29:13:29:20 | selection of Header | klog.go:29:13:29:41 | call to Get | $@ flows to a logging call. | klog.go:29:13:29:20 | selection of Header | Sensitive data returned by HTTP request headers |
|
||||||
| main.go:19:12:19:19 | password | main.go:17:2:17:9 | SSA def(password) | main.go:19:12:19:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:19:12:19:19 | password | main.go:17:2:17:23 | SSA def(password) | main.go:19:12:19:19 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:20:19:20:26 | password | main.go:17:2:17:9 | SSA def(password) | main.go:20:19:20:26 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:20:19:20:26 | password | main.go:17:2:17:23 | SSA def(password) | main.go:20:19:20:26 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:21:13:21:20 | password | main.go:17:2:17:9 | SSA def(password) | main.go:21:13:21:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:21:13:21:20 | password | main.go:17:2:17:23 | SSA def(password) | main.go:21:13:21:20 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:22:14:22:21 | password | main.go:17:2:17:9 | SSA def(password) | main.go:22:14:22:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:22:14:22:21 | password | main.go:17:2:17:23 | SSA def(password) | main.go:22:14:22:21 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:24:13:24:20 | password | main.go:17:2:17:9 | SSA def(password) | main.go:24:13:24:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:24:13:24:20 | password | main.go:17:2:17:23 | SSA def(password) | main.go:24:13:24:20 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:27:20:27:27 | password | main.go:17:2:17:9 | SSA def(password) | main.go:27:20:27:27 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:27:20:27:27 | password | main.go:17:2:17:23 | SSA def(password) | main.go:27:20:27:27 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:30:14:30:21 | password | main.go:17:2:17:9 | SSA def(password) | main.go:30:14:30:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:30:14:30:21 | password | main.go:17:2:17:23 | SSA def(password) | main.go:30:14:30:21 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:33:15:33:22 | password | main.go:17:2:17:9 | SSA def(password) | main.go:33:15:33:22 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:33:15:33:22 | password | main.go:17:2:17:23 | SSA def(password) | main.go:33:15:33:22 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:36:13:36:20 | password | main.go:17:2:17:9 | SSA def(password) | main.go:36:13:36:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:36:13:36:20 | password | main.go:17:2:17:23 | SSA def(password) | main.go:36:13:36:20 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:39:20:39:27 | password | main.go:17:2:17:9 | SSA def(password) | main.go:39:20:39:27 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:39:20:39:27 | password | main.go:17:2:17:23 | SSA def(password) | main.go:39:20:39:27 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:42:14:42:21 | password | main.go:17:2:17:9 | SSA def(password) | main.go:42:14:42:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:42:14:42:21 | password | main.go:17:2:17:23 | SSA def(password) | main.go:42:14:42:21 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:45:15:45:22 | password | main.go:17:2:17:9 | SSA def(password) | main.go:45:15:45:22 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:45:15:45:22 | password | main.go:17:2:17:23 | SSA def(password) | main.go:45:15:45:22 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:47:16:47:23 | password | main.go:17:2:17:9 | SSA def(password) | main.go:47:16:47:23 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:47:16:47:23 | password | main.go:17:2:17:23 | SSA def(password) | main.go:47:16:47:23 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:51:10:51:17 | password | main.go:17:2:17:9 | SSA def(password) | main.go:51:10:51:17 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:51:10:51:17 | password | main.go:17:2:17:23 | SSA def(password) | main.go:51:10:51:17 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:52:17:52:24 | password | main.go:17:2:17:9 | SSA def(password) | main.go:52:17:52:24 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:52:17:52:24 | password | main.go:17:2:17:23 | SSA def(password) | main.go:52:17:52:24 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:53:11:53:18 | password | main.go:17:2:17:9 | SSA def(password) | main.go:53:11:53:18 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:53:11:53:18 | password | main.go:17:2:17:23 | SSA def(password) | main.go:53:11:53:18 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:54:12:54:19 | password | main.go:17:2:17:9 | SSA def(password) | main.go:54:12:54:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:54:12:54:19 | password | main.go:17:2:17:23 | SSA def(password) | main.go:54:12:54:19 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:56:11:56:18 | password | main.go:17:2:17:9 | SSA def(password) | main.go:56:11:56:18 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:56:11:56:18 | password | main.go:17:2:17:23 | SSA def(password) | main.go:56:11:56:18 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:59:18:59:25 | password | main.go:17:2:17:9 | SSA def(password) | main.go:59:18:59:25 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:59:18:59:25 | password | main.go:17:2:17:23 | SSA def(password) | main.go:59:18:59:25 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:62:12:62:19 | password | main.go:17:2:17:9 | SSA def(password) | main.go:62:12:62:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:62:12:62:19 | password | main.go:17:2:17:23 | SSA def(password) | main.go:62:12:62:19 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:65:13:65:20 | password | main.go:17:2:17:9 | SSA def(password) | main.go:65:13:65:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:65:13:65:20 | password | main.go:17:2:17:23 | SSA def(password) | main.go:65:13:65:20 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:68:11:68:18 | password | main.go:17:2:17:9 | SSA def(password) | main.go:68:11:68:18 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:68:11:68:18 | password | main.go:17:2:17:23 | SSA def(password) | main.go:68:11:68:18 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:71:18:71:25 | password | main.go:17:2:17:9 | SSA def(password) | main.go:71:18:71:25 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:71:18:71:25 | password | main.go:17:2:17:23 | SSA def(password) | main.go:71:18:71:25 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:74:12:74:19 | password | main.go:17:2:17:9 | SSA def(password) | main.go:74:12:74:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:74:12:74:19 | password | main.go:17:2:17:23 | SSA def(password) | main.go:74:12:74:19 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:77:13:77:20 | password | main.go:17:2:17:9 | SSA def(password) | main.go:77:13:77:20 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:77:13:77:20 | password | main.go:17:2:17:23 | SSA def(password) | main.go:77:13:77:20 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:79:14:79:21 | password | main.go:17:2:17:9 | SSA def(password) | main.go:79:14:79:21 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:79:14:79:21 | password | main.go:17:2:17:23 | SSA def(password) | main.go:79:14:79:21 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:82:12:82:19 | password | main.go:17:2:17:9 | SSA def(password) | main.go:82:12:82:19 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:82:12:82:19 | password | main.go:17:2:17:23 | SSA def(password) | main.go:82:12:82:19 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:83:17:83:24 | password | main.go:17:2:17:9 | SSA def(password) | main.go:83:17:83:24 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:83:17:83:24 | password | main.go:17:2:17:23 | SSA def(password) | main.go:83:17:83:24 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:87:29:87:34 | fields | main.go:17:2:17:9 | SSA def(password) | main.go:87:29:87:34 | fields | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:87:29:87:34 | fields | main.go:17:2:17:23 | SSA def(password) | main.go:87:29:87:34 | fields | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| main.go:90:35:90:42 | password | main.go:17:2:17:9 | SSA def(password) | main.go:90:35:90:42 | password | $@ flows to a logging call. | main.go:17:2:17:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| main.go:90:35:90:42 | password | main.go:17:2:17:23 | SSA def(password) | main.go:90:35:90:42 | password | $@ flows to a logging call. | main.go:17:2:17:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| overrides.go:13:14:13:23 | call to String | overrides.go:8:2:8:9 | SSA def(password) | overrides.go:13:14:13:23 | call to String | $@ flows to a logging call. | overrides.go:8:2:8:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| overrides.go:13:14:13:23 | call to String | overrides.go:8:2:8:40 | SSA def(password) | overrides.go:13:14:13:23 | call to String | $@ flows to a logging call. | overrides.go:8:2:8:40 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| passwords.go:9:14:9:14 | x | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:9:14:9:14 | x | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| passwords.go:9:14:9:14 | x | passwords.go:21:2:21:23 | SSA def(password) | passwords.go:9:14:9:14 | x | $@ flows to a logging call. | passwords.go:21:2:21:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| passwords.go:25:14:25:21 | password | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:25:14:25:21 | password | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| passwords.go:25:14:25:21 | password | passwords.go:21:2:21:23 | SSA def(password) | passwords.go:25:14:25:21 | password | $@ flows to a logging call. | passwords.go:21:2:21:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| passwords.go:26:14:26:23 | selection of password | passwords.go:26:14:26:23 | selection of password | passwords.go:26:14:26:23 | selection of password | $@ flows to a logging call. | passwords.go:26:14:26:23 | selection of password | Sensitive data returned by an access to password |
|
| passwords.go:26:14:26:23 | selection of password | passwords.go:26:14:26:23 | selection of password | passwords.go:26:14:26:23 | selection of password | $@ flows to a logging call. | passwords.go:26:14:26:23 | selection of password | Sensitive data returned by an access to password |
|
||||||
| passwords.go:27:14:27:26 | call to getPassword | passwords.go:27:14:27:26 | call to getPassword | passwords.go:27:14:27:26 | call to getPassword | $@ flows to a logging call. | passwords.go:27:14:27:26 | call to getPassword | Sensitive data returned by a call to getPassword |
|
| passwords.go:27:14:27:26 | call to getPassword | passwords.go:27:14:27:26 | call to getPassword | passwords.go:27:14:27:26 | call to getPassword | $@ flows to a logging call. | passwords.go:27:14:27:26 | call to getPassword | Sensitive data returned by a call to getPassword |
|
||||||
| passwords.go:28:14:28:28 | call to getPassword | passwords.go:28:14:28:28 | call to getPassword | passwords.go:28:14:28:28 | call to getPassword | $@ flows to a logging call. | passwords.go:28:14:28:28 | call to getPassword | Sensitive data returned by a call to getPassword |
|
| passwords.go:28:14:28:28 | call to getPassword | passwords.go:28:14:28:28 | call to getPassword | passwords.go:28:14:28:28 | call to getPassword | $@ flows to a logging call. | passwords.go:28:14:28:28 | call to getPassword | Sensitive data returned by a call to getPassword |
|
||||||
| passwords.go:33:13:33:20 | password | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:33:13:33:20 | password | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| passwords.go:33:13:33:20 | password | passwords.go:21:2:21:23 | SSA def(password) | passwords.go:33:13:33:20 | password | $@ flows to a logging call. | passwords.go:21:2:21:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| passwords.go:36:14:36:35 | ...+... | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:36:14:36:35 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| passwords.go:36:14:36:35 | ...+... | passwords.go:21:2:21:23 | SSA def(password) | passwords.go:36:14:36:35 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
|
| passwords.go:41:14:41:17 | obj1 | passwords.go:39:3:39:13 | key-value pair | passwords.go:41:14:41:17 | obj1 | $@ flows to a logging call. | passwords.go:39:3:39:13 | key-value pair | Sensitive data returned by an access to password |
|
||||||
| passwords.go:41:14:41:17 | obj1 | passwords.go:39:13:39:13 | x | passwords.go:41:14:41:17 | obj1 | $@ flows to a logging call. | passwords.go:39:13:39:13 | x | Sensitive data returned by an access to password |
|
| passwords.go:41:14:41:17 | obj1 | passwords.go:39:13:39:13 | x | passwords.go:41:14:41:17 | obj1 | $@ flows to a logging call. | passwords.go:39:13:39:13 | x | Sensitive data returned by an access to password |
|
||||||
| passwords.go:46:14:46:17 | obj2 | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:46:14:46:17 | obj2 | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| passwords.go:46:14:46:17 | obj2 | passwords.go:21:2:21:23 | SSA def(password) | passwords.go:46:14:46:17 | obj2 | $@ flows to a logging call. | passwords.go:21:2:21:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| passwords.go:53:14:53:27 | fixed_password | passwords.go:52:2:52:15 | SSA def(fixed_password) | passwords.go:53:14:53:27 | fixed_password | $@ flows to a logging call. | passwords.go:52:2:52:15 | SSA def(fixed_password) | Sensitive data returned by an access to fixed_password |
|
| passwords.go:53:14:53:27 | fixed_password | passwords.go:52:2:52:44 | SSA def(fixed_password) | passwords.go:53:14:53:27 | fixed_password | $@ flows to a logging call. | passwords.go:52:2:52:44 | SSA def(fixed_password) | Sensitive data returned by an access to fixed_password |
|
||||||
|
| passwords.go:65:14:65:44 | struct literal | passwords.go:65:25:65:43 | key-value pair | passwords.go:65:14:65:44 | struct literal | $@ flows to a logging call. | passwords.go:65:25:65:43 | key-value pair | Sensitive data returned by an access to password |
|
||||||
|
| passwords.go:91:14:91:26 | utilityObject | passwords.go:89:3:89:36 | key-value pair | passwords.go:91:14:91:26 | utilityObject | $@ flows to a logging call. | passwords.go:89:3:89:36 | key-value pair | Sensitive data returned by an access to passwordSet |
|
||||||
| passwords.go:91:14:91:26 | utilityObject | passwords.go:89:16:89:36 | call to make | passwords.go:91:14:91:26 | utilityObject | $@ flows to a logging call. | passwords.go:89:16:89:36 | call to make | Sensitive data returned by an access to passwordSet |
|
| passwords.go:91:14:91:26 | utilityObject | passwords.go:89:16:89:36 | call to make | passwords.go:91:14:91:26 | utilityObject | $@ flows to a logging call. | passwords.go:89:16:89:36 | call to make | Sensitive data returned by an access to passwordSet |
|
||||||
| passwords.go:94:23:94:28 | secret | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:94:23:94:28 | secret | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| passwords.go:94:23:94:28 | secret | passwords.go:21:2:21:23 | SSA def(password) | passwords.go:94:23:94:28 | secret | $@ flows to a logging call. | passwords.go:21:2:21:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| passwords.go:104:15:104:40 | ...+... | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:104:15:104:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| passwords.go:104:15:104:40 | ...+... | passwords.go:21:2:21:23 | SSA def(password) | passwords.go:104:15:104:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| passwords.go:110:16:110:41 | ...+... | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:110:16:110:41 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| passwords.go:110:16:110:41 | ...+... | passwords.go:21:2:21:23 | SSA def(password) | passwords.go:110:16:110:41 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| passwords.go:115:15:115:40 | ...+... | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:115:15:115:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| passwords.go:115:15:115:40 | ...+... | passwords.go:21:2:21:23 | SSA def(password) | passwords.go:115:15:115:40 | ...+... | $@ flows to a logging call. | passwords.go:21:2:21:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| passwords.go:119:14:119:45 | ...+... | passwords.go:118:6:118:14 | SSA def(password1) | passwords.go:119:14:119:45 | ...+... | $@ flows to a logging call. | passwords.go:118:6:118:14 | SSA def(password1) | Sensitive data returned by an access to password1 |
|
| passwords.go:119:14:119:45 | ...+... | passwords.go:118:6:118:50 | SSA def(password1) | passwords.go:119:14:119:45 | ...+... | $@ flows to a logging call. | passwords.go:118:6:118:50 | SSA def(password1) | Sensitive data returned by an access to password1 |
|
||||||
| passwords.go:129:14:129:19 | config | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| passwords.go:129:14:129:19 | config | passwords.go:21:2:21:23 | SSA def(password) | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:21:2:21:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
|
| passwords.go:129:14:129:19 | config | passwords.go:123:3:123:14 | key-value pair | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:123:3:123:14 | key-value pair | Sensitive data returned by an access to password |
|
||||||
| passwords.go:129:14:129:19 | config | passwords.go:123:13:123:14 | x3 | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:123:13:123:14 | x3 | Sensitive data returned by an access to password |
|
| passwords.go:129:14:129:19 | config | passwords.go:123:13:123:14 | x3 | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:123:13:123:14 | x3 | Sensitive data returned by an access to password |
|
||||||
| passwords.go:129:14:129:19 | config | passwords.go:126:13:126:25 | call to getPassword | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:126:13:126:25 | call to getPassword | Sensitive data returned by a call to getPassword |
|
| passwords.go:129:14:129:19 | config | passwords.go:126:13:126:25 | call to getPassword | passwords.go:129:14:129:19 | config | $@ flows to a logging call. | passwords.go:126:13:126:25 | call to getPassword | Sensitive data returned by a call to getPassword |
|
||||||
| passwords.go:130:14:130:21 | selection of x | passwords.go:21:2:21:9 | SSA def(password) | passwords.go:130:14:130:21 | selection of x | $@ flows to a logging call. | passwords.go:21:2:21:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| passwords.go:130:14:130:21 | selection of x | passwords.go:21:2:21:23 | SSA def(password) | passwords.go:130:14:130:21 | selection of x | $@ flows to a logging call. | passwords.go:21:2:21:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
| passwords.go:131:14:131:21 | selection of y | passwords.go:126:13:126:25 | call to getPassword | passwords.go:131:14:131:21 | selection of y | $@ flows to a logging call. | passwords.go:126:13:126:25 | call to getPassword | Sensitive data returned by a call to getPassword |
|
| passwords.go:131:14:131:21 | selection of y | passwords.go:126:13:126:25 | call to getPassword | passwords.go:131:14:131:21 | selection of y | $@ flows to a logging call. | passwords.go:126:13:126:25 | call to getPassword | Sensitive data returned by a call to getPassword |
|
||||||
| protobuf.go:14:14:14:35 | call to GetDescription | protobuf.go:9:2:9:9 | SSA def(password) | protobuf.go:14:14:14:35 | call to GetDescription | $@ flows to a logging call. | protobuf.go:9:2:9:9 | SSA def(password) | Sensitive data returned by an access to password |
|
| protobuf.go:14:14:14:35 | call to GetDescription | protobuf.go:9:2:9:23 | SSA def(password) | protobuf.go:14:14:14:35 | call to GetDescription | $@ flows to a logging call. | protobuf.go:9:2:9:23 | SSA def(password) | Sensitive data returned by an access to password |
|
||||||
|
| server1.go:19:15:19:19 | user3 | server1.go:17:4:17:63 | key-value pair | server1.go:19:15:19:19 | user3 | $@ flows to a logging call. | server1.go:17:4:17:63 | key-value pair | Sensitive data returned by an access to password |
|
||||||
edges
|
edges
|
||||||
| klog.go:21:3:26:3 | range statement[1] | klog.go:22:27:22:33 | headers | provenance | |
|
| klog.go:21:3:26:3 | extract:1 range statement | klog.go:22:27:22:33 | headers | provenance | |
|
||||||
| klog.go:21:30:21:37 | selection of Header | klog.go:21:3:26:3 | range statement[1] | provenance | Src:MaD:11 Config |
|
| klog.go:21:30:21:37 | selection of Header | klog.go:21:3:26:3 | extract:1 range statement | provenance | Src:MaD:11 Config |
|
||||||
| klog.go:22:4:25:4 | range statement[1] | klog.go:23:15:23:20 | header | provenance | |
|
| klog.go:22:4:25:4 | extract:1 range statement | klog.go:23:15:23:20 | header | provenance | |
|
||||||
| klog.go:22:27:22:33 | headers | klog.go:22:4:25:4 | range statement[1] | provenance | Config |
|
| klog.go:22:27:22:33 | headers | klog.go:22:4:25:4 | extract:1 range statement | provenance | Config |
|
||||||
| klog.go:29:13:29:20 | selection of Header | klog.go:29:13:29:41 | call to Get | provenance | Src:MaD:11 Config |
|
| klog.go:29:13:29:20 | selection of Header | klog.go:29:13:29:41 | call to Get | provenance | Src:MaD:11 Config |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:19:12:19:19 | password | provenance | |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:19:12:19:19 | password | provenance | |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:20:19:20:26 | password | provenance | |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:20:19:20:26 | password | provenance | |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:21:13:21:20 | password | provenance | Sink:MaD:6 |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:21:13:21:20 | password | provenance | Sink:MaD:6 |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:22:14:22:21 | password | provenance | |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:22:14:22:21 | password | provenance | |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:24:13:24:20 | password | provenance | |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:24:13:24:20 | password | provenance | |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:27:20:27:27 | password | provenance | |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:27:20:27:27 | password | provenance | |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:30:14:30:21 | password | provenance | Sink:MaD:3 |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:30:14:30:21 | password | provenance | Sink:MaD:3 |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:33:15:33:22 | password | provenance | |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:33:15:33:22 | password | provenance | |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:36:13:36:20 | password | provenance | |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:36:13:36:20 | password | provenance | |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:39:20:39:27 | password | provenance | |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:39:20:39:27 | password | provenance | |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:42:14:42:21 | password | provenance | Sink:MaD:5 |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:42:14:42:21 | password | provenance | Sink:MaD:5 |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:45:15:45:22 | password | provenance | |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:45:15:45:22 | password | provenance | |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:47:16:47:23 | password | provenance | Sink:MaD:4 |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:47:16:47:23 | password | provenance | Sink:MaD:4 |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:51:10:51:17 | password | provenance | |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:51:10:51:17 | password | provenance | |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | main.go:51:10:51:17 | password | provenance | |
|
| main.go:17:2:17:23 | SSA def(password) | main.go:51:10:51:17 | password | provenance | |
|
||||||
| main.go:51:10:51:17 | password | main.go:52:17:52:24 | password | provenance | |
|
| main.go:51:10:51:17 | password | main.go:52:17:52:24 | password | provenance | |
|
||||||
| main.go:51:10:51:17 | password | main.go:52:17:52:24 | password | provenance | |
|
| main.go:51:10:51:17 | password | main.go:52:17:52:24 | password | provenance | |
|
||||||
| main.go:52:17:52:24 | password | main.go:53:11:53:18 | password | provenance | |
|
| main.go:52:17:52:24 | password | main.go:53:11:53:18 | password | provenance | |
|
||||||
@@ -97,17 +102,18 @@ edges
|
|||||||
| main.go:86:2:86:7 | fields [postupdate] | main.go:87:29:87:34 | fields | provenance | Sink:MaD:2 |
|
| main.go:86:2:86:7 | fields [postupdate] | main.go:87:29:87:34 | fields | provenance | Sink:MaD:2 |
|
||||||
| main.go:86:19:86:26 | password | main.go:86:2:86:7 | fields [postupdate] | provenance | Config |
|
| main.go:86:19:86:26 | password | main.go:86:2:86:7 | fields [postupdate] | provenance | Config |
|
||||||
| main.go:86:19:86:26 | password | main.go:90:35:90:42 | password | provenance | Sink:MaD:1 |
|
| main.go:86:19:86:26 | password | main.go:90:35:90:42 | password | provenance | Sink:MaD:1 |
|
||||||
| overrides.go:8:2:8:9 | SSA def(password) | overrides.go:9:9:9:16 | password | provenance | |
|
| overrides.go:8:2:8:40 | SSA def(password) | overrides.go:9:9:9:16 | password | provenance | |
|
||||||
| overrides.go:9:9:9:16 | password | overrides.go:13:14:13:23 | call to String | provenance | |
|
| overrides.go:9:9:9:16 | password | overrides.go:13:14:13:23 | call to String | provenance | |
|
||||||
| passwords.go:8:12:8:12 | SSA def(x) | passwords.go:9:14:9:14 | x | provenance | |
|
| passwords.go:8:22:10:1 | SSA def(x) | passwords.go:9:14:9:14 | x | provenance | |
|
||||||
| passwords.go:21:2:21:9 | SSA def(password) | passwords.go:25:14:25:21 | password | provenance | |
|
| passwords.go:21:2:21:23 | SSA def(password) | passwords.go:25:14:25:21 | password | provenance | |
|
||||||
| passwords.go:21:2:21:9 | SSA def(password) | passwords.go:30:8:30:15 | password | provenance | |
|
| passwords.go:21:2:21:23 | SSA def(password) | passwords.go:30:8:30:15 | password | provenance | |
|
||||||
| passwords.go:21:2:21:9 | SSA def(password) | passwords.go:33:13:33:20 | password | provenance | |
|
| passwords.go:21:2:21:23 | SSA def(password) | passwords.go:33:13:33:20 | password | provenance | |
|
||||||
| passwords.go:21:2:21:9 | SSA def(password) | passwords.go:36:28:36:35 | password | provenance | |
|
| passwords.go:21:2:21:23 | SSA def(password) | passwords.go:36:28:36:35 | password | provenance | |
|
||||||
| passwords.go:30:8:30:15 | password | passwords.go:8:12:8:12 | SSA def(x) | provenance | |
|
| passwords.go:30:8:30:15 | password | passwords.go:8:22:10:1 | SSA def(x) | provenance | |
|
||||||
| passwords.go:36:28:36:35 | password | passwords.go:36:14:36:35 | ...+... | provenance | Config |
|
| passwords.go:36:28:36:35 | password | passwords.go:36:14:36:35 | ...+... | provenance | Config |
|
||||||
| passwords.go:36:28:36:35 | password | passwords.go:44:6:44:13 | password | provenance | |
|
| passwords.go:36:28:36:35 | password | passwords.go:44:6:44:13 | password | provenance | |
|
||||||
| passwords.go:38:10:40:2 | struct literal | passwords.go:41:14:41:17 | obj1 | provenance | |
|
| passwords.go:38:10:40:2 | struct literal | passwords.go:41:14:41:17 | obj1 | provenance | |
|
||||||
|
| passwords.go:39:3:39:13 | key-value pair | passwords.go:38:10:40:2 | struct literal | provenance | Config |
|
||||||
| passwords.go:39:13:39:13 | x | passwords.go:38:10:40:2 | struct literal | provenance | Config |
|
| passwords.go:39:13:39:13 | x | passwords.go:38:10:40:2 | struct literal | provenance | Config |
|
||||||
| passwords.go:43:10:45:2 | struct literal | passwords.go:46:14:46:17 | obj2 | provenance | |
|
| passwords.go:43:10:45:2 | struct literal | passwords.go:46:14:46:17 | obj2 | provenance | |
|
||||||
| passwords.go:44:6:44:13 | password | passwords.go:43:10:45:2 | struct literal | provenance | Config |
|
| passwords.go:44:6:44:13 | password | passwords.go:43:10:45:2 | struct literal | provenance | Config |
|
||||||
@@ -117,8 +123,10 @@ edges
|
|||||||
| passwords.go:50:11:50:18 | password | passwords.go:110:34:110:41 | password | provenance | |
|
| passwords.go:50:11:50:18 | password | passwords.go:110:34:110:41 | password | provenance | |
|
||||||
| passwords.go:50:11:50:18 | password | passwords.go:115:33:115:40 | password | provenance | |
|
| passwords.go:50:11:50:18 | password | passwords.go:115:33:115:40 | password | provenance | |
|
||||||
| passwords.go:50:11:50:18 | password | passwords.go:125:13:125:20 | password | provenance | |
|
| passwords.go:50:11:50:18 | password | passwords.go:125:13:125:20 | password | provenance | |
|
||||||
| passwords.go:52:2:52:15 | SSA def(fixed_password) | passwords.go:53:14:53:27 | fixed_password | provenance | |
|
| passwords.go:52:2:52:44 | SSA def(fixed_password) | passwords.go:53:14:53:27 | fixed_password | provenance | |
|
||||||
|
| passwords.go:65:25:65:43 | key-value pair | passwords.go:65:14:65:44 | struct literal | provenance | Config |
|
||||||
| passwords.go:88:19:90:2 | struct literal | passwords.go:91:14:91:26 | utilityObject | provenance | |
|
| passwords.go:88:19:90:2 | struct literal | passwords.go:91:14:91:26 | utilityObject | provenance | |
|
||||||
|
| passwords.go:89:3:89:36 | key-value pair | passwords.go:88:19:90:2 | struct literal | provenance | Config |
|
||||||
| passwords.go:89:16:89:36 | call to make | passwords.go:88:19:90:2 | struct literal | provenance | Config |
|
| passwords.go:89:16:89:36 | call to make | passwords.go:88:19:90:2 | struct literal | provenance | Config |
|
||||||
| passwords.go:104:33:104:40 | password | passwords.go:104:15:104:40 | ...+... | provenance | Config |
|
| passwords.go:104:33:104:40 | password | passwords.go:104:15:104:40 | ...+... | provenance | Config |
|
||||||
| passwords.go:104:33:104:40 | password | passwords.go:110:34:110:41 | password | provenance | |
|
| passwords.go:104:33:104:40 | password | passwords.go:110:34:110:41 | password | provenance | |
|
||||||
@@ -129,12 +137,13 @@ edges
|
|||||||
| passwords.go:110:34:110:41 | password | passwords.go:125:13:125:20 | password | provenance | |
|
| passwords.go:110:34:110:41 | password | passwords.go:125:13:125:20 | password | provenance | |
|
||||||
| passwords.go:115:33:115:40 | password | passwords.go:115:15:115:40 | ...+... | provenance | Config |
|
| passwords.go:115:33:115:40 | password | passwords.go:115:15:115:40 | ...+... | provenance | Config |
|
||||||
| passwords.go:115:33:115:40 | password | passwords.go:125:13:125:20 | password | provenance | |
|
| passwords.go:115:33:115:40 | password | passwords.go:125:13:125:20 | password | provenance | |
|
||||||
| passwords.go:118:6:118:14 | SSA def(password1) | passwords.go:119:28:119:36 | password1 | provenance | |
|
| passwords.go:118:6:118:50 | SSA def(password1) | passwords.go:119:28:119:36 | password1 | provenance | |
|
||||||
| passwords.go:119:28:119:36 | password1 | passwords.go:119:28:119:45 | call to String | provenance | Config |
|
| passwords.go:119:28:119:36 | password1 | passwords.go:119:28:119:45 | call to String | provenance | Config |
|
||||||
| passwords.go:119:28:119:45 | call to String | passwords.go:119:14:119:45 | ...+... | provenance | Config |
|
| passwords.go:119:28:119:45 | call to String | passwords.go:119:14:119:45 | ...+... | provenance | Config |
|
||||||
| passwords.go:122:12:127:2 | struct literal | passwords.go:129:14:129:19 | config | provenance | |
|
| passwords.go:122:12:127:2 | struct literal | passwords.go:129:14:129:19 | config | provenance | |
|
||||||
| passwords.go:122:12:127:2 | struct literal [x] | passwords.go:130:14:130:19 | config [x] | provenance | |
|
| passwords.go:122:12:127:2 | struct literal [x] | passwords.go:130:14:130:19 | config [x] | provenance | |
|
||||||
| passwords.go:122:12:127:2 | struct literal [y] | passwords.go:131:14:131:19 | config [y] | provenance | |
|
| passwords.go:122:12:127:2 | struct literal [y] | passwords.go:131:14:131:19 | config [y] | provenance | |
|
||||||
|
| passwords.go:123:3:123:14 | key-value pair | passwords.go:122:12:127:2 | struct literal | provenance | Config |
|
||||||
| passwords.go:123:13:123:14 | x3 | passwords.go:122:12:127:2 | struct literal | provenance | Config |
|
| passwords.go:123:13:123:14 | x3 | passwords.go:122:12:127:2 | struct literal | provenance | Config |
|
||||||
| passwords.go:125:13:125:20 | password | passwords.go:122:12:127:2 | struct literal | provenance | Config |
|
| passwords.go:125:13:125:20 | password | passwords.go:122:12:127:2 | struct literal | provenance | Config |
|
||||||
| passwords.go:125:13:125:20 | password | passwords.go:122:12:127:2 | struct literal [x] | provenance | |
|
| passwords.go:125:13:125:20 | password | passwords.go:122:12:127:2 | struct literal [x] | provenance | |
|
||||||
@@ -142,15 +151,17 @@ edges
|
|||||||
| passwords.go:126:13:126:25 | call to getPassword | passwords.go:122:12:127:2 | struct literal [y] | provenance | |
|
| passwords.go:126:13:126:25 | call to getPassword | passwords.go:122:12:127:2 | struct literal [y] | provenance | |
|
||||||
| passwords.go:130:14:130:19 | config [x] | passwords.go:130:14:130:21 | selection of x | provenance | |
|
| passwords.go:130:14:130:19 | config [x] | passwords.go:130:14:130:21 | selection of x | provenance | |
|
||||||
| passwords.go:131:14:131:19 | config [y] | passwords.go:131:14:131:21 | selection of y | provenance | |
|
| passwords.go:131:14:131:19 | config [y] | passwords.go:131:14:131:21 | selection of y | provenance | |
|
||||||
| protobuf.go:9:2:9:9 | SSA def(password) | protobuf.go:12:22:12:29 | password | provenance | |
|
| protobuf.go:9:2:9:23 | SSA def(password) | protobuf.go:12:22:12:29 | password | provenance | |
|
||||||
| protobuf.go:12:2:12:6 | implicit dereference [postupdate] [Description] | protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | provenance | |
|
| protobuf.go:12:2:12:6 | implicit-deref query [postupdate] [Description] | protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | provenance | |
|
||||||
| protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | protobuf.go:14:14:14:18 | query [pointer, Description] | provenance | |
|
| protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | protobuf.go:14:14:14:18 | query [pointer, Description] | provenance | |
|
||||||
| protobuf.go:12:22:12:29 | password | protobuf.go:12:2:12:6 | implicit dereference [postupdate] [Description] | provenance | |
|
| protobuf.go:12:22:12:29 | password | protobuf.go:12:2:12:6 | implicit-deref query [postupdate] [Description] | provenance | |
|
||||||
| protobuf.go:14:14:14:18 | query [pointer, Description] | protobuf.go:14:14:14:35 | call to GetDescription | provenance | |
|
| protobuf.go:14:14:14:18 | query [pointer, Description] | protobuf.go:14:14:14:35 | call to GetDescription | provenance | |
|
||||||
| protobuf.go:14:14:14:18 | query [pointer, Description] | protos/query/query.pb.go:117:7:117:7 | SSA def(x) [pointer, Description] | provenance | |
|
| protobuf.go:14:14:14:18 | query [pointer, Description] | protos/query/query.pb.go:117:41:122:1 | SSA def(x) [pointer, Description] | provenance | |
|
||||||
| protos/query/query.pb.go:117:7:117:7 | SSA def(x) [pointer, Description] | protos/query/query.pb.go:119:10:119:10 | x [pointer, Description] | provenance | |
|
| protos/query/query.pb.go:117:41:122:1 | SSA def(x) [pointer, Description] | protos/query/query.pb.go:119:10:119:10 | x [pointer, Description] | provenance | |
|
||||||
| protos/query/query.pb.go:119:10:119:10 | implicit dereference [Description] | protos/query/query.pb.go:119:10:119:22 | selection of Description | provenance | |
|
| protos/query/query.pb.go:119:10:119:10 | implicit-deref x [Description] | protos/query/query.pb.go:119:10:119:22 | selection of Description | provenance | |
|
||||||
| protos/query/query.pb.go:119:10:119:10 | x [pointer, Description] | protos/query/query.pb.go:119:10:119:10 | implicit dereference [Description] | provenance | |
|
| protos/query/query.pb.go:119:10:119:10 | x [pointer, Description] | protos/query/query.pb.go:119:10:119:10 | implicit-deref x [Description] | provenance | |
|
||||||
|
| server1.go:16:15:18:3 | struct literal | server1.go:19:15:19:19 | user3 | provenance | |
|
||||||
|
| server1.go:17:4:17:63 | key-value pair | server1.go:16:15:18:3 | struct literal | provenance | Config |
|
||||||
models
|
models
|
||||||
| 1 | Sink: group:logrus; ; false; WithField; ; ; Argument[0..1]; log-injection; manual |
|
| 1 | Sink: group:logrus; ; false; WithField; ; ; Argument[0..1]; log-injection; manual |
|
||||||
| 2 | Sink: group:logrus; ; false; WithFields; ; ; Argument[0]; log-injection; manual |
|
| 2 | Sink: group:logrus; ; false; WithFields; ; ; Argument[0]; log-injection; manual |
|
||||||
@@ -164,14 +175,14 @@ models
|
|||||||
| 10 | Sink: log; Logger; true; Printf; ; ; Argument[0..1]; log-injection; manual |
|
| 10 | Sink: log; Logger; true; Printf; ; ; Argument[0..1]; log-injection; manual |
|
||||||
| 11 | Source: net/http; Request; true; Header; ; ; ; remote; manual |
|
| 11 | Source: net/http; Request; true; Header; ; ; ; remote; manual |
|
||||||
nodes
|
nodes
|
||||||
| klog.go:21:3:26:3 | range statement[1] | semmle.label | range statement[1] |
|
| klog.go:21:3:26:3 | extract:1 range statement | semmle.label | extract:1 range statement |
|
||||||
| klog.go:21:30:21:37 | selection of Header | semmle.label | selection of Header |
|
| klog.go:21:30:21:37 | selection of Header | semmle.label | selection of Header |
|
||||||
| klog.go:22:4:25:4 | range statement[1] | semmle.label | range statement[1] |
|
| klog.go:22:4:25:4 | extract:1 range statement | semmle.label | extract:1 range statement |
|
||||||
| klog.go:22:27:22:33 | headers | semmle.label | headers |
|
| klog.go:22:27:22:33 | headers | semmle.label | headers |
|
||||||
| klog.go:23:15:23:20 | header | semmle.label | header |
|
| klog.go:23:15:23:20 | header | semmle.label | header |
|
||||||
| klog.go:29:13:29:20 | selection of Header | semmle.label | selection of Header |
|
| klog.go:29:13:29:20 | selection of Header | semmle.label | selection of Header |
|
||||||
| klog.go:29:13:29:41 | call to Get | semmle.label | call to Get |
|
| klog.go:29:13:29:41 | call to Get | semmle.label | call to Get |
|
||||||
| main.go:17:2:17:9 | SSA def(password) | semmle.label | SSA def(password) |
|
| main.go:17:2:17:23 | SSA def(password) | semmle.label | SSA def(password) |
|
||||||
| main.go:19:12:19:19 | password | semmle.label | password |
|
| main.go:19:12:19:19 | password | semmle.label | password |
|
||||||
| main.go:20:19:20:26 | password | semmle.label | password |
|
| main.go:20:19:20:26 | password | semmle.label | password |
|
||||||
| main.go:21:13:21:20 | password | semmle.label | password |
|
| main.go:21:13:21:20 | password | semmle.label | password |
|
||||||
@@ -209,12 +220,12 @@ nodes
|
|||||||
| main.go:86:19:86:26 | password | semmle.label | password |
|
| main.go:86:19:86:26 | password | semmle.label | password |
|
||||||
| main.go:87:29:87:34 | fields | semmle.label | fields |
|
| main.go:87:29:87:34 | fields | semmle.label | fields |
|
||||||
| main.go:90:35:90:42 | password | semmle.label | password |
|
| main.go:90:35:90:42 | password | semmle.label | password |
|
||||||
| overrides.go:8:2:8:9 | SSA def(password) | semmle.label | SSA def(password) |
|
| overrides.go:8:2:8:40 | SSA def(password) | semmle.label | SSA def(password) |
|
||||||
| overrides.go:9:9:9:16 | password | semmle.label | password |
|
| overrides.go:9:9:9:16 | password | semmle.label | password |
|
||||||
| overrides.go:13:14:13:23 | call to String | semmle.label | call to String |
|
| overrides.go:13:14:13:23 | call to String | semmle.label | call to String |
|
||||||
| passwords.go:8:12:8:12 | SSA def(x) | semmle.label | SSA def(x) |
|
| passwords.go:8:22:10:1 | SSA def(x) | semmle.label | SSA def(x) |
|
||||||
| passwords.go:9:14:9:14 | x | semmle.label | x |
|
| passwords.go:9:14:9:14 | x | semmle.label | x |
|
||||||
| passwords.go:21:2:21:9 | SSA def(password) | semmle.label | SSA def(password) |
|
| passwords.go:21:2:21:23 | SSA def(password) | semmle.label | SSA def(password) |
|
||||||
| passwords.go:25:14:25:21 | password | semmle.label | password |
|
| passwords.go:25:14:25:21 | password | semmle.label | password |
|
||||||
| passwords.go:26:14:26:23 | selection of password | semmle.label | selection of password |
|
| passwords.go:26:14:26:23 | selection of password | semmle.label | selection of password |
|
||||||
| passwords.go:27:14:27:26 | call to getPassword | semmle.label | call to getPassword |
|
| passwords.go:27:14:27:26 | call to getPassword | semmle.label | call to getPassword |
|
||||||
@@ -224,15 +235,19 @@ nodes
|
|||||||
| passwords.go:36:14:36:35 | ...+... | semmle.label | ...+... |
|
| passwords.go:36:14:36:35 | ...+... | semmle.label | ...+... |
|
||||||
| passwords.go:36:28:36:35 | password | semmle.label | password |
|
| passwords.go:36:28:36:35 | password | semmle.label | password |
|
||||||
| passwords.go:38:10:40:2 | struct literal | semmle.label | struct literal |
|
| passwords.go:38:10:40:2 | struct literal | semmle.label | struct literal |
|
||||||
|
| passwords.go:39:3:39:13 | key-value pair | semmle.label | key-value pair |
|
||||||
| passwords.go:39:13:39:13 | x | semmle.label | x |
|
| passwords.go:39:13:39:13 | x | semmle.label | x |
|
||||||
| passwords.go:41:14:41:17 | obj1 | semmle.label | obj1 |
|
| passwords.go:41:14:41:17 | obj1 | semmle.label | obj1 |
|
||||||
| passwords.go:43:10:45:2 | struct literal | semmle.label | struct literal |
|
| passwords.go:43:10:45:2 | struct literal | semmle.label | struct literal |
|
||||||
| passwords.go:44:6:44:13 | password | semmle.label | password |
|
| passwords.go:44:6:44:13 | password | semmle.label | password |
|
||||||
| passwords.go:46:14:46:17 | obj2 | semmle.label | obj2 |
|
| passwords.go:46:14:46:17 | obj2 | semmle.label | obj2 |
|
||||||
| passwords.go:50:11:50:18 | password | semmle.label | password |
|
| passwords.go:50:11:50:18 | password | semmle.label | password |
|
||||||
| passwords.go:52:2:52:15 | SSA def(fixed_password) | semmle.label | SSA def(fixed_password) |
|
| passwords.go:52:2:52:44 | SSA def(fixed_password) | semmle.label | SSA def(fixed_password) |
|
||||||
| passwords.go:53:14:53:27 | fixed_password | semmle.label | fixed_password |
|
| passwords.go:53:14:53:27 | fixed_password | semmle.label | fixed_password |
|
||||||
|
| passwords.go:65:14:65:44 | struct literal | semmle.label | struct literal |
|
||||||
|
| passwords.go:65:25:65:43 | key-value pair | semmle.label | key-value pair |
|
||||||
| passwords.go:88:19:90:2 | struct literal | semmle.label | struct literal |
|
| passwords.go:88:19:90:2 | struct literal | semmle.label | struct literal |
|
||||||
|
| passwords.go:89:3:89:36 | key-value pair | semmle.label | key-value pair |
|
||||||
| passwords.go:89:16:89:36 | call to make | semmle.label | call to make |
|
| passwords.go:89:16:89:36 | call to make | semmle.label | call to make |
|
||||||
| passwords.go:91:14:91:26 | utilityObject | semmle.label | utilityObject |
|
| passwords.go:91:14:91:26 | utilityObject | semmle.label | utilityObject |
|
||||||
| passwords.go:94:23:94:28 | secret | semmle.label | secret |
|
| passwords.go:94:23:94:28 | secret | semmle.label | secret |
|
||||||
@@ -242,13 +257,14 @@ nodes
|
|||||||
| passwords.go:110:34:110:41 | password | semmle.label | password |
|
| passwords.go:110:34:110:41 | password | semmle.label | password |
|
||||||
| passwords.go:115:15:115:40 | ...+... | semmle.label | ...+... |
|
| passwords.go:115:15:115:40 | ...+... | semmle.label | ...+... |
|
||||||
| passwords.go:115:33:115:40 | password | semmle.label | password |
|
| passwords.go:115:33:115:40 | password | semmle.label | password |
|
||||||
| passwords.go:118:6:118:14 | SSA def(password1) | semmle.label | SSA def(password1) |
|
| passwords.go:118:6:118:50 | SSA def(password1) | semmle.label | SSA def(password1) |
|
||||||
| passwords.go:119:14:119:45 | ...+... | semmle.label | ...+... |
|
| passwords.go:119:14:119:45 | ...+... | semmle.label | ...+... |
|
||||||
| passwords.go:119:28:119:36 | password1 | semmle.label | password1 |
|
| passwords.go:119:28:119:36 | password1 | semmle.label | password1 |
|
||||||
| passwords.go:119:28:119:45 | call to String | semmle.label | call to String |
|
| passwords.go:119:28:119:45 | call to String | semmle.label | call to String |
|
||||||
| passwords.go:122:12:127:2 | struct literal | semmle.label | struct literal |
|
| passwords.go:122:12:127:2 | struct literal | semmle.label | struct literal |
|
||||||
| passwords.go:122:12:127:2 | struct literal [x] | semmle.label | struct literal [x] |
|
| passwords.go:122:12:127:2 | struct literal [x] | semmle.label | struct literal [x] |
|
||||||
| passwords.go:122:12:127:2 | struct literal [y] | semmle.label | struct literal [y] |
|
| passwords.go:122:12:127:2 | struct literal [y] | semmle.label | struct literal [y] |
|
||||||
|
| passwords.go:123:3:123:14 | key-value pair | semmle.label | key-value pair |
|
||||||
| passwords.go:123:13:123:14 | x3 | semmle.label | x3 |
|
| passwords.go:123:13:123:14 | x3 | semmle.label | x3 |
|
||||||
| passwords.go:125:13:125:20 | password | semmle.label | password |
|
| passwords.go:125:13:125:20 | password | semmle.label | password |
|
||||||
| passwords.go:126:13:126:25 | call to getPassword | semmle.label | call to getPassword |
|
| passwords.go:126:13:126:25 | call to getPassword | semmle.label | call to getPassword |
|
||||||
@@ -257,15 +273,23 @@ nodes
|
|||||||
| passwords.go:130:14:130:21 | selection of x | semmle.label | selection of x |
|
| passwords.go:130:14:130:21 | selection of x | semmle.label | selection of x |
|
||||||
| passwords.go:131:14:131:19 | config [y] | semmle.label | config [y] |
|
| passwords.go:131:14:131:19 | config [y] | semmle.label | config [y] |
|
||||||
| passwords.go:131:14:131:21 | selection of y | semmle.label | selection of y |
|
| passwords.go:131:14:131:21 | selection of y | semmle.label | selection of y |
|
||||||
| protobuf.go:9:2:9:9 | SSA def(password) | semmle.label | SSA def(password) |
|
| protobuf.go:9:2:9:23 | SSA def(password) | semmle.label | SSA def(password) |
|
||||||
| protobuf.go:12:2:12:6 | implicit dereference [postupdate] [Description] | semmle.label | implicit dereference [postupdate] [Description] |
|
| protobuf.go:12:2:12:6 | implicit-deref query [postupdate] [Description] | semmle.label | implicit-deref query [postupdate] [Description] |
|
||||||
| protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | semmle.label | query [postupdate] [pointer, Description] |
|
| protobuf.go:12:2:12:6 | query [postupdate] [pointer, Description] | semmle.label | query [postupdate] [pointer, Description] |
|
||||||
| protobuf.go:12:22:12:29 | password | semmle.label | password |
|
| protobuf.go:12:22:12:29 | password | semmle.label | password |
|
||||||
| protobuf.go:14:14:14:18 | query [pointer, Description] | semmle.label | query [pointer, Description] |
|
| protobuf.go:14:14:14:18 | query [pointer, Description] | semmle.label | query [pointer, Description] |
|
||||||
| protobuf.go:14:14:14:35 | call to GetDescription | semmle.label | call to GetDescription |
|
| protobuf.go:14:14:14:35 | call to GetDescription | semmle.label | call to GetDescription |
|
||||||
| protos/query/query.pb.go:117:7:117:7 | SSA def(x) [pointer, Description] | semmle.label | SSA def(x) [pointer, Description] |
|
| protos/query/query.pb.go:117:41:122:1 | SSA def(x) [pointer, Description] | semmle.label | SSA def(x) [pointer, Description] |
|
||||||
| protos/query/query.pb.go:119:10:119:10 | implicit dereference [Description] | semmle.label | implicit dereference [Description] |
|
| protos/query/query.pb.go:119:10:119:10 | implicit-deref x [Description] | semmle.label | implicit-deref x [Description] |
|
||||||
| protos/query/query.pb.go:119:10:119:10 | x [pointer, Description] | semmle.label | x [pointer, Description] |
|
| protos/query/query.pb.go:119:10:119:10 | x [pointer, Description] | semmle.label | x [pointer, Description] |
|
||||||
| protos/query/query.pb.go:119:10:119:22 | selection of Description | semmle.label | selection of Description |
|
| protos/query/query.pb.go:119:10:119:22 | selection of Description | semmle.label | selection of Description |
|
||||||
|
| server1.go:16:15:18:3 | struct literal | semmle.label | struct literal |
|
||||||
|
| server1.go:17:4:17:63 | key-value pair | semmle.label | key-value pair |
|
||||||
|
| server1.go:19:15:19:19 | user3 | semmle.label | user3 |
|
||||||
subpaths
|
subpaths
|
||||||
| protobuf.go:14:14:14:18 | query [pointer, Description] | protos/query/query.pb.go:117:7:117:7 | SSA def(x) [pointer, Description] | protos/query/query.pb.go:119:10:119:22 | selection of Description | protobuf.go:14:14:14:35 | call to GetDescription |
|
| protobuf.go:14:14:14:18 | query [pointer, Description] | protos/query/query.pb.go:117:41:122:1 | SSA def(x) [pointer, Description] | protos/query/query.pb.go:119:10:119:22 | selection of Description | protobuf.go:14:14:14:35 | call to GetDescription |
|
||||||
|
testFailures
|
||||||
|
| passwords.go:65:14:65:44 | struct literal | Unexpected result: Alert |
|
||||||
|
| passwords.go:65:25:65:43 | key-value pair | Unexpected result: Alert |
|
||||||
|
| server1.go:17:4:17:63 | key-value pair | Unexpected result: Source |
|
||||||
|
| server1.go:19:15:19:19 | user3 | Unexpected result: Alert |
|
||||||
|
|||||||
@@ -8,18 +8,18 @@ edges
|
|||||||
| InsecureHostKeyCallbackExample.go:31:14:34:4 | type conversion | InsecureHostKeyCallbackExample.go:39:20:39:27 | callback | provenance | |
|
| InsecureHostKeyCallbackExample.go:31:14:34:4 | type conversion | InsecureHostKeyCallbackExample.go:39:20:39:27 | callback | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:32:3:34:3 | function literal | InsecureHostKeyCallbackExample.go:31:14:34:4 | type conversion | provenance | |
|
| InsecureHostKeyCallbackExample.go:32:3:34:3 | function literal | InsecureHostKeyCallbackExample.go:31:14:34:4 | type conversion | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:45:3:47:3 | function literal | InsecureHostKeyCallbackExample.go:52:20:52:48 | type conversion | provenance | |
|
| InsecureHostKeyCallbackExample.go:45:3:47:3 | function literal | InsecureHostKeyCallbackExample.go:52:20:52:48 | type conversion | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:58:39:58:46 | SSA def(callback) | InsecureHostKeyCallbackExample.go:62:20:62:27 | callback | provenance | |
|
| InsecureHostKeyCallbackExample.go:58:69:64:1 | SSA def(callback) | InsecureHostKeyCallbackExample.go:62:20:62:27 | callback | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:68:48:68:55 | SSA def(callback) | InsecureHostKeyCallbackExample.go:78:28:78:35 | callback | provenance | |
|
| InsecureHostKeyCallbackExample.go:68:78:80:1 | SSA def(callback) | InsecureHostKeyCallbackExample.go:78:28:78:35 | callback | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:94:3:94:43 | ... := ...[0] | InsecureHostKeyCallbackExample.go:95:28:95:35 | callback | provenance | |
|
| InsecureHostKeyCallbackExample.go:94:3:94:43 | extract:0 ... := ... | InsecureHostKeyCallbackExample.go:95:28:95:35 | callback | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:102:22:105:4 | type conversion | InsecureHostKeyCallbackExample.go:107:35:107:50 | insecureCallback | provenance | |
|
| InsecureHostKeyCallbackExample.go:102:22:105:4 | type conversion | InsecureHostKeyCallbackExample.go:107:35:107:50 | insecureCallback | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:103:3:105:3 | function literal | InsecureHostKeyCallbackExample.go:102:22:105:4 | type conversion | provenance | |
|
| InsecureHostKeyCallbackExample.go:103:3:105:3 | function literal | InsecureHostKeyCallbackExample.go:102:22:105:4 | type conversion | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:107:35:107:50 | insecureCallback | InsecureHostKeyCallbackExample.go:58:39:58:46 | SSA def(callback) | provenance | |
|
| InsecureHostKeyCallbackExample.go:107:35:107:50 | insecureCallback | InsecureHostKeyCallbackExample.go:58:69:64:1 | SSA def(callback) | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:109:31:115:4 | type conversion | InsecureHostKeyCallbackExample.go:117:35:117:59 | potentiallySecureCallback | provenance | |
|
| InsecureHostKeyCallbackExample.go:109:31:115:4 | type conversion | InsecureHostKeyCallbackExample.go:117:35:117:59 | potentiallySecureCallback | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:109:31:115:4 | type conversion | InsecureHostKeyCallbackExample.go:120:44:120:68 | potentiallySecureCallback | provenance | |
|
| InsecureHostKeyCallbackExample.go:109:31:115:4 | type conversion | InsecureHostKeyCallbackExample.go:120:44:120:68 | potentiallySecureCallback | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:110:3:115:3 | function literal | InsecureHostKeyCallbackExample.go:109:31:115:4 | type conversion | provenance | |
|
| InsecureHostKeyCallbackExample.go:110:3:115:3 | function literal | InsecureHostKeyCallbackExample.go:109:31:115:4 | type conversion | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:117:35:117:59 | potentiallySecureCallback | InsecureHostKeyCallbackExample.go:58:39:58:46 | SSA def(callback) | provenance | |
|
| InsecureHostKeyCallbackExample.go:117:35:117:59 | potentiallySecureCallback | InsecureHostKeyCallbackExample.go:58:69:64:1 | SSA def(callback) | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:118:35:118:61 | call to InsecureIgnoreHostKey | InsecureHostKeyCallbackExample.go:58:39:58:46 | SSA def(callback) | provenance | |
|
| InsecureHostKeyCallbackExample.go:118:35:118:61 | call to InsecureIgnoreHostKey | InsecureHostKeyCallbackExample.go:58:69:64:1 | SSA def(callback) | provenance | |
|
||||||
| InsecureHostKeyCallbackExample.go:120:44:120:68 | potentiallySecureCallback | InsecureHostKeyCallbackExample.go:68:48:68:55 | SSA def(callback) | provenance | |
|
| InsecureHostKeyCallbackExample.go:120:44:120:68 | potentiallySecureCallback | InsecureHostKeyCallbackExample.go:68:78:80:1 | SSA def(callback) | provenance | |
|
||||||
nodes
|
nodes
|
||||||
| InsecureHostKeyCallbackExample.go:15:20:18:5 | type conversion | semmle.label | type conversion |
|
| InsecureHostKeyCallbackExample.go:15:20:18:5 | type conversion | semmle.label | type conversion |
|
||||||
| InsecureHostKeyCallbackExample.go:16:4:18:4 | function literal | semmle.label | function literal |
|
| InsecureHostKeyCallbackExample.go:16:4:18:4 | function literal | semmle.label | function literal |
|
||||||
@@ -29,13 +29,13 @@ nodes
|
|||||||
| InsecureHostKeyCallbackExample.go:39:20:39:27 | callback | semmle.label | callback |
|
| InsecureHostKeyCallbackExample.go:39:20:39:27 | callback | semmle.label | callback |
|
||||||
| InsecureHostKeyCallbackExample.go:45:3:47:3 | function literal | semmle.label | function literal |
|
| InsecureHostKeyCallbackExample.go:45:3:47:3 | function literal | semmle.label | function literal |
|
||||||
| InsecureHostKeyCallbackExample.go:52:20:52:48 | type conversion | semmle.label | type conversion |
|
| InsecureHostKeyCallbackExample.go:52:20:52:48 | type conversion | semmle.label | type conversion |
|
||||||
| InsecureHostKeyCallbackExample.go:58:39:58:46 | SSA def(callback) | semmle.label | SSA def(callback) |
|
| InsecureHostKeyCallbackExample.go:58:69:64:1 | SSA def(callback) | semmle.label | SSA def(callback) |
|
||||||
| InsecureHostKeyCallbackExample.go:62:20:62:27 | callback | semmle.label | callback |
|
| InsecureHostKeyCallbackExample.go:62:20:62:27 | callback | semmle.label | callback |
|
||||||
| InsecureHostKeyCallbackExample.go:68:48:68:55 | SSA def(callback) | semmle.label | SSA def(callback) |
|
| InsecureHostKeyCallbackExample.go:68:78:80:1 | SSA def(callback) | semmle.label | SSA def(callback) |
|
||||||
| InsecureHostKeyCallbackExample.go:76:28:76:54 | call to InsecureIgnoreHostKey | semmle.label | call to InsecureIgnoreHostKey |
|
| InsecureHostKeyCallbackExample.go:76:28:76:54 | call to InsecureIgnoreHostKey | semmle.label | call to InsecureIgnoreHostKey |
|
||||||
| InsecureHostKeyCallbackExample.go:78:28:78:35 | callback | semmle.label | callback |
|
| InsecureHostKeyCallbackExample.go:78:28:78:35 | callback | semmle.label | callback |
|
||||||
| InsecureHostKeyCallbackExample.go:92:28:92:54 | call to InsecureIgnoreHostKey | semmle.label | call to InsecureIgnoreHostKey |
|
| InsecureHostKeyCallbackExample.go:92:28:92:54 | call to InsecureIgnoreHostKey | semmle.label | call to InsecureIgnoreHostKey |
|
||||||
| InsecureHostKeyCallbackExample.go:94:3:94:43 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| InsecureHostKeyCallbackExample.go:94:3:94:43 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| InsecureHostKeyCallbackExample.go:95:28:95:35 | callback | semmle.label | callback |
|
| InsecureHostKeyCallbackExample.go:95:28:95:35 | callback | semmle.label | callback |
|
||||||
| InsecureHostKeyCallbackExample.go:102:22:105:4 | type conversion | semmle.label | type conversion |
|
| InsecureHostKeyCallbackExample.go:102:22:105:4 | type conversion | semmle.label | type conversion |
|
||||||
| InsecureHostKeyCallbackExample.go:103:3:105:3 | function literal | semmle.label | function literal |
|
| InsecureHostKeyCallbackExample.go:103:3:105:3 | function literal | semmle.label | function literal |
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
|
#select
|
||||||
|
| InsufficientKeySize.go:9:31:9:34 | 1024 | InsufficientKeySize.go:9:31:9:34 | 1024 | InsufficientKeySize.go:9:31:9:34 | 1024 | The size of this RSA key should be at least 2048 bits. |
|
||||||
|
| InsufficientKeySize.go:14:31:14:34 | size | InsufficientKeySize.go:13:10:13:13 | 1024 | InsufficientKeySize.go:14:31:14:34 | size | The size of this RSA key should be at least 2048 bits. |
|
||||||
|
| InsufficientKeySize.go:26:31:26:34 | size | InsufficientKeySize.go:18:7:18:10 | 1024 | InsufficientKeySize.go:26:31:26:34 | size | The size of this RSA key should be at least 2048 bits. |
|
||||||
|
| InsufficientKeySize.go:32:32:32:38 | keyBits | InsufficientKeySize.go:30:13:30:16 | 1024 | InsufficientKeySize.go:32:32:32:38 | keyBits | The size of this RSA key should be at least 2048 bits. |
|
||||||
|
| InsufficientKeySize.go:47:32:47:38 | keyBits | InsufficientKeySize.go:44:13:44:16 | 1024 | InsufficientKeySize.go:47:32:47:38 | keyBits | The size of this RSA key should be at least 2048 bits. |
|
||||||
|
| InsufficientKeySize.go:67:31:67:37 | keyBits | InsufficientKeySize.go:61:21:61:24 | 1024 | InsufficientKeySize.go:67:31:67:37 | keyBits | The size of this RSA key should be at least 2048 bits. |
|
||||||
edges
|
edges
|
||||||
| InsufficientKeySize.go:13:10:13:13 | 1024 | InsufficientKeySize.go:14:31:14:34 | size | provenance | |
|
| InsufficientKeySize.go:13:10:13:13 | 1024 | InsufficientKeySize.go:14:31:14:34 | size | provenance | |
|
||||||
| InsufficientKeySize.go:18:7:18:10 | 1024 | InsufficientKeySize.go:25:11:25:14 | SSA def(size) | provenance | |
|
| InsufficientKeySize.go:18:7:18:10 | 1024 | InsufficientKeySize.go:25:21:27:1 | SSA def(size) | provenance | |
|
||||||
| InsufficientKeySize.go:25:11:25:14 | SSA def(size) | InsufficientKeySize.go:26:31:26:34 | size | provenance | |
|
| InsufficientKeySize.go:25:21:27:1 | SSA def(size) | InsufficientKeySize.go:26:31:26:34 | size | provenance | |
|
||||||
| InsufficientKeySize.go:30:13:30:16 | 1024 | InsufficientKeySize.go:32:32:32:38 | keyBits | provenance | |
|
| InsufficientKeySize.go:30:13:30:16 | 1024 | InsufficientKeySize.go:32:32:32:38 | keyBits | provenance | |
|
||||||
| InsufficientKeySize.go:44:13:44:16 | 1024 | InsufficientKeySize.go:47:32:47:38 | keyBits | provenance | |
|
| InsufficientKeySize.go:44:13:44:16 | 1024 | InsufficientKeySize.go:47:32:47:38 | keyBits | provenance | |
|
||||||
| InsufficientKeySize.go:61:21:61:24 | 1024 | InsufficientKeySize.go:67:31:67:37 | keyBits | provenance | |
|
| InsufficientKeySize.go:61:21:61:24 | 1024 | InsufficientKeySize.go:67:31:67:37 | keyBits | provenance | |
|
||||||
@@ -10,7 +17,7 @@ nodes
|
|||||||
| InsufficientKeySize.go:13:10:13:13 | 1024 | semmle.label | 1024 |
|
| InsufficientKeySize.go:13:10:13:13 | 1024 | semmle.label | 1024 |
|
||||||
| InsufficientKeySize.go:14:31:14:34 | size | semmle.label | size |
|
| InsufficientKeySize.go:14:31:14:34 | size | semmle.label | size |
|
||||||
| InsufficientKeySize.go:18:7:18:10 | 1024 | semmle.label | 1024 |
|
| InsufficientKeySize.go:18:7:18:10 | 1024 | semmle.label | 1024 |
|
||||||
| InsufficientKeySize.go:25:11:25:14 | SSA def(size) | semmle.label | SSA def(size) |
|
| InsufficientKeySize.go:25:21:27:1 | SSA def(size) | semmle.label | SSA def(size) |
|
||||||
| InsufficientKeySize.go:26:31:26:34 | size | semmle.label | size |
|
| InsufficientKeySize.go:26:31:26:34 | size | semmle.label | size |
|
||||||
| InsufficientKeySize.go:30:13:30:16 | 1024 | semmle.label | 1024 |
|
| InsufficientKeySize.go:30:13:30:16 | 1024 | semmle.label | 1024 |
|
||||||
| InsufficientKeySize.go:32:32:32:38 | keyBits | semmle.label | keyBits |
|
| InsufficientKeySize.go:32:32:32:38 | keyBits | semmle.label | keyBits |
|
||||||
@@ -19,10 +26,3 @@ nodes
|
|||||||
| InsufficientKeySize.go:61:21:61:24 | 1024 | semmle.label | 1024 |
|
| InsufficientKeySize.go:61:21:61:24 | 1024 | semmle.label | 1024 |
|
||||||
| InsufficientKeySize.go:67:31:67:37 | keyBits | semmle.label | keyBits |
|
| InsufficientKeySize.go:67:31:67:37 | keyBits | semmle.label | keyBits |
|
||||||
subpaths
|
subpaths
|
||||||
#select
|
|
||||||
| InsufficientKeySize.go:9:31:9:34 | 1024 | InsufficientKeySize.go:9:31:9:34 | 1024 | InsufficientKeySize.go:9:31:9:34 | 1024 | The size of this RSA key should be at least 2048 bits. |
|
|
||||||
| InsufficientKeySize.go:14:31:14:34 | size | InsufficientKeySize.go:13:10:13:13 | 1024 | InsufficientKeySize.go:14:31:14:34 | size | The size of this RSA key should be at least 2048 bits. |
|
|
||||||
| InsufficientKeySize.go:26:31:26:34 | size | InsufficientKeySize.go:18:7:18:10 | 1024 | InsufficientKeySize.go:26:31:26:34 | size | The size of this RSA key should be at least 2048 bits. |
|
|
||||||
| InsufficientKeySize.go:32:32:32:38 | keyBits | InsufficientKeySize.go:30:13:30:16 | 1024 | InsufficientKeySize.go:32:32:32:38 | keyBits | The size of this RSA key should be at least 2048 bits. |
|
|
||||||
| InsufficientKeySize.go:47:32:47:38 | keyBits | InsufficientKeySize.go:44:13:44:16 | 1024 | InsufficientKeySize.go:47:32:47:38 | keyBits | The size of this RSA key should be at least 2048 bits. |
|
|
||||||
| InsufficientKeySize.go:67:31:67:37 | keyBits | InsufficientKeySize.go:61:21:61:24 | 1024 | InsufficientKeySize.go:67:31:67:37 | keyBits | The size of this RSA key should be at least 2048 bits. |
|
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
| encryption.go:30:2:30:36 | call to Encrypt | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:30:2:30:36 | call to Encrypt | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:34:2:34:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:34:2:34:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:38:2:38:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:38:2:38:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:42:2:42:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:42:2:42:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:46:2:46:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:46:2:46:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:50:2:50:47 | call to CryptBlocks | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:50:2:50:47 | call to CryptBlocks | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:54:2:54:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:54:2:54:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:56:22:56:91 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:56:22:56:91 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:59:21:59:68 | &... [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:59:21:59:68 | &... [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:59:22:59:68 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:59:22:59:68 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:59:22:59:68 | struct literal [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:59:22:59:68 | struct literal [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:60:10:60:24 | ctrStreamWriter [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:60:10:60:24 | ctrStreamWriter [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:65:2:65:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:65:2:65:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:69:2:69:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | ... := ...[0] | The cryptographic algorithm DES |
|
| encryption.go:69:2:69:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:28:2:28:31 | extract:0 ... := ... | The cryptographic algorithm DES |
|
||||||
| encryption.go:76:2:76:32 | call to Encrypt | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:76:2:76:32 | call to Encrypt | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:80:2:80:38 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:80:2:80:38 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:84:2:84:38 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:84:2:84:38 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:88:2:88:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:88:2:88:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:92:2:92:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:92:2:92:42 | call to Seal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:96:2:96:43 | call to CryptBlocks | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:96:2:96:43 | call to CryptBlocks | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:100:2:100:41 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:100:2:100:41 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:102:22:102:87 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:102:22:102:87 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:105:21:105:68 | &... [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:105:21:105:68 | &... [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:105:22:105:68 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:105:22:105:68 | struct literal | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:105:22:105:68 | struct literal [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:105:22:105:68 | struct literal [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:106:10:106:24 | ctrStreamWriter [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:106:10:106:24 | ctrStreamWriter [postupdate] | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:111:2:111:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:111:2:111:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:115:2:115:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | ... := ...[0] | The cryptographic algorithm TRIPLEDES |
|
| encryption.go:115:2:115:45 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:74:2:74:40 | extract:0 ... := ... | The cryptographic algorithm TRIPLEDES |
|
||||||
| encryption.go:166:2:166:33 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:166:2:166:33 | call to XORKeyStream | The cryptographic algorithm RC4 |
|
| encryption.go:166:2:166:33 | call to XORKeyStream | $@ is broken or weak, and should not be used. | encryption.go:166:2:166:33 | call to XORKeyStream | The cryptographic algorithm RC4 |
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ edges
|
|||||||
| go-jose.v3.go:25:16:25:20 | selection of URL | go-jose.v3.go:25:16:25:28 | call to Query | provenance | Src:MaD:3 MaD:5 |
|
| go-jose.v3.go:25:16:25:20 | selection of URL | go-jose.v3.go:25:16:25:28 | call to Query | provenance | Src:MaD:3 MaD:5 |
|
||||||
| go-jose.v3.go:25:16:25:28 | call to Query | go-jose.v3.go:25:16:25:47 | call to Get | provenance | MaD:6 |
|
| go-jose.v3.go:25:16:25:28 | call to Query | go-jose.v3.go:25:16:25:47 | call to Get | provenance | MaD:6 |
|
||||||
| go-jose.v3.go:25:16:25:47 | call to Get | go-jose.v3.go:26:15:26:25 | signedToken | provenance | |
|
| go-jose.v3.go:25:16:25:47 | call to Get | go-jose.v3.go:26:15:26:25 | signedToken | provenance | |
|
||||||
| go-jose.v3.go:26:15:26:25 | signedToken | go-jose.v3.go:29:19:29:29 | SSA def(signedToken) | provenance | |
|
| go-jose.v3.go:26:15:26:25 | signedToken | go-jose.v3.go:29:39:37:1 | SSA def(signedToken) | provenance | |
|
||||||
| go-jose.v3.go:29:19:29:29 | SSA def(signedToken) | go-jose.v3.go:31:37:31:47 | signedToken | provenance | |
|
| go-jose.v3.go:29:39:37:1 | SSA def(signedToken) | go-jose.v3.go:31:37:31:47 | signedToken | provenance | |
|
||||||
| go-jose.v3.go:31:2:31:48 | ... := ...[0] | go-jose.v3.go:33:12:33:23 | DecodedToken | provenance | Sink:MaD:2 |
|
| go-jose.v3.go:31:2:31:48 | extract:0 ... := ... | go-jose.v3.go:33:12:33:23 | DecodedToken | provenance | Sink:MaD:2 |
|
||||||
| go-jose.v3.go:31:37:31:47 | signedToken | go-jose.v3.go:31:2:31:48 | ... := ...[0] | provenance | MaD:4 |
|
| go-jose.v3.go:31:37:31:47 | signedToken | go-jose.v3.go:31:2:31:48 | extract:0 ... := ... | provenance | MaD:4 |
|
||||||
| golang-jwt-v5.go:28:16:28:20 | selection of URL | golang-jwt-v5.go:28:16:28:28 | call to Query | provenance | Src:MaD:3 MaD:5 |
|
| golang-jwt-v5.go:28:16:28:20 | selection of URL | golang-jwt-v5.go:28:16:28:28 | call to Query | provenance | Src:MaD:3 MaD:5 |
|
||||||
| golang-jwt-v5.go:28:16:28:28 | call to Query | golang-jwt-v5.go:28:16:28:47 | call to Get | provenance | MaD:6 |
|
| golang-jwt-v5.go:28:16:28:28 | call to Query | golang-jwt-v5.go:28:16:28:47 | call to Get | provenance | MaD:6 |
|
||||||
| golang-jwt-v5.go:28:16:28:47 | call to Get | golang-jwt-v5.go:29:25:29:35 | signedToken | provenance | |
|
| golang-jwt-v5.go:28:16:28:47 | call to Get | golang-jwt-v5.go:29:25:29:35 | signedToken | provenance | |
|
||||||
| golang-jwt-v5.go:29:25:29:35 | signedToken | golang-jwt-v5.go:32:29:32:39 | SSA def(signedToken) | provenance | |
|
| golang-jwt-v5.go:29:25:29:35 | signedToken | golang-jwt-v5.go:32:49:40:1 | SSA def(signedToken) | provenance | |
|
||||||
| golang-jwt-v5.go:32:29:32:39 | SSA def(signedToken) | golang-jwt-v5.go:34:58:34:68 | signedToken | provenance | Sink:MaD:1 |
|
| golang-jwt-v5.go:32:49:40:1 | SSA def(signedToken) | golang-jwt-v5.go:34:58:34:68 | signedToken | provenance | Sink:MaD:1 |
|
||||||
models
|
models
|
||||||
| 1 | Sink: github.com/golang-jwt/jwt; Parser; true; ParseUnverified; ; ; Argument[0]; jwt; manual |
|
| 1 | Sink: github.com/golang-jwt/jwt; Parser; true; ParseUnverified; ; ; Argument[0]; jwt; manual |
|
||||||
| 2 | Sink: group:go-jose/jwt; JSONWebToken; true; UnsafeClaimsWithoutVerification; ; ; Argument[receiver]; jwt; manual |
|
| 2 | Sink: group:go-jose/jwt; JSONWebToken; true; UnsafeClaimsWithoutVerification; ; ; Argument[receiver]; jwt; manual |
|
||||||
@@ -26,14 +26,14 @@ nodes
|
|||||||
| go-jose.v3.go:25:16:25:28 | call to Query | semmle.label | call to Query |
|
| go-jose.v3.go:25:16:25:28 | call to Query | semmle.label | call to Query |
|
||||||
| go-jose.v3.go:25:16:25:47 | call to Get | semmle.label | call to Get |
|
| go-jose.v3.go:25:16:25:47 | call to Get | semmle.label | call to Get |
|
||||||
| go-jose.v3.go:26:15:26:25 | signedToken | semmle.label | signedToken |
|
| go-jose.v3.go:26:15:26:25 | signedToken | semmle.label | signedToken |
|
||||||
| go-jose.v3.go:29:19:29:29 | SSA def(signedToken) | semmle.label | SSA def(signedToken) |
|
| go-jose.v3.go:29:39:37:1 | SSA def(signedToken) | semmle.label | SSA def(signedToken) |
|
||||||
| go-jose.v3.go:31:2:31:48 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| go-jose.v3.go:31:2:31:48 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| go-jose.v3.go:31:37:31:47 | signedToken | semmle.label | signedToken |
|
| go-jose.v3.go:31:37:31:47 | signedToken | semmle.label | signedToken |
|
||||||
| go-jose.v3.go:33:12:33:23 | DecodedToken | semmle.label | DecodedToken |
|
| go-jose.v3.go:33:12:33:23 | DecodedToken | semmle.label | DecodedToken |
|
||||||
| golang-jwt-v5.go:28:16:28:20 | selection of URL | semmle.label | selection of URL |
|
| golang-jwt-v5.go:28:16:28:20 | selection of URL | semmle.label | selection of URL |
|
||||||
| golang-jwt-v5.go:28:16:28:28 | call to Query | semmle.label | call to Query |
|
| golang-jwt-v5.go:28:16:28:28 | call to Query | semmle.label | call to Query |
|
||||||
| golang-jwt-v5.go:28:16:28:47 | call to Get | semmle.label | call to Get |
|
| golang-jwt-v5.go:28:16:28:47 | call to Get | semmle.label | call to Get |
|
||||||
| golang-jwt-v5.go:29:25:29:35 | signedToken | semmle.label | signedToken |
|
| golang-jwt-v5.go:29:25:29:35 | signedToken | semmle.label | signedToken |
|
||||||
| golang-jwt-v5.go:32:29:32:39 | SSA def(signedToken) | semmle.label | SSA def(signedToken) |
|
| golang-jwt-v5.go:32:49:40:1 | SSA def(signedToken) | semmle.label | SSA def(signedToken) |
|
||||||
| golang-jwt-v5.go:34:58:34:68 | signedToken | semmle.label | signedToken |
|
| golang-jwt-v5.go:34:58:34:68 | signedToken | semmle.label | signedToken |
|
||||||
subpaths
|
subpaths
|
||||||
|
|||||||
@@ -1,63 +1,76 @@
|
|||||||
#select
|
#select
|
||||||
| BadRedirectCheck.go:4:23:4:37 | ...==... | BadRedirectCheck.go:3:18:3:22 | argument corresponding to redir | main.go:11:25:11:45 | call to sanitizeUrl | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | BadRedirectCheck.go:3:18:3:22 | argument corresponding to redir | this value | main.go:11:25:11:45 | call to sanitizeUrl | redirect |
|
| BadRedirectCheck.go:4:23:4:37 | ...==... | BadRedirectCheck.go:3:39:8:1 | arg:0 block statement | main.go:11:25:11:45 | call to sanitizeUrl | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | BadRedirectCheck.go:3:39:8:1 | arg:0 block statement | this value | main.go:11:25:11:45 | call to sanitizeUrl | redirect |
|
||||||
| BadRedirectCheck.go:4:23:4:37 | ...==... | main.go:10:18:10:25 | argument corresponding to redirect | main.go:11:25:11:45 | call to sanitizeUrl | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:10:18:10:25 | argument corresponding to redirect | this value | main.go:11:25:11:45 | call to sanitizeUrl | redirect |
|
| BadRedirectCheck.go:4:23:4:37 | ...==... | main.go:10:78:12:1 | arg:0 block statement | main.go:11:25:11:45 | call to sanitizeUrl | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:10:78:12:1 | arg:0 block statement | this value | main.go:11:25:11:45 | call to sanitizeUrl | redirect |
|
||||||
| cves.go:11:26:11:38 | ...==... | cves.go:14:23:14:25 | argument corresponding to url | cves.go:16:26:16:28 | url | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | cves.go:14:23:14:25 | argument corresponding to url | this value | cves.go:16:26:16:28 | url | redirect |
|
| cves.go:11:26:11:38 | ...==... | cves.go:14:78:18:1 | arg:0 block statement | cves.go:16:26:16:28 | url | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | cves.go:14:78:18:1 | arg:0 block statement | this value | cves.go:16:26:16:28 | url | redirect |
|
||||||
| cves.go:34:6:34:37 | call to HasPrefix | cves.go:33:14:33:34 | call to Get | cves.go:37:25:37:32 | redirect | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | cves.go:33:14:33:34 | call to Get | this value | cves.go:37:25:37:32 | redirect | redirect |
|
| cves.go:34:6:34:37 | call to HasPrefix | cves.go:33:14:33:34 | call to Get | cves.go:37:25:37:32 | redirect | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | cves.go:33:14:33:34 | call to Get | this value | cves.go:37:25:37:32 | redirect | redirect |
|
||||||
| cves.go:42:6:42:37 | call to HasPrefix | cves.go:41:14:41:34 | call to Get | cves.go:45:25:45:32 | redirect | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | cves.go:41:14:41:34 | call to Get | this value | cves.go:45:25:45:32 | redirect | redirect |
|
| cves.go:42:6:42:37 | call to HasPrefix | cves.go:41:14:41:34 | call to Get | cves.go:45:25:45:32 | redirect | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | cves.go:41:14:41:34 | call to Get | this value | cves.go:45:25:45:32 | redirect | redirect |
|
||||||
| main.go:25:7:25:38 | call to HasPrefix | main.go:32:24:32:26 | argument corresponding to url | main.go:34:26:34:28 | url | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:32:24:32:26 | argument corresponding to url | this value | main.go:34:26:34:28 | url | redirect |
|
| main.go:25:7:25:38 | call to HasPrefix | main.go:32:79:36:1 | arg:0 block statement | main.go:34:26:34:28 | url | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:32:79:36:1 | arg:0 block statement | this value | main.go:34:26:34:28 | url | redirect |
|
||||||
| main.go:69:5:69:22 | ...!=... | main.go:68:17:68:24 | argument corresponding to redirect | main.go:77:25:77:39 | call to getTarget1 | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:68:17:68:24 | argument corresponding to redirect | this value | main.go:77:25:77:39 | call to getTarget1 | redirect |
|
| main.go:69:5:69:22 | ...!=... | main.go:68:41:74:1 | arg:0 block statement | main.go:77:25:77:39 | call to getTarget1 | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:68:41:74:1 | arg:0 block statement | this value | main.go:77:25:77:39 | call to getTarget1 | redirect |
|
||||||
| main.go:69:5:69:22 | ...!=... | main.go:76:19:76:21 | argument corresponding to url | main.go:77:25:77:39 | call to getTarget1 | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:76:19:76:21 | argument corresponding to url | this value | main.go:77:25:77:39 | call to getTarget1 | redirect |
|
| main.go:69:5:69:22 | ...!=... | main.go:76:74:78:1 | arg:0 block statement | main.go:77:25:77:39 | call to getTarget1 | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:76:74:78:1 | arg:0 block statement | this value | main.go:77:25:77:39 | call to getTarget1 | redirect |
|
||||||
| main.go:83:5:83:20 | ...!=... | main.go:87:9:87:14 | selection of Path | main.go:91:25:91:39 | call to getTarget2 | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:87:9:87:14 | selection of Path | this value | main.go:91:25:91:39 | call to getTarget2 | redirect |
|
| main.go:83:5:83:20 | ...!=... | main.go:87:9:87:14 | selection of Path | main.go:91:25:91:39 | call to getTarget2 | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:87:9:87:14 | selection of Path | this value | main.go:91:25:91:39 | call to getTarget2 | redirect |
|
||||||
edges
|
edges
|
||||||
| BadRedirectCheck.go:3:18:3:22 | SSA def(redir) | BadRedirectCheck.go:5:10:5:14 | redir | provenance | |
|
| BadRedirectCheck.go:3:39:8:1 | SSA def(redir) | BadRedirectCheck.go:5:10:5:14 | redir | provenance | |
|
||||||
| BadRedirectCheck.go:3:18:3:22 | argument corresponding to redir | BadRedirectCheck.go:5:10:5:14 | redir | provenance | |
|
| BadRedirectCheck.go:3:39:8:1 | arg:0 block statement | BadRedirectCheck.go:5:10:5:14 | redir | provenance | |
|
||||||
| BadRedirectCheck.go:5:10:5:14 | redir | main.go:11:25:11:45 | call to sanitizeUrl | provenance | Sink:MaD:1 |
|
| BadRedirectCheck.go:5:10:5:14 | redir | main.go:11:25:11:45 | call to sanitizeUrl | provenance | Sink:MaD:1 |
|
||||||
| cves.go:14:23:14:25 | argument corresponding to url | cves.go:16:26:16:28 | url | provenance | Sink:MaD:1 |
|
| cves.go:14:78:18:1 | arg:0 block statement | cves.go:16:26:16:28 | url | provenance | Sink:MaD:1 |
|
||||||
| cves.go:33:14:33:34 | call to Get | cves.go:37:25:37:32 | redirect | provenance | Sink:MaD:1 |
|
| cves.go:33:14:33:34 | call to Get | cves.go:37:25:37:32 | redirect | provenance | Sink:MaD:1 |
|
||||||
| cves.go:41:14:41:34 | call to Get | cves.go:45:25:45:32 | redirect | provenance | Sink:MaD:1 |
|
| cves.go:41:14:41:34 | call to Get | cves.go:45:25:45:32 | redirect | provenance | Sink:MaD:1 |
|
||||||
| main.go:10:18:10:25 | argument corresponding to redirect | main.go:11:37:11:44 | redirect | provenance | |
|
| main.go:10:78:12:1 | arg:0 block statement | main.go:11:37:11:44 | redirect | provenance | |
|
||||||
| main.go:11:37:11:44 | redirect | BadRedirectCheck.go:3:18:3:22 | SSA def(redir) | provenance | |
|
| main.go:11:37:11:44 | redirect | BadRedirectCheck.go:3:39:8:1 | SSA def(redir) | provenance | |
|
||||||
| main.go:11:37:11:44 | redirect | main.go:11:25:11:45 | call to sanitizeUrl | provenance | Sink:MaD:1 |
|
| main.go:11:37:11:44 | redirect | main.go:11:25:11:45 | call to sanitizeUrl | provenance | Sink:MaD:1 |
|
||||||
| main.go:32:24:32:26 | argument corresponding to url | main.go:34:26:34:28 | url | provenance | Sink:MaD:1 |
|
| main.go:32:79:36:1 | arg:0 block statement | main.go:34:26:34:28 | url | provenance | Sink:MaD:1 |
|
||||||
| main.go:68:17:68:24 | SSA def(redirect) | main.go:73:20:73:27 | redirect | provenance | |
|
| main.go:68:41:74:1 | SSA def(redirect) | main.go:73:20:73:27 | redirect | provenance | |
|
||||||
| main.go:68:17:68:24 | argument corresponding to redirect | main.go:73:20:73:27 | redirect | provenance | |
|
| main.go:68:41:74:1 | arg:0 block statement | main.go:73:20:73:27 | redirect | provenance | |
|
||||||
| main.go:73:9:73:28 | call to Clean | main.go:77:25:77:39 | call to getTarget1 | provenance | Sink:MaD:1 |
|
| main.go:73:9:73:28 | call to Clean | main.go:77:25:77:39 | call to getTarget1 | provenance | Sink:MaD:1 |
|
||||||
| main.go:73:20:73:27 | redirect | main.go:73:9:73:28 | call to Clean | provenance | MaD:2 |
|
| main.go:73:20:73:27 | redirect | main.go:73:9:73:28 | call to Clean | provenance | MaD:2 |
|
||||||
| main.go:73:20:73:27 | redirect | main.go:73:9:73:28 | call to Clean | provenance | MaD:2 |
|
| main.go:73:20:73:27 | redirect | main.go:73:9:73:28 | call to Clean | provenance | MaD:2 |
|
||||||
| main.go:76:19:76:21 | argument corresponding to url | main.go:77:36:77:38 | url | provenance | |
|
| main.go:76:74:78:1 | arg:0 block statement | main.go:77:36:77:38 | url | provenance | |
|
||||||
| main.go:77:36:77:38 | url | main.go:68:17:68:24 | SSA def(redirect) | provenance | |
|
| main.go:77:36:77:38 | url | main.go:68:41:74:1 | SSA def(redirect) | provenance | |
|
||||||
| main.go:77:36:77:38 | url | main.go:77:25:77:39 | call to getTarget1 | provenance | MaD:2 Sink:MaD:1 |
|
| main.go:77:36:77:38 | url | main.go:77:25:77:39 | call to getTarget1 | provenance | MaD:2 Sink:MaD:1 |
|
||||||
| main.go:87:9:87:14 | selection of Path | main.go:91:25:91:39 | call to getTarget2 | provenance | Sink:MaD:1 |
|
| main.go:87:9:87:14 | selection of Path | main.go:91:25:91:39 | call to getTarget2 | provenance | Sink:MaD:1 |
|
||||||
models
|
models
|
||||||
| 1 | Sink: net/http; ; false; Redirect; ; ; Argument[2]; url-redirection[0]; manual |
|
| 1 | Sink: net/http; ; false; Redirect; ; ; Argument[2]; url-redirection[0]; manual |
|
||||||
| 2 | Summary: path; ; false; Clean; ; ; Argument[0]; ReturnValue; taint; manual |
|
| 2 | Summary: path; ; false; Clean; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||||
nodes
|
nodes
|
||||||
| BadRedirectCheck.go:3:18:3:22 | SSA def(redir) | semmle.label | SSA def(redir) |
|
| BadRedirectCheck.go:3:39:8:1 | SSA def(redir) | semmle.label | SSA def(redir) |
|
||||||
| BadRedirectCheck.go:3:18:3:22 | argument corresponding to redir | semmle.label | argument corresponding to redir |
|
| BadRedirectCheck.go:3:39:8:1 | arg:0 block statement | semmle.label | arg:0 block statement |
|
||||||
| BadRedirectCheck.go:5:10:5:14 | redir | semmle.label | redir |
|
| BadRedirectCheck.go:5:10:5:14 | redir | semmle.label | redir |
|
||||||
| BadRedirectCheck.go:5:10:5:14 | redir | semmle.label | redir |
|
| BadRedirectCheck.go:5:10:5:14 | redir | semmle.label | redir |
|
||||||
| cves.go:14:23:14:25 | argument corresponding to url | semmle.label | argument corresponding to url |
|
| cves.go:14:78:18:1 | arg:0 block statement | semmle.label | arg:0 block statement |
|
||||||
| cves.go:16:26:16:28 | url | semmle.label | url |
|
| cves.go:16:26:16:28 | url | semmle.label | url |
|
||||||
| cves.go:33:14:33:34 | call to Get | semmle.label | call to Get |
|
| cves.go:33:14:33:34 | call to Get | semmle.label | call to Get |
|
||||||
| cves.go:37:25:37:32 | redirect | semmle.label | redirect |
|
| cves.go:37:25:37:32 | redirect | semmle.label | redirect |
|
||||||
| cves.go:41:14:41:34 | call to Get | semmle.label | call to Get |
|
| cves.go:41:14:41:34 | call to Get | semmle.label | call to Get |
|
||||||
| cves.go:45:25:45:32 | redirect | semmle.label | redirect |
|
| cves.go:45:25:45:32 | redirect | semmle.label | redirect |
|
||||||
| main.go:10:18:10:25 | argument corresponding to redirect | semmle.label | argument corresponding to redirect |
|
| main.go:10:78:12:1 | arg:0 block statement | semmle.label | arg:0 block statement |
|
||||||
| main.go:11:25:11:45 | call to sanitizeUrl | semmle.label | call to sanitizeUrl |
|
| main.go:11:25:11:45 | call to sanitizeUrl | semmle.label | call to sanitizeUrl |
|
||||||
| main.go:11:37:11:44 | redirect | semmle.label | redirect |
|
| main.go:11:37:11:44 | redirect | semmle.label | redirect |
|
||||||
| main.go:32:24:32:26 | argument corresponding to url | semmle.label | argument corresponding to url |
|
| main.go:32:79:36:1 | arg:0 block statement | semmle.label | arg:0 block statement |
|
||||||
| main.go:34:26:34:28 | url | semmle.label | url |
|
| main.go:34:26:34:28 | url | semmle.label | url |
|
||||||
| main.go:68:17:68:24 | SSA def(redirect) | semmle.label | SSA def(redirect) |
|
| main.go:68:41:74:1 | SSA def(redirect) | semmle.label | SSA def(redirect) |
|
||||||
| main.go:68:17:68:24 | argument corresponding to redirect | semmle.label | argument corresponding to redirect |
|
| main.go:68:41:74:1 | arg:0 block statement | semmle.label | arg:0 block statement |
|
||||||
| main.go:73:9:73:28 | call to Clean | semmle.label | call to Clean |
|
| main.go:73:9:73:28 | call to Clean | semmle.label | call to Clean |
|
||||||
| main.go:73:9:73:28 | call to Clean | semmle.label | call to Clean |
|
| main.go:73:9:73:28 | call to Clean | semmle.label | call to Clean |
|
||||||
| main.go:73:20:73:27 | redirect | semmle.label | redirect |
|
| main.go:73:20:73:27 | redirect | semmle.label | redirect |
|
||||||
| main.go:73:20:73:27 | redirect | semmle.label | redirect |
|
| main.go:73:20:73:27 | redirect | semmle.label | redirect |
|
||||||
| main.go:76:19:76:21 | argument corresponding to url | semmle.label | argument corresponding to url |
|
| main.go:76:74:78:1 | arg:0 block statement | semmle.label | arg:0 block statement |
|
||||||
| main.go:77:25:77:39 | call to getTarget1 | semmle.label | call to getTarget1 |
|
| main.go:77:25:77:39 | call to getTarget1 | semmle.label | call to getTarget1 |
|
||||||
| main.go:77:36:77:38 | url | semmle.label | url |
|
| main.go:77:36:77:38 | url | semmle.label | url |
|
||||||
| main.go:87:9:87:14 | selection of Path | semmle.label | selection of Path |
|
| main.go:87:9:87:14 | selection of Path | semmle.label | selection of Path |
|
||||||
| main.go:91:25:91:39 | call to getTarget2 | semmle.label | call to getTarget2 |
|
| main.go:91:25:91:39 | call to getTarget2 | semmle.label | call to getTarget2 |
|
||||||
subpaths
|
subpaths
|
||||||
| main.go:11:37:11:44 | redirect | BadRedirectCheck.go:3:18:3:22 | SSA def(redir) | BadRedirectCheck.go:5:10:5:14 | redir | main.go:11:25:11:45 | call to sanitizeUrl |
|
| main.go:11:37:11:44 | redirect | BadRedirectCheck.go:3:39:8:1 | SSA def(redir) | BadRedirectCheck.go:5:10:5:14 | redir | main.go:11:25:11:45 | call to sanitizeUrl |
|
||||||
| main.go:77:36:77:38 | url | main.go:68:17:68:24 | SSA def(redirect) | main.go:73:9:73:28 | call to Clean | main.go:77:25:77:39 | call to getTarget1 |
|
| main.go:77:36:77:38 | url | main.go:68:41:74:1 | SSA def(redirect) | main.go:73:9:73:28 | call to Clean | main.go:77:25:77:39 | call to getTarget1 |
|
||||||
|
testFailures
|
||||||
|
| BadRedirectCheck.go:3:39:8:1 | arg:0 block statement | Unexpected result: Source |
|
||||||
|
| BadRedirectCheck.go:3:41:3:51 | comment | Missing result: Source |
|
||||||
|
| cves.go:14:78:18:1 | arg:0 block statement | Unexpected result: Source |
|
||||||
|
| cves.go:14:80:14:90 | comment | Missing result: Source |
|
||||||
|
| main.go:10:78:12:1 | arg:0 block statement | Unexpected result: Source |
|
||||||
|
| main.go:10:80:10:90 | comment | Missing result: Source |
|
||||||
|
| main.go:32:79:36:1 | arg:0 block statement | Unexpected result: Source |
|
||||||
|
| main.go:32:81:32:91 | comment | Missing result: Source |
|
||||||
|
| main.go:68:41:74:1 | arg:0 block statement | Unexpected result: Source |
|
||||||
|
| main.go:68:43:68:53 | comment | Missing result: Source |
|
||||||
|
| main.go:76:74:78:1 | arg:0 block statement | Unexpected result: Source |
|
||||||
|
| main.go:76:76:76:86 | comment | Missing result: Source |
|
||||||
|
|||||||
@@ -30,16 +30,16 @@ edges
|
|||||||
| stdlib.go:71:23:71:37 | ...+... | stdlib.go:71:23:71:40 | ...+... | provenance | Config Sink:MaD:1 |
|
| stdlib.go:71:23:71:37 | ...+... | stdlib.go:71:23:71:40 | ...+... | provenance | Config Sink:MaD:1 |
|
||||||
| stdlib.go:93:13:93:18 | selection of Form | stdlib.go:93:13:93:32 | call to Get | provenance | Src:MaD:2 Config |
|
| stdlib.go:93:13:93:18 | selection of Form | stdlib.go:93:13:93:32 | call to Get | provenance | Src:MaD:2 Config |
|
||||||
| stdlib.go:93:13:93:32 | call to Get | stdlib.go:94:3:94:8 | target | provenance | |
|
| stdlib.go:93:13:93:32 | call to Get | stdlib.go:94:3:94:8 | target | provenance | |
|
||||||
| stdlib.go:94:3:94:8 | target | stdlib.go:94:3:94:25 | ... += ... | provenance | Config |
|
| stdlib.go:94:3:94:8 | target | stdlib.go:94:3:94:25 | compound-rhs ... += ... | provenance | Config |
|
||||||
| stdlib.go:94:3:94:25 | ... += ... | stdlib.go:96:23:96:28 | target | provenance | Sink:MaD:1 |
|
| stdlib.go:94:3:94:25 | compound-rhs ... += ... | stdlib.go:96:23:96:28 | target | provenance | Sink:MaD:1 |
|
||||||
| stdlib.go:116:4:116:4 | implicit dereference [postupdate] [URL] | stdlib.go:116:4:116:4 | r [postupdate] [pointer, URL] | provenance | |
|
| stdlib.go:116:4:116:4 | implicit-deref r [postupdate] [URL] | stdlib.go:116:4:116:4 | r [postupdate] [pointer, URL] | provenance | |
|
||||||
| stdlib.go:116:4:116:4 | r [postupdate] [pointer, URL] | stdlib.go:117:24:117:24 | r [pointer, URL] | provenance | |
|
| stdlib.go:116:4:116:4 | r [postupdate] [pointer, URL] | stdlib.go:117:24:117:24 | r [pointer, URL] | provenance | |
|
||||||
| stdlib.go:116:4:116:8 | implicit dereference | stdlib.go:116:4:116:8 | selection of URL [postupdate] | provenance | Config |
|
| stdlib.go:116:4:116:8 | implicit-deref selection of URL | stdlib.go:116:4:116:8 | selection of URL [postupdate] | provenance | Config |
|
||||||
| stdlib.go:116:4:116:8 | selection of URL | stdlib.go:116:4:116:8 | implicit dereference | provenance | Src:MaD:4 Config |
|
| stdlib.go:116:4:116:8 | selection of URL | stdlib.go:116:4:116:8 | implicit-deref selection of URL | provenance | Src:MaD:4 Config |
|
||||||
| stdlib.go:116:4:116:8 | selection of URL [postupdate] | stdlib.go:116:4:116:4 | implicit dereference [postupdate] [URL] | provenance | |
|
| stdlib.go:116:4:116:8 | selection of URL [postupdate] | stdlib.go:116:4:116:4 | implicit-deref r [postupdate] [URL] | provenance | |
|
||||||
| stdlib.go:116:4:116:8 | selection of URL [postupdate] | stdlib.go:116:4:116:8 | implicit dereference | provenance | Config |
|
| stdlib.go:116:4:116:8 | selection of URL [postupdate] | stdlib.go:116:4:116:8 | implicit-deref selection of URL | provenance | Config |
|
||||||
| stdlib.go:117:24:117:24 | implicit dereference [URL] | stdlib.go:117:24:117:28 | selection of URL | provenance | |
|
| stdlib.go:117:24:117:24 | implicit-deref r [URL] | stdlib.go:117:24:117:28 | selection of URL | provenance | |
|
||||||
| stdlib.go:117:24:117:24 | r [pointer, URL] | stdlib.go:117:24:117:24 | implicit dereference [URL] | provenance | |
|
| stdlib.go:117:24:117:24 | r [pointer, URL] | stdlib.go:117:24:117:24 | implicit-deref r [URL] | provenance | |
|
||||||
| stdlib.go:117:24:117:28 | selection of URL | stdlib.go:117:24:117:37 | call to String | provenance | Src:MaD:4 Config Sink:MaD:1 |
|
| stdlib.go:117:24:117:28 | selection of URL | stdlib.go:117:24:117:37 | call to String | provenance | Src:MaD:4 Config Sink:MaD:1 |
|
||||||
| stdlib.go:150:13:150:18 | selection of Form | stdlib.go:150:13:150:32 | call to Get | provenance | Src:MaD:2 Config |
|
| stdlib.go:150:13:150:18 | selection of Form | stdlib.go:150:13:150:32 | call to Get | provenance | Src:MaD:2 Config |
|
||||||
| stdlib.go:150:13:150:32 | call to Get | stdlib.go:156:23:156:28 | target | provenance | Sink:MaD:1 |
|
| stdlib.go:150:13:150:32 | call to Get | stdlib.go:156:23:156:28 | target | provenance | Sink:MaD:1 |
|
||||||
@@ -51,42 +51,42 @@ edges
|
|||||||
| stdlib.go:177:35:177:39 | selection of URL | stdlib.go:177:35:177:52 | call to RequestURI | provenance | Src:MaD:4 Config |
|
| stdlib.go:177:35:177:39 | selection of URL | stdlib.go:177:35:177:52 | call to RequestURI | provenance | Src:MaD:4 Config |
|
||||||
| stdlib.go:177:35:177:52 | call to RequestURI | stdlib.go:177:24:177:52 | ...+... | provenance | Config Sink:MaD:1 |
|
| stdlib.go:177:35:177:52 | call to RequestURI | stdlib.go:177:24:177:52 | ...+... | provenance | Config Sink:MaD:1 |
|
||||||
| stdlib.go:186:13:186:33 | call to FormValue | stdlib.go:188:23:188:28 | target | provenance | Src:MaD:3 Sink:MaD:1 |
|
| stdlib.go:186:13:186:33 | call to FormValue | stdlib.go:188:23:188:28 | target | provenance | Src:MaD:3 Sink:MaD:1 |
|
||||||
| stdlib.go:194:3:194:57 | ... := ...[0] | stdlib.go:196:23:196:28 | target | provenance | |
|
| stdlib.go:194:3:194:57 | extract:0 ... := ... | stdlib.go:196:23:196:28 | target | provenance | |
|
||||||
| stdlib.go:194:36:194:56 | call to FormValue | stdlib.go:194:3:194:57 | ... := ...[0] | provenance | Src:MaD:3 Config |
|
| stdlib.go:194:36:194:56 | call to FormValue | stdlib.go:194:3:194:57 | extract:0 ... := ... | provenance | Src:MaD:3 Config |
|
||||||
| stdlib.go:196:23:196:28 | implicit dereference | stdlib.go:196:23:196:28 | target [postupdate] | provenance | Config |
|
| stdlib.go:196:23:196:28 | implicit-deref target | stdlib.go:196:23:196:28 | target [postupdate] | provenance | Config |
|
||||||
| stdlib.go:196:23:196:28 | implicit dereference | stdlib.go:196:23:196:33 | selection of Path | provenance | Config Sink:MaD:1 |
|
| stdlib.go:196:23:196:28 | implicit-deref target | stdlib.go:196:23:196:33 | selection of Path | provenance | Config Sink:MaD:1 |
|
||||||
| stdlib.go:196:23:196:28 | target | stdlib.go:196:23:196:28 | implicit dereference | provenance | Config |
|
| stdlib.go:196:23:196:28 | target | stdlib.go:196:23:196:28 | implicit-deref target | provenance | Config |
|
||||||
| stdlib.go:196:23:196:28 | target | stdlib.go:196:23:196:33 | selection of Path | provenance | Config Sink:MaD:1 |
|
| stdlib.go:196:23:196:28 | target | stdlib.go:196:23:196:33 | selection of Path | provenance | Config Sink:MaD:1 |
|
||||||
| stdlib.go:196:23:196:28 | target | stdlib.go:198:23:198:28 | target | provenance | |
|
| stdlib.go:196:23:196:28 | target | stdlib.go:198:23:198:28 | target | provenance | |
|
||||||
| stdlib.go:196:23:196:28 | target [postupdate] | stdlib.go:196:23:196:28 | implicit dereference | provenance | Config |
|
| stdlib.go:196:23:196:28 | target [postupdate] | stdlib.go:196:23:196:28 | implicit-deref target | provenance | Config |
|
||||||
| stdlib.go:196:23:196:28 | target [postupdate] | stdlib.go:198:23:198:28 | target | provenance | |
|
| stdlib.go:196:23:196:28 | target [postupdate] | stdlib.go:198:23:198:28 | target | provenance | |
|
||||||
| stdlib.go:198:23:198:28 | target | stdlib.go:198:23:198:42 | call to EscapedPath | provenance | Config Sink:MaD:1 |
|
| stdlib.go:198:23:198:28 | target | stdlib.go:198:23:198:42 | call to EscapedPath | provenance | Config Sink:MaD:1 |
|
||||||
| stdlib.go:210:3:210:3 | implicit dereference [postupdate] | stdlib.go:210:3:210:3 | u [postupdate] | provenance | Config |
|
| stdlib.go:210:3:210:3 | implicit-deref u [postupdate] | stdlib.go:210:3:210:3 | u [postupdate] | provenance | Config |
|
||||||
| stdlib.go:210:3:210:3 | implicit dereference [postupdate] | stdlib.go:210:3:210:3 | u [postupdate] [pointer] | provenance | |
|
| stdlib.go:210:3:210:3 | implicit-deref u [postupdate] | stdlib.go:210:3:210:3 | u [postupdate] [pointer] | provenance | |
|
||||||
| stdlib.go:210:3:210:3 | u [postupdate] | stdlib.go:212:23:212:23 | u | provenance | |
|
| stdlib.go:210:3:210:3 | u [postupdate] | stdlib.go:212:23:212:23 | u | provenance | |
|
||||||
| stdlib.go:210:3:210:3 | u [postupdate] [pointer] | stdlib.go:212:23:212:23 | u [pointer] | provenance | |
|
| stdlib.go:210:3:210:3 | u [postupdate] [pointer] | stdlib.go:212:23:212:23 | u [pointer] | provenance | |
|
||||||
| stdlib.go:210:12:210:30 | call to FormValue | stdlib.go:210:3:210:3 | implicit dereference [postupdate] | provenance | Src:MaD:3 Config |
|
| stdlib.go:210:12:210:30 | call to FormValue | stdlib.go:210:3:210:3 | implicit-deref u [postupdate] | provenance | Src:MaD:3 Config |
|
||||||
| stdlib.go:210:12:210:30 | call to FormValue | stdlib.go:210:3:210:3 | u [postupdate] | provenance | Src:MaD:3 Config |
|
| stdlib.go:210:12:210:30 | call to FormValue | stdlib.go:210:3:210:3 | u [postupdate] | provenance | Src:MaD:3 Config |
|
||||||
| stdlib.go:212:23:212:23 | implicit dereference | stdlib.go:212:23:212:23 | u [postupdate] | provenance | Config |
|
| stdlib.go:212:23:212:23 | implicit-deref u | stdlib.go:212:23:212:23 | u [postupdate] | provenance | Config |
|
||||||
| stdlib.go:212:23:212:23 | implicit dereference | stdlib.go:212:23:212:28 | selection of Path | provenance | Config Sink:MaD:1 |
|
| stdlib.go:212:23:212:23 | implicit-deref u | stdlib.go:212:23:212:28 | selection of Path | provenance | Config Sink:MaD:1 |
|
||||||
| stdlib.go:212:23:212:23 | u | stdlib.go:212:23:212:23 | implicit dereference | provenance | Config |
|
| stdlib.go:212:23:212:23 | u | stdlib.go:212:23:212:23 | implicit-deref u | provenance | Config |
|
||||||
| stdlib.go:212:23:212:23 | u | stdlib.go:212:23:212:28 | selection of Path | provenance | Config Sink:MaD:1 |
|
| stdlib.go:212:23:212:23 | u | stdlib.go:212:23:212:28 | selection of Path | provenance | Config Sink:MaD:1 |
|
||||||
| stdlib.go:212:23:212:23 | u | stdlib.go:214:23:214:23 | u | provenance | |
|
| stdlib.go:212:23:212:23 | u | stdlib.go:214:23:214:23 | u | provenance | |
|
||||||
| stdlib.go:212:23:212:23 | u [pointer] | stdlib.go:212:23:212:23 | implicit dereference | provenance | |
|
| stdlib.go:212:23:212:23 | u [pointer] | stdlib.go:212:23:212:23 | implicit-deref u | provenance | |
|
||||||
| stdlib.go:212:23:212:23 | u [postupdate] | stdlib.go:212:23:212:23 | implicit dereference | provenance | Config |
|
| stdlib.go:212:23:212:23 | u [postupdate] | stdlib.go:212:23:212:23 | implicit-deref u | provenance | Config |
|
||||||
| stdlib.go:212:23:212:23 | u [postupdate] | stdlib.go:214:23:214:23 | u | provenance | |
|
| stdlib.go:212:23:212:23 | u [postupdate] | stdlib.go:214:23:214:23 | u | provenance | |
|
||||||
| stdlib.go:214:23:214:23 | u | stdlib.go:214:23:214:32 | call to String | provenance | Config Sink:MaD:1 |
|
| stdlib.go:214:23:214:23 | u | stdlib.go:214:23:214:32 | call to String | provenance | Config Sink:MaD:1 |
|
||||||
| stdlib.go:257:3:257:3 | implicit dereference [postupdate] | stdlib.go:257:3:257:3 | u [postupdate] | provenance | Config |
|
| stdlib.go:257:3:257:3 | implicit-deref u [postupdate] | stdlib.go:257:3:257:3 | u [postupdate] | provenance | Config |
|
||||||
| stdlib.go:257:3:257:3 | implicit dereference [postupdate] | stdlib.go:257:3:257:3 | u [postupdate] [pointer] | provenance | |
|
| stdlib.go:257:3:257:3 | implicit-deref u [postupdate] | stdlib.go:257:3:257:3 | u [postupdate] [pointer] | provenance | |
|
||||||
| stdlib.go:257:3:257:3 | u [postupdate] | stdlib.go:260:3:260:3 | u | provenance | |
|
| stdlib.go:257:3:257:3 | u [postupdate] | stdlib.go:260:3:260:3 | u | provenance | |
|
||||||
| stdlib.go:257:3:257:3 | u [postupdate] [pointer] | stdlib.go:260:3:260:3 | u [pointer] | provenance | |
|
| stdlib.go:257:3:257:3 | u [postupdate] [pointer] | stdlib.go:260:3:260:3 | u [pointer] | provenance | |
|
||||||
| stdlib.go:257:12:257:30 | call to FormValue | stdlib.go:257:3:257:3 | implicit dereference [postupdate] | provenance | Src:MaD:3 Config |
|
| stdlib.go:257:12:257:30 | call to FormValue | stdlib.go:257:3:257:3 | implicit-deref u [postupdate] | provenance | Src:MaD:3 Config |
|
||||||
| stdlib.go:257:12:257:30 | call to FormValue | stdlib.go:257:3:257:3 | u [postupdate] | provenance | Src:MaD:3 Config |
|
| stdlib.go:257:12:257:30 | call to FormValue | stdlib.go:257:3:257:3 | u [postupdate] | provenance | Src:MaD:3 Config |
|
||||||
| stdlib.go:260:3:260:3 | implicit dereference | stdlib.go:260:3:260:3 | u [postupdate] | provenance | Config |
|
| stdlib.go:260:3:260:3 | implicit-deref u | stdlib.go:260:3:260:3 | u [postupdate] | provenance | Config |
|
||||||
| stdlib.go:260:3:260:3 | u | stdlib.go:260:3:260:3 | implicit dereference | provenance | Config |
|
| stdlib.go:260:3:260:3 | u | stdlib.go:260:3:260:3 | implicit-deref u | provenance | Config |
|
||||||
| stdlib.go:260:3:260:3 | u | stdlib.go:261:23:261:23 | u | provenance | |
|
| stdlib.go:260:3:260:3 | u | stdlib.go:261:23:261:23 | u | provenance | |
|
||||||
| stdlib.go:260:3:260:3 | u [pointer] | stdlib.go:260:3:260:3 | implicit dereference | provenance | |
|
| stdlib.go:260:3:260:3 | u [pointer] | stdlib.go:260:3:260:3 | implicit-deref u | provenance | |
|
||||||
| stdlib.go:260:3:260:3 | u [postupdate] | stdlib.go:260:3:260:3 | implicit dereference | provenance | Config |
|
| stdlib.go:260:3:260:3 | u [postupdate] | stdlib.go:260:3:260:3 | implicit-deref u | provenance | Config |
|
||||||
| stdlib.go:260:3:260:3 | u [postupdate] | stdlib.go:261:23:261:23 | u | provenance | |
|
| stdlib.go:260:3:260:3 | u [postupdate] | stdlib.go:261:23:261:23 | u | provenance | |
|
||||||
| stdlib.go:261:23:261:23 | u | stdlib.go:261:23:261:32 | call to String | provenance | Config Sink:MaD:1 |
|
| stdlib.go:261:23:261:23 | u | stdlib.go:261:23:261:32 | call to String | provenance | Config Sink:MaD:1 |
|
||||||
models
|
models
|
||||||
@@ -118,14 +118,14 @@ nodes
|
|||||||
| stdlib.go:93:13:93:18 | selection of Form | semmle.label | selection of Form |
|
| stdlib.go:93:13:93:18 | selection of Form | semmle.label | selection of Form |
|
||||||
| stdlib.go:93:13:93:32 | call to Get | semmle.label | call to Get |
|
| stdlib.go:93:13:93:32 | call to Get | semmle.label | call to Get |
|
||||||
| stdlib.go:94:3:94:8 | target | semmle.label | target |
|
| stdlib.go:94:3:94:8 | target | semmle.label | target |
|
||||||
| stdlib.go:94:3:94:25 | ... += ... | semmle.label | ... += ... |
|
| stdlib.go:94:3:94:25 | compound-rhs ... += ... | semmle.label | compound-rhs ... += ... |
|
||||||
| stdlib.go:96:23:96:28 | target | semmle.label | target |
|
| stdlib.go:96:23:96:28 | target | semmle.label | target |
|
||||||
| stdlib.go:116:4:116:4 | implicit dereference [postupdate] [URL] | semmle.label | implicit dereference [postupdate] [URL] |
|
| stdlib.go:116:4:116:4 | implicit-deref r [postupdate] [URL] | semmle.label | implicit-deref r [postupdate] [URL] |
|
||||||
| stdlib.go:116:4:116:4 | r [postupdate] [pointer, URL] | semmle.label | r [postupdate] [pointer, URL] |
|
| stdlib.go:116:4:116:4 | r [postupdate] [pointer, URL] | semmle.label | r [postupdate] [pointer, URL] |
|
||||||
| stdlib.go:116:4:116:8 | implicit dereference | semmle.label | implicit dereference |
|
| stdlib.go:116:4:116:8 | implicit-deref selection of URL | semmle.label | implicit-deref selection of URL |
|
||||||
| stdlib.go:116:4:116:8 | selection of URL | semmle.label | selection of URL |
|
| stdlib.go:116:4:116:8 | selection of URL | semmle.label | selection of URL |
|
||||||
| stdlib.go:116:4:116:8 | selection of URL [postupdate] | semmle.label | selection of URL [postupdate] |
|
| stdlib.go:116:4:116:8 | selection of URL [postupdate] | semmle.label | selection of URL [postupdate] |
|
||||||
| stdlib.go:117:24:117:24 | implicit dereference [URL] | semmle.label | implicit dereference [URL] |
|
| stdlib.go:117:24:117:24 | implicit-deref r [URL] | semmle.label | implicit-deref r [URL] |
|
||||||
| stdlib.go:117:24:117:24 | r [pointer, URL] | semmle.label | r [pointer, URL] |
|
| stdlib.go:117:24:117:24 | r [pointer, URL] | semmle.label | r [pointer, URL] |
|
||||||
| stdlib.go:117:24:117:28 | selection of URL | semmle.label | selection of URL |
|
| stdlib.go:117:24:117:28 | selection of URL | semmle.label | selection of URL |
|
||||||
| stdlib.go:117:24:117:37 | call to String | semmle.label | call to String |
|
| stdlib.go:117:24:117:37 | call to String | semmle.label | call to String |
|
||||||
@@ -142,30 +142,30 @@ nodes
|
|||||||
| stdlib.go:177:35:177:52 | call to RequestURI | semmle.label | call to RequestURI |
|
| stdlib.go:177:35:177:52 | call to RequestURI | semmle.label | call to RequestURI |
|
||||||
| stdlib.go:186:13:186:33 | call to FormValue | semmle.label | call to FormValue |
|
| stdlib.go:186:13:186:33 | call to FormValue | semmle.label | call to FormValue |
|
||||||
| stdlib.go:188:23:188:28 | target | semmle.label | target |
|
| stdlib.go:188:23:188:28 | target | semmle.label | target |
|
||||||
| stdlib.go:194:3:194:57 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| stdlib.go:194:3:194:57 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| stdlib.go:194:36:194:56 | call to FormValue | semmle.label | call to FormValue |
|
| stdlib.go:194:36:194:56 | call to FormValue | semmle.label | call to FormValue |
|
||||||
| stdlib.go:196:23:196:28 | implicit dereference | semmle.label | implicit dereference |
|
| stdlib.go:196:23:196:28 | implicit-deref target | semmle.label | implicit-deref target |
|
||||||
| stdlib.go:196:23:196:28 | target | semmle.label | target |
|
| stdlib.go:196:23:196:28 | target | semmle.label | target |
|
||||||
| stdlib.go:196:23:196:28 | target [postupdate] | semmle.label | target [postupdate] |
|
| stdlib.go:196:23:196:28 | target [postupdate] | semmle.label | target [postupdate] |
|
||||||
| stdlib.go:196:23:196:33 | selection of Path | semmle.label | selection of Path |
|
| stdlib.go:196:23:196:33 | selection of Path | semmle.label | selection of Path |
|
||||||
| stdlib.go:198:23:198:28 | target | semmle.label | target |
|
| stdlib.go:198:23:198:28 | target | semmle.label | target |
|
||||||
| stdlib.go:198:23:198:42 | call to EscapedPath | semmle.label | call to EscapedPath |
|
| stdlib.go:198:23:198:42 | call to EscapedPath | semmle.label | call to EscapedPath |
|
||||||
| stdlib.go:210:3:210:3 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
|
| stdlib.go:210:3:210:3 | implicit-deref u [postupdate] | semmle.label | implicit-deref u [postupdate] |
|
||||||
| stdlib.go:210:3:210:3 | u [postupdate] | semmle.label | u [postupdate] |
|
| stdlib.go:210:3:210:3 | u [postupdate] | semmle.label | u [postupdate] |
|
||||||
| stdlib.go:210:3:210:3 | u [postupdate] [pointer] | semmle.label | u [postupdate] [pointer] |
|
| stdlib.go:210:3:210:3 | u [postupdate] [pointer] | semmle.label | u [postupdate] [pointer] |
|
||||||
| stdlib.go:210:12:210:30 | call to FormValue | semmle.label | call to FormValue |
|
| stdlib.go:210:12:210:30 | call to FormValue | semmle.label | call to FormValue |
|
||||||
| stdlib.go:212:23:212:23 | implicit dereference | semmle.label | implicit dereference |
|
| stdlib.go:212:23:212:23 | implicit-deref u | semmle.label | implicit-deref u |
|
||||||
| stdlib.go:212:23:212:23 | u | semmle.label | u |
|
| stdlib.go:212:23:212:23 | u | semmle.label | u |
|
||||||
| stdlib.go:212:23:212:23 | u [pointer] | semmle.label | u [pointer] |
|
| stdlib.go:212:23:212:23 | u [pointer] | semmle.label | u [pointer] |
|
||||||
| stdlib.go:212:23:212:23 | u [postupdate] | semmle.label | u [postupdate] |
|
| stdlib.go:212:23:212:23 | u [postupdate] | semmle.label | u [postupdate] |
|
||||||
| stdlib.go:212:23:212:28 | selection of Path | semmle.label | selection of Path |
|
| stdlib.go:212:23:212:28 | selection of Path | semmle.label | selection of Path |
|
||||||
| stdlib.go:214:23:214:23 | u | semmle.label | u |
|
| stdlib.go:214:23:214:23 | u | semmle.label | u |
|
||||||
| stdlib.go:214:23:214:32 | call to String | semmle.label | call to String |
|
| stdlib.go:214:23:214:32 | call to String | semmle.label | call to String |
|
||||||
| stdlib.go:257:3:257:3 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
|
| stdlib.go:257:3:257:3 | implicit-deref u [postupdate] | semmle.label | implicit-deref u [postupdate] |
|
||||||
| stdlib.go:257:3:257:3 | u [postupdate] | semmle.label | u [postupdate] |
|
| stdlib.go:257:3:257:3 | u [postupdate] | semmle.label | u [postupdate] |
|
||||||
| stdlib.go:257:3:257:3 | u [postupdate] [pointer] | semmle.label | u [postupdate] [pointer] |
|
| stdlib.go:257:3:257:3 | u [postupdate] [pointer] | semmle.label | u [postupdate] [pointer] |
|
||||||
| stdlib.go:257:12:257:30 | call to FormValue | semmle.label | call to FormValue |
|
| stdlib.go:257:12:257:30 | call to FormValue | semmle.label | call to FormValue |
|
||||||
| stdlib.go:260:3:260:3 | implicit dereference | semmle.label | implicit dereference |
|
| stdlib.go:260:3:260:3 | implicit-deref u | semmle.label | implicit-deref u |
|
||||||
| stdlib.go:260:3:260:3 | u | semmle.label | u |
|
| stdlib.go:260:3:260:3 | u | semmle.label | u |
|
||||||
| stdlib.go:260:3:260:3 | u [pointer] | semmle.label | u [pointer] |
|
| stdlib.go:260:3:260:3 | u [pointer] | semmle.label | u [pointer] |
|
||||||
| stdlib.go:260:3:260:3 | u [postupdate] | semmle.label | u [postupdate] |
|
| stdlib.go:260:3:260:3 | u [postupdate] | semmle.label | u [postupdate] |
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ edges
|
|||||||
| UncontrolledAllocationSizeBad.go:11:12:11:24 | call to Query | UncontrolledAllocationSizeBad.go:13:15:13:20 | source | provenance | |
|
| UncontrolledAllocationSizeBad.go:11:12:11:24 | call to Query | UncontrolledAllocationSizeBad.go:13:15:13:20 | source | provenance | |
|
||||||
| UncontrolledAllocationSizeBad.go:13:15:13:20 | source | UncontrolledAllocationSizeBad.go:13:15:13:29 | call to Get | provenance | MaD:3 |
|
| UncontrolledAllocationSizeBad.go:13:15:13:20 | source | UncontrolledAllocationSizeBad.go:13:15:13:29 | call to Get | provenance | MaD:3 |
|
||||||
| UncontrolledAllocationSizeBad.go:13:15:13:29 | call to Get | UncontrolledAllocationSizeBad.go:14:28:14:36 | sourceStr | provenance | |
|
| UncontrolledAllocationSizeBad.go:13:15:13:29 | call to Get | UncontrolledAllocationSizeBad.go:14:28:14:36 | sourceStr | provenance | |
|
||||||
| UncontrolledAllocationSizeBad.go:14:2:14:37 | ... := ...[0] | UncontrolledAllocationSizeBad.go:20:27:20:30 | sink | provenance | |
|
| UncontrolledAllocationSizeBad.go:14:2:14:37 | extract:0 ... := ... | UncontrolledAllocationSizeBad.go:20:27:20:30 | sink | provenance | |
|
||||||
| UncontrolledAllocationSizeBad.go:14:28:14:36 | sourceStr | UncontrolledAllocationSizeBad.go:14:2:14:37 | ... := ...[0] | provenance | Config |
|
| UncontrolledAllocationSizeBad.go:14:28:14:36 | sourceStr | UncontrolledAllocationSizeBad.go:14:2:14:37 | extract:0 ... := ... | provenance | Config |
|
||||||
models
|
models
|
||||||
| 1 | Source: net/http; Request; true; URL; ; ; ; remote; manual |
|
| 1 | Source: net/http; Request; true; URL; ; ; ; remote; manual |
|
||||||
| 2 | Summary: net/url; URL; true; Query; ; ; Argument[receiver]; ReturnValue; taint; manual |
|
| 2 | Summary: net/url; URL; true; Query; ; ; Argument[receiver]; ReturnValue; taint; manual |
|
||||||
@@ -16,7 +16,7 @@ nodes
|
|||||||
| UncontrolledAllocationSizeBad.go:11:12:11:24 | call to Query | semmle.label | call to Query |
|
| UncontrolledAllocationSizeBad.go:11:12:11:24 | call to Query | semmle.label | call to Query |
|
||||||
| UncontrolledAllocationSizeBad.go:13:15:13:20 | source | semmle.label | source |
|
| UncontrolledAllocationSizeBad.go:13:15:13:20 | source | semmle.label | source |
|
||||||
| UncontrolledAllocationSizeBad.go:13:15:13:29 | call to Get | semmle.label | call to Get |
|
| UncontrolledAllocationSizeBad.go:13:15:13:29 | call to Get | semmle.label | call to Get |
|
||||||
| UncontrolledAllocationSizeBad.go:14:2:14:37 | ... := ...[0] | semmle.label | ... := ...[0] |
|
| UncontrolledAllocationSizeBad.go:14:2:14:37 | extract:0 ... := ... | semmle.label | extract:0 ... := ... |
|
||||||
| UncontrolledAllocationSizeBad.go:14:28:14:36 | sourceStr | semmle.label | sourceStr |
|
| UncontrolledAllocationSizeBad.go:14:28:14:36 | sourceStr | semmle.label | sourceStr |
|
||||||
| UncontrolledAllocationSizeBad.go:20:27:20:30 | sink | semmle.label | sink |
|
| UncontrolledAllocationSizeBad.go:20:27:20:30 | sink | semmle.label | sink |
|
||||||
subpaths
|
subpaths
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ edges
|
|||||||
| tst.go:11:13:11:35 | call to FormValue | tst.go:39:11:39:29 | ...+... | provenance | Src:MaD:1 |
|
| tst.go:11:13:11:35 | call to FormValue | tst.go:39:11:39:29 | ...+... | provenance | Src:MaD:1 |
|
||||||
| tst.go:11:13:11:35 | call to FormValue | tst.go:41:11:41:40 | ...+... | provenance | Src:MaD:1 |
|
| tst.go:11:13:11:35 | call to FormValue | tst.go:41:11:41:40 | ...+... | provenance | Src:MaD:1 |
|
||||||
| tst.go:11:13:11:35 | call to FormValue | tst.go:48:11:48:18 | tainted2 | provenance | Src:MaD:1 |
|
| tst.go:11:13:11:35 | call to FormValue | tst.go:48:11:48:18 | tainted2 | provenance | Src:MaD:1 |
|
||||||
| tst.go:48:2:48:2 | implicit dereference [postupdate] | tst.go:48:2:48:2 | u [postupdate] | provenance | |
|
| tst.go:48:2:48:2 | implicit-deref u [postupdate] | tst.go:48:2:48:2 | u [postupdate] | provenance | |
|
||||||
| tst.go:48:2:48:2 | u [postupdate] | tst.go:49:11:49:11 | u | provenance | |
|
| tst.go:48:2:48:2 | u [postupdate] | tst.go:49:11:49:11 | u | provenance | |
|
||||||
| tst.go:48:11:48:18 | tainted2 | tst.go:48:2:48:2 | implicit dereference [postupdate] | provenance | Config |
|
| tst.go:48:11:48:18 | tainted2 | tst.go:48:2:48:2 | implicit-deref u [postupdate] | provenance | Config |
|
||||||
| tst.go:48:11:48:18 | tainted2 | tst.go:48:2:48:2 | u [postupdate] | provenance | Config |
|
| tst.go:48:11:48:18 | tainted2 | tst.go:48:2:48:2 | u [postupdate] | provenance | Config |
|
||||||
| tst.go:49:11:49:11 | u | tst.go:49:11:49:20 | call to String | provenance | MaD:3 |
|
| tst.go:49:11:49:11 | u | tst.go:49:11:49:20 | call to String | provenance | MaD:3 |
|
||||||
| websocket.go:60:21:60:31 | call to Referer | websocket.go:65:27:65:40 | untrustedInput | provenance | Src:MaD:2 |
|
| websocket.go:60:21:60:31 | call to Referer | websocket.go:65:27:65:40 | untrustedInput | provenance | Src:MaD:2 |
|
||||||
@@ -71,7 +71,7 @@ nodes
|
|||||||
| tst.go:37:18:37:24 | tainted | semmle.label | tainted |
|
| tst.go:37:18:37:24 | tainted | semmle.label | tainted |
|
||||||
| tst.go:39:11:39:29 | ...+... | semmle.label | ...+... |
|
| tst.go:39:11:39:29 | ...+... | semmle.label | ...+... |
|
||||||
| tst.go:41:11:41:40 | ...+... | semmle.label | ...+... |
|
| tst.go:41:11:41:40 | ...+... | semmle.label | ...+... |
|
||||||
| tst.go:48:2:48:2 | implicit dereference [postupdate] | semmle.label | implicit dereference [postupdate] |
|
| tst.go:48:2:48:2 | implicit-deref u [postupdate] | semmle.label | implicit-deref u [postupdate] |
|
||||||
| tst.go:48:2:48:2 | u [postupdate] | semmle.label | u [postupdate] |
|
| tst.go:48:2:48:2 | u [postupdate] | semmle.label | u [postupdate] |
|
||||||
| tst.go:48:11:48:18 | tainted2 | semmle.label | tainted2 |
|
| tst.go:48:11:48:18 | tainted2 | semmle.label | tainted2 |
|
||||||
| tst.go:49:11:49:11 | u | semmle.label | u |
|
| tst.go:49:11:49:11 | u | semmle.label | u |
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
import semmle.python.controlflow.internal.AstNodeImpl
|
|
||||||
import ControlFlow::Consistency
|
|
||||||
@@ -9,7 +9,6 @@ private import semmle.python.dataflow.new.internal.DataFlowImplSpecific
|
|||||||
private import semmle.python.dataflow.new.internal.DataFlowDispatch
|
private import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||||
private import semmle.python.dataflow.new.internal.TaintTrackingImplSpecific
|
private import semmle.python.dataflow.new.internal.TaintTrackingImplSpecific
|
||||||
private import codeql.dataflow.internal.DataFlowImplConsistency
|
private import codeql.dataflow.internal.DataFlowImplConsistency
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
|
|
||||||
private module Input implements InputSig<Location, PythonDataFlow> {
|
private module Input implements InputSig<Location, PythonDataFlow> {
|
||||||
private import Private
|
private import Private
|
||||||
@@ -75,7 +74,7 @@ private module Input implements InputSig<Location, PythonDataFlow> {
|
|||||||
// resolve to multiple functions), but we only make _one_ ArgumentNode for each
|
// resolve to multiple functions), but we only make _one_ ArgumentNode for each
|
||||||
// argument in the CallNode, we end up violating this consistency check in those
|
// argument in the CallNode, we end up violating this consistency check in those
|
||||||
// cases. (see `getCallArg` in DataFlowDispatch.qll)
|
// cases. (see `getCallArg` in DataFlowDispatch.qll)
|
||||||
exists(DataFlowCall other, Cfg::CallNode cfgCall | other != call |
|
exists(DataFlowCall other, CallNode cfgCall | other != call |
|
||||||
call.getNode() = cfgCall and
|
call.getNode() = cfgCall and
|
||||||
other.getNode() = cfgCall and
|
other.getNode() = cfgCall and
|
||||||
isArgumentNode(arg, call, _) and
|
isArgumentNode(arg, call, _) and
|
||||||
@@ -91,16 +90,16 @@ private module Input implements InputSig<Location, PythonDataFlow> {
|
|||||||
// allow it instead.
|
// allow it instead.
|
||||||
(
|
(
|
||||||
call.getScope() = attr.getScope() and
|
call.getScope() = attr.getScope() and
|
||||||
any(CfgNode n | n.asCfgNode() = call.getNode().(Cfg::CallNode).getFunction())
|
any(CfgNode n | n.asCfgNode() = call.getNode().(CallNode).getFunction()).getALocalSource() =
|
||||||
.getALocalSource() = attr
|
attr
|
||||||
or
|
or
|
||||||
not exists(call.getScope().(Function).getDefinition()) and
|
not exists(call.getScope().(Function).getDefinition()) and
|
||||||
call.getScope().getScope+() = attr.getScope()
|
call.getScope().getScope+() = attr.getScope()
|
||||||
) and
|
) and
|
||||||
(
|
(
|
||||||
other.getScope() = attr.getScope() and
|
other.getScope() = attr.getScope() and
|
||||||
any(CfgNode n | n.asCfgNode() = other.getNode().(Cfg::CallNode).getFunction())
|
any(CfgNode n | n.asCfgNode() = other.getNode().(CallNode).getFunction()).getALocalSource() =
|
||||||
.getALocalSource() = attr
|
attr
|
||||||
or
|
or
|
||||||
not exists(other.getScope().(Function).getDefinition()) and
|
not exists(other.getScope().(Function).getDefinition()) and
|
||||||
other.getScope().getScope+() = attr.getScope()
|
other.getScope().getScope+() = attr.getScope()
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* A new Python control flow graph implementation has been added under `semmle.python.controlflow.internal.Cfg` (backed by `AstNodeImpl.qll`), built on the shared `codeql.controlflow.ControlFlowGraph` library. It is not yet used by the dataflow library or any production query; the legacy CFG in `semmle/python/Flow.qll` remains the default. The new library is exposed for tests and for upcoming migrations.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* A new SSA adapter has been added under `semmle.python.dataflow.new.internal.SsaImpl`, built on the shared `codeql.ssa.Ssa` library and the new shared CFG (`semmle.python.controlflow.internal.Cfg`). It is not yet used by the dataflow library or any production query; the legacy ESSA SSA in `semmle/python/essa/*` remains the default. The new SSA adapter is exposed for tests and for the upcoming dataflow migration.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: breaking
|
|
||||||
---
|
|
||||||
* The deprecated `AstNode.getAFlowNode()` and `Function.getAReturnValueFlowNode()` predicates now return nodes from the new shared CFG (`Cfg::ControlFlowNode`) rather than from the legacy CFG (`ControlFlowNode`). Callers that still rely on these deprecated APIs and feed the result into legacy-CFG-aware predicates will no longer type-check; migrate to `n.getNode() = e` (or, for return values, the explicit `Return` pattern shown in the deprecation message) to get nodes from the dataflow library's current CFG.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* The new (shared-CFG-based) Python control flow graph now visits parameter and return type annotations as CFG nodes for function definitions, matching the legacy CFG. This restores annotation-based type tracking through framework models such as FastAPI's `Depends()`, Pydantic request models, Starlette `WebSocket` handlers, and any other models that flow a class reference through `Parameter.getAnnotation()` to identify instances of the annotated class.
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/**
|
|
||||||
* @name Print CFG (New)
|
|
||||||
* @description Produces a representation of a file's Control Flow Graph
|
|
||||||
* using the new shared control flow library.
|
|
||||||
* This query is used by the VS Code extension.
|
|
||||||
* @id python/print-cfg
|
|
||||||
* @kind graph
|
|
||||||
* @tags ide-contextual-queries/print-cfg
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import python as Py
|
|
||||||
import semmle.python.controlflow.internal.AstNodeImpl
|
|
||||||
|
|
||||||
external string selectedSourceFile();
|
|
||||||
|
|
||||||
private predicate selectedSourceFileAlias = selectedSourceFile/0;
|
|
||||||
|
|
||||||
external int selectedSourceLine();
|
|
||||||
|
|
||||||
private predicate selectedSourceLineAlias = selectedSourceLine/0;
|
|
||||||
|
|
||||||
external int selectedSourceColumn();
|
|
||||||
|
|
||||||
private predicate selectedSourceColumnAlias = selectedSourceColumn/0;
|
|
||||||
|
|
||||||
module ViewCfgQueryInput implements ControlFlow::ViewCfgQueryInputSig<Py::File> {
|
|
||||||
predicate selectedSourceFile = selectedSourceFileAlias/0;
|
|
||||||
|
|
||||||
predicate selectedSourceLine = selectedSourceLineAlias/0;
|
|
||||||
|
|
||||||
predicate selectedSourceColumn = selectedSourceColumnAlias/0;
|
|
||||||
|
|
||||||
predicate cfgScopeSpan(
|
|
||||||
Ast::Callable callable, Py::File file, int startLine, int startColumn, int endLine,
|
|
||||||
int endColumn
|
|
||||||
) {
|
|
||||||
exists(Py::Scope scope |
|
|
||||||
scope = callable.asScope() and
|
|
||||||
file = scope.getLocation().getFile() and
|
|
||||||
scope.getLocation().hasLocationInfo(_, startLine, startColumn, endLine, endColumn)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
import ControlFlow::ViewCfgQuery<Py::File, ViewCfgQueryInput>
|
|
||||||
@@ -6,9 +6,8 @@
|
|||||||
* directed and labeled; they specify how the components represented by nodes relate to each other.
|
* directed and labeled; they specify how the components represented by nodes relate to each other.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Importing python under the `PY` namespace to avoid pulling in `CallNode` from `Flow.qll` (via `import python`) and thereby having a naming conflict with `API::CallNode`.
|
// Importing python under the `py` namespace to avoid importing `CallNode` from `Flow.qll` and thereby having a naming conflict with `API::CallNode`.
|
||||||
private import python as PY
|
private import python as PY
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
import semmle.python.dataflow.new.DataFlow
|
import semmle.python.dataflow.new.DataFlow
|
||||||
private import semmle.python.internal.CachedStages
|
private import semmle.python.internal.CachedStages
|
||||||
|
|
||||||
@@ -283,7 +282,7 @@ module API {
|
|||||||
index = this.getIndex() and
|
index = this.getIndex() and
|
||||||
(
|
(
|
||||||
// subscripting
|
// subscripting
|
||||||
exists(Cfg::SubscriptNode subscript |
|
exists(PY::SubscriptNode subscript |
|
||||||
subscript.getObject() = this.getAValueReachableFromSource().asCfgNode() and
|
subscript.getObject() = this.getAValueReachableFromSource().asCfgNode() and
|
||||||
subscript.getIndex() = index.asSink().asCfgNode()
|
subscript.getIndex() = index.asSink().asCfgNode()
|
||||||
|
|
|
|
||||||
@@ -291,7 +290,7 @@ module API {
|
|||||||
subscript = result.asSource().asCfgNode()
|
subscript = result.asSource().asCfgNode()
|
||||||
or
|
or
|
||||||
// writing
|
// writing
|
||||||
subscript.(Cfg::DefinitionNode).getValue() = result.asSink().asCfgNode()
|
subscript.(PY::DefinitionNode).getValue() = result.asSink().asCfgNode()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// dictionary literals
|
// dictionary literals
|
||||||
@@ -685,7 +684,7 @@ module API {
|
|||||||
* Ignores relative imports, such as `from ..foo.bar import baz`.
|
* Ignores relative imports, such as `from ..foo.bar import baz`.
|
||||||
*/
|
*/
|
||||||
private predicate imports(DataFlow::CfgNode imp, string name) {
|
private predicate imports(DataFlow::CfgNode imp, string name) {
|
||||||
exists(Cfg::ImportExprNode iexpr |
|
exists(PY::ImportExprNode iexpr |
|
||||||
imp.getNode() = iexpr and
|
imp.getNode() = iexpr and
|
||||||
not iexpr.getNode().isRelative() and
|
not iexpr.getNode().isRelative() and
|
||||||
name = iexpr.getNode().getImportedModuleName()
|
name = iexpr.getNode().getImportedModuleName()
|
||||||
@@ -776,7 +775,7 @@ module API {
|
|||||||
// list literals, from `x` to `[x]`
|
// list literals, from `x` to `[x]`
|
||||||
// TODO: once convenient, this should be done at a higher level than the AST,
|
// TODO: once convenient, this should be done at a higher level than the AST,
|
||||||
// at least at the CFG layer, to take splitting into account.
|
// at least at the CFG layer, to take splitting into account.
|
||||||
// Also consider `Cfg::SequenceNode` for generality.
|
// Also consider `SequenceNode for generality.
|
||||||
exists(PY::List list | list = pred.(DataFlow::ExprNode).getNode().getNode() |
|
exists(PY::List list | list = pred.(DataFlow::ExprNode).getNode().getNode() |
|
||||||
rhs.(DataFlow::ExprNode).getNode().getNode() = list.getAnElt() and
|
rhs.(DataFlow::ExprNode).getNode().getNode() = list.getAnElt() and
|
||||||
lbl = Label::subscript()
|
lbl = Label::subscript()
|
||||||
@@ -806,7 +805,7 @@ module API {
|
|||||||
subscript = trackUseNode(src).getSubscript(index)
|
subscript = trackUseNode(src).getSubscript(index)
|
||||||
|
|
|
|
||||||
// from `x` to a definition of `x[...]`
|
// from `x` to a definition of `x[...]`
|
||||||
rhs.asCfgNode() = subscript.asCfgNode().(Cfg::DefinitionNode).getValue() and
|
rhs.asCfgNode() = subscript.asCfgNode().(PY::DefinitionNode).getValue() and
|
||||||
lbl = Label::subscript()
|
lbl = Label::subscript()
|
||||||
or
|
or
|
||||||
// from `x` to `"key"` in `x["key"]`
|
// from `x` to `"key"` in `x["key"]`
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ module;
|
|||||||
|
|
||||||
import python
|
import python
|
||||||
private import semmle.python.internal.CachedStages
|
private import semmle.python.internal.CachedStages
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
|
|
||||||
/** A syntactic node (Class, Function, Module, Expr, Stmt or Comprehension) corresponding to a flow node */
|
/** A syntactic node (Class, Function, Module, Expr, Stmt or Comprehension) corresponding to a flow node */
|
||||||
abstract class AstNode extends AstNode_ {
|
abstract class AstNode extends AstNode_ {
|
||||||
@@ -20,16 +19,17 @@ abstract class AstNode extends AstNode_ {
|
|||||||
/**
|
/**
|
||||||
* DEPRECATED: use `ControlFlowNode.getNode()` from the other direction instead;
|
* DEPRECATED: use `ControlFlowNode.getNode()` from the other direction instead;
|
||||||
* that is, replace `e.getAFlowNode() = n` with `n.getNode() = e`. This API is
|
* that is, replace `e.getAFlowNode() = n` with `n.getNode() = e`. This API is
|
||||||
* being removed to untangle the AST and CFG hierarchies.
|
* being removed to untangle the AST and CFG hierarchies in preparation for
|
||||||
|
* migrating the dataflow library off the legacy CFG.
|
||||||
*
|
*
|
||||||
* Gets a flow node corresponding directly to this node, from the new
|
* Gets a flow node corresponding directly to this node.
|
||||||
* (shared) CFG. NOTE: For some statements and other purely syntactic
|
* NOTE: For some statements and other purely syntactic elements,
|
||||||
* elements, there may not be a `ControlFlowNode`.
|
* there may not be a `ControlFlowNode`.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
deprecated Cfg::ControlFlowNode getAFlowNode() {
|
deprecated ControlFlowNode getAFlowNode() {
|
||||||
Stages::AST::ref() and
|
Stages::AST::ref() and
|
||||||
result.getNode() = this
|
py_flow_bb_node(result, this, _, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the location for this AST node */
|
/** Gets the location for this AST node */
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import semmle.python.dataflow.new.DataFlow
|
private import semmle.python.dataflow.new.DataFlow
|
||||||
private import semmle.python.dataflow.new.internal.DataFlowImplSpecific
|
private import semmle.python.dataflow.new.internal.DataFlowImplSpecific
|
||||||
private import semmle.python.dataflow.new.RemoteFlowSources
|
private import semmle.python.dataflow.new.RemoteFlowSources
|
||||||
@@ -215,7 +214,7 @@ module Path {
|
|||||||
SafeAccessCheck() { this = DataFlow::BarrierGuard<safeAccessCheck/3>::getABarrierNode() }
|
SafeAccessCheck() { this = DataFlow::BarrierGuard<safeAccessCheck/3>::getABarrierNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate safeAccessCheck(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) {
|
private predicate safeAccessCheck(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) {
|
||||||
g.(SafeAccessCheck::Range).checks(node, branch)
|
g.(SafeAccessCheck::Range).checks(node, branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +223,7 @@ module Path {
|
|||||||
/** A data-flow node that checks that a path is safe to access in some way, for example by having a controlled prefix. */
|
/** A data-flow node that checks that a path is safe to access in some way, for example by having a controlled prefix. */
|
||||||
abstract class Range extends DataFlow::GuardNode {
|
abstract class Range extends DataFlow::GuardNode {
|
||||||
/** Holds if this guard validates `node` upon evaluating to `branch`. */
|
/** Holds if this guard validates `node` upon evaluating to `branch`. */
|
||||||
abstract predicate checks(Cfg::ControlFlowNode node, boolean branch);
|
abstract predicate checks(ControlFlowNode node, boolean branch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ module;
|
|||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.internal.CachedStages
|
private import semmle.python.internal.CachedStages
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
|
|
||||||
/** An expression */
|
/** An expression */
|
||||||
class Expr extends Expr_, AstNode {
|
class Expr extends Expr_, AstNode {
|
||||||
@@ -71,7 +70,7 @@ class Attribute extends Attribute_ {
|
|||||||
/* syntax: Expr.name */
|
/* syntax: Expr.name */
|
||||||
override Expr getASubExpression() { result = this.getObject() }
|
override Expr getASubExpression() { result = this.getObject() }
|
||||||
|
|
||||||
deprecated override Cfg::AttrNode getAFlowNode() { result = super.getAFlowNode() }
|
deprecated override AttrNode getAFlowNode() { result = super.getAFlowNode() }
|
||||||
|
|
||||||
/** Gets the name of this attribute. That is the `name` in `obj.name` */
|
/** Gets the name of this attribute. That is the `name` in `obj.name` */
|
||||||
string getName() { result = Attribute_.super.getAttr() }
|
string getName() { result = Attribute_.super.getAttr() }
|
||||||
@@ -100,7 +99,7 @@ class Subscript extends Subscript_ {
|
|||||||
|
|
||||||
Expr getObject() { result = Subscript_.super.getValue() }
|
Expr getObject() { result = Subscript_.super.getValue() }
|
||||||
|
|
||||||
deprecated override Cfg::SubscriptNode getAFlowNode() { result = super.getAFlowNode() }
|
deprecated override SubscriptNode getAFlowNode() { result = super.getAFlowNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A call expression, such as `func(...)` */
|
/** A call expression, such as `func(...)` */
|
||||||
@@ -116,7 +115,7 @@ class Call extends Call_ {
|
|||||||
|
|
||||||
override string toString() { result = this.getFunc().toString() + "()" }
|
override string toString() { result = this.getFunc().toString() + "()" }
|
||||||
|
|
||||||
deprecated override Cfg::CallNode getAFlowNode() { result = super.getAFlowNode() }
|
deprecated override CallNode getAFlowNode() { result = super.getAFlowNode() }
|
||||||
|
|
||||||
/** Gets a tuple (*) argument of this call. */
|
/** Gets a tuple (*) argument of this call. */
|
||||||
Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() }
|
Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() }
|
||||||
@@ -204,7 +203,7 @@ class IfExp extends IfExp_ {
|
|||||||
result = this.getTest() or result = this.getBody() or result = this.getOrelse()
|
result = this.getTest() or result = this.getBody() or result = this.getOrelse()
|
||||||
}
|
}
|
||||||
|
|
||||||
deprecated override Cfg::IfExprNode getAFlowNode() { result = super.getAFlowNode() }
|
deprecated override IfExprNode getAFlowNode() { result = super.getAFlowNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A starred expression, such as the `*rest` in the assignment `first, *rest = seq` */
|
/** A starred expression, such as the `*rest` in the assignment `first, *rest = seq` */
|
||||||
@@ -414,7 +413,7 @@ class PlaceHolder extends PlaceHolder_ {
|
|||||||
|
|
||||||
override string toString() { result = "$" + this.getId() }
|
override string toString() { result = "$" + this.getId() }
|
||||||
|
|
||||||
deprecated override Cfg::NameNode getAFlowNode() { result = super.getAFlowNode() }
|
deprecated override NameNode getAFlowNode() { result = super.getAFlowNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A tuple expression such as `( 1, 3, 5, 7, 9 )` */
|
/** A tuple expression such as `( 1, 3, 5, 7, 9 )` */
|
||||||
@@ -481,7 +480,7 @@ class Name extends Name_ {
|
|||||||
|
|
||||||
override string toString() { result = this.getId() }
|
override string toString() { result = this.getId() }
|
||||||
|
|
||||||
deprecated override Cfg::NameNode getAFlowNode() { result = super.getAFlowNode() }
|
deprecated override NameNode getAFlowNode() { result = super.getAFlowNode() }
|
||||||
|
|
||||||
override predicate isArtificial() {
|
override predicate isArtificial() {
|
||||||
/* Artificial variable names in comprehensions all start with "." */
|
/* Artificial variable names in comprehensions all start with "." */
|
||||||
@@ -588,7 +587,7 @@ abstract class NameConstant extends Name, ImmutableLiteral {
|
|||||||
|
|
||||||
override predicate isConstant() { any() }
|
override predicate isConstant() { any() }
|
||||||
|
|
||||||
deprecated override Cfg::NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() }
|
deprecated override NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() }
|
||||||
|
|
||||||
override predicate isArtificial() { none() }
|
override predicate isArtificial() { none() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
overlay[local]
|
overlay[local]
|
||||||
module;
|
module;
|
||||||
|
|
||||||
import python as Py
|
import python
|
||||||
private import semmle.python.internal.CachedStages
|
private import semmle.python.internal.CachedStages
|
||||||
private import codeql.controlflow.BasicBlock as BB
|
private import codeql.controlflow.BasicBlock as BB
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ private import codeql.controlflow.BasicBlock as BB
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
private predicate augstore(ControlFlowNode load, ControlFlowNode store) {
|
private predicate augstore(ControlFlowNode load, ControlFlowNode store) {
|
||||||
exists(Py::Expr load_store | exists(Py::AugAssign aa | aa.getTarget() = load_store) |
|
exists(Expr load_store | exists(AugAssign aa | aa.getTarget() = load_store) |
|
||||||
toAst(load) = load_store and
|
toAst(load) = load_store and
|
||||||
toAst(store) = load_store and
|
toAst(store) = load_store and
|
||||||
load.strictlyDominates(store)
|
load.strictlyDominates(store)
|
||||||
@@ -25,7 +25,7 @@ private predicate augstore(ControlFlowNode load, ControlFlowNode store) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A non-dispatched getNode() to avoid negative recursion issues */
|
/** A non-dispatched getNode() to avoid negative recursion issues */
|
||||||
private Py::AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) }
|
private AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A control flow node. Control flow nodes have a many-to-one relation with syntactic nodes,
|
* A control flow node. Control flow nodes have a many-to-one relation with syntactic nodes,
|
||||||
@@ -35,19 +35,19 @@ private Py::AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _)
|
|||||||
class ControlFlowNode extends @py_flow_node {
|
class ControlFlowNode extends @py_flow_node {
|
||||||
/** Whether this control flow node is a load (including those in augmented assignments) */
|
/** Whether this control flow node is a load (including those in augmented assignments) */
|
||||||
predicate isLoad() {
|
predicate isLoad() {
|
||||||
exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this))
|
exists(Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this control flow node is a store (including those in augmented assignments) */
|
/** Whether this control flow node is a store (including those in augmented assignments) */
|
||||||
predicate isStore() {
|
predicate isStore() {
|
||||||
exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this))
|
exists(Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this control flow node is a delete */
|
/** Whether this control flow node is a delete */
|
||||||
predicate isDelete() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) }
|
predicate isDelete() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) }
|
||||||
|
|
||||||
/** Whether this control flow node is a parameter */
|
/** Whether this control flow node is a parameter */
|
||||||
predicate isParameter() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) }
|
predicate isParameter() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) }
|
||||||
|
|
||||||
/** Whether this control flow node is a store in an augmented assignment */
|
/** Whether this control flow node is a store in an augmented assignment */
|
||||||
predicate isAugStore() { augstore(_, this) }
|
predicate isAugStore() { augstore(_, this) }
|
||||||
@@ -57,61 +57,61 @@ class ControlFlowNode extends @py_flow_node {
|
|||||||
|
|
||||||
/** Whether this flow node corresponds to a literal */
|
/** Whether this flow node corresponds to a literal */
|
||||||
predicate isLiteral() {
|
predicate isLiteral() {
|
||||||
toAst(this) instanceof Py::Bytes
|
toAst(this) instanceof Bytes
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::Dict
|
toAst(this) instanceof Dict
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::DictComp
|
toAst(this) instanceof DictComp
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::Set
|
toAst(this) instanceof Set
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::SetComp
|
toAst(this) instanceof SetComp
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::Ellipsis
|
toAst(this) instanceof Ellipsis
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::GeneratorExp
|
toAst(this) instanceof GeneratorExp
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::Lambda
|
toAst(this) instanceof Lambda
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::ListComp
|
toAst(this) instanceof ListComp
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::List
|
toAst(this) instanceof List
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::Num
|
toAst(this) instanceof Num
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::Tuple
|
toAst(this) instanceof Tuple
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::Unicode
|
toAst(this) instanceof Unicode
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::NameConstant
|
toAst(this) instanceof NameConstant
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this flow node corresponds to an attribute expression */
|
/** Whether this flow node corresponds to an attribute expression */
|
||||||
predicate isAttribute() { toAst(this) instanceof Py::Attribute }
|
predicate isAttribute() { toAst(this) instanceof Attribute }
|
||||||
|
|
||||||
/** Whether this flow node corresponds to an subscript expression */
|
/** Whether this flow node corresponds to an subscript expression */
|
||||||
predicate isSubscript() { toAst(this) instanceof Py::Subscript }
|
predicate isSubscript() { toAst(this) instanceof Subscript }
|
||||||
|
|
||||||
/** Whether this flow node corresponds to an import member */
|
/** Whether this flow node corresponds to an import member */
|
||||||
predicate isImportMember() { toAst(this) instanceof Py::ImportMember }
|
predicate isImportMember() { toAst(this) instanceof ImportMember }
|
||||||
|
|
||||||
/** Whether this flow node corresponds to a call */
|
/** Whether this flow node corresponds to a call */
|
||||||
predicate isCall() { toAst(this) instanceof Py::Call }
|
predicate isCall() { toAst(this) instanceof Call }
|
||||||
|
|
||||||
/** Whether this flow node is the first in a module */
|
/** Whether this flow node is the first in a module */
|
||||||
predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Py::Module }
|
predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Module }
|
||||||
|
|
||||||
/** Whether this flow node corresponds to an import */
|
/** Whether this flow node corresponds to an import */
|
||||||
predicate isImport() { toAst(this) instanceof Py::ImportExpr }
|
predicate isImport() { toAst(this) instanceof ImportExpr }
|
||||||
|
|
||||||
/** Whether this flow node corresponds to a conditional expression */
|
/** Whether this flow node corresponds to a conditional expression */
|
||||||
predicate isIfExp() { toAst(this) instanceof Py::IfExp }
|
predicate isIfExp() { toAst(this) instanceof IfExp }
|
||||||
|
|
||||||
/** Whether this flow node corresponds to a function definition expression */
|
/** Whether this flow node corresponds to a function definition expression */
|
||||||
predicate isFunction() { toAst(this) instanceof Py::FunctionExpr }
|
predicate isFunction() { toAst(this) instanceof FunctionExpr }
|
||||||
|
|
||||||
/** Whether this flow node corresponds to a class definition expression */
|
/** Whether this flow node corresponds to a class definition expression */
|
||||||
predicate isClass() { toAst(this) instanceof Py::ClassExpr }
|
predicate isClass() { toAst(this) instanceof ClassExpr }
|
||||||
|
|
||||||
/** Gets a predecessor of this flow node */
|
/** Gets a predecessor of this flow node */
|
||||||
ControlFlowNode getAPredecessor() { this = result.getASuccessor() }
|
ControlFlowNode getAPredecessor() { this = result.getASuccessor() }
|
||||||
@@ -123,25 +123,25 @@ class ControlFlowNode extends @py_flow_node {
|
|||||||
ControlFlowNode getImmediateDominator() { py_idoms(this, result) }
|
ControlFlowNode getImmediateDominator() { py_idoms(this, result) }
|
||||||
|
|
||||||
/** Gets the syntactic element corresponding to this flow node */
|
/** Gets the syntactic element corresponding to this flow node */
|
||||||
Py::AstNode getNode() { py_flow_bb_node(this, result, _, _) }
|
AstNode getNode() { py_flow_bb_node(this, result, _, _) }
|
||||||
|
|
||||||
/** Gets a textual representation of this element. */
|
/** Gets a textual representation of this element. */
|
||||||
cached
|
cached
|
||||||
string toString() {
|
string toString() {
|
||||||
Stages::AST::ref() and
|
Stages::AST::ref() and
|
||||||
// Since modules can have ambigous names, entry nodes can too, if we do not collate them.
|
// Since modules can have ambigous names, entry nodes can too, if we do not collate them.
|
||||||
exists(Py::Scope s | s.getEntryNode() = this |
|
exists(Scope s | s.getEntryNode() = this |
|
||||||
result = "Entry node for " + concat( | | s.toString(), ",")
|
result = "Entry node for " + concat( | | s.toString(), ",")
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(Py::Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString())
|
exists(Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString())
|
||||||
or
|
or
|
||||||
not exists(Py::Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and
|
not exists(Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and
|
||||||
result = "ControlFlowNode for " + this.getNode().toString()
|
result = "ControlFlowNode for " + this.getNode().toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the location of this ControlFlowNode */
|
/** Gets the location of this ControlFlowNode */
|
||||||
Py::Location getLocation() { result = this.getNode().getLocation() }
|
Location getLocation() { result = this.getNode().getLocation() }
|
||||||
|
|
||||||
/** Whether this flow node is the first in its scope */
|
/** Whether this flow node is the first in its scope */
|
||||||
predicate isEntryNode() { py_scope_flow(this, _, -1) }
|
predicate isEntryNode() { py_scope_flow(this, _, -1) }
|
||||||
@@ -151,9 +151,9 @@ class ControlFlowNode extends @py_flow_node {
|
|||||||
|
|
||||||
/** Gets the scope containing this flow node */
|
/** Gets the scope containing this flow node */
|
||||||
cached
|
cached
|
||||||
Py::Scope getScope() {
|
Scope getScope() {
|
||||||
Stages::AST::ref() and
|
Stages::AST::ref() and
|
||||||
if this.getNode() instanceof Py::Scope
|
if this.getNode() instanceof Scope
|
||||||
then
|
then
|
||||||
/* Entry or exit node */
|
/* Entry or exit node */
|
||||||
result = this.getNode()
|
result = this.getNode()
|
||||||
@@ -161,7 +161,7 @@ class ControlFlowNode extends @py_flow_node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the enclosing module */
|
/** Gets the enclosing module */
|
||||||
Py::Module getEnclosingModule() { result = this.getScope().getEnclosingModule() }
|
Module getEnclosingModule() { result = this.getScope().getEnclosingModule() }
|
||||||
|
|
||||||
/** Gets a successor for this node if the relevant condition is True. */
|
/** Gets a successor for this node if the relevant condition is True. */
|
||||||
ControlFlowNode getATrueSuccessor() {
|
ControlFlowNode getATrueSuccessor() {
|
||||||
@@ -188,7 +188,7 @@ class ControlFlowNode extends @py_flow_node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether the scope may be exited as a result of this node raising an exception */
|
/** Whether the scope may be exited as a result of this node raising an exception */
|
||||||
predicate isExceptionalExit(Py::Scope s) { py_scope_flow(this, s, 1) }
|
predicate isExceptionalExit(Scope s) { py_scope_flow(this, s, 1) }
|
||||||
|
|
||||||
/** Whether this node is a normal (non-exceptional) exit */
|
/** Whether this node is a normal (non-exceptional) exit */
|
||||||
predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) }
|
predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) }
|
||||||
@@ -236,7 +236,7 @@ class ControlFlowNode extends @py_flow_node {
|
|||||||
/* join-ordering helper for `getAChild() */
|
/* join-ordering helper for `getAChild() */
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private ControlFlowNode getExprChild(BasicBlock dom) {
|
private ControlFlowNode getExprChild(BasicBlock dom) {
|
||||||
this.getNode().(Py::Expr).getAChildNode() = result.getNode() and
|
this.getNode().(Expr).getAChildNode() = result.getNode() and
|
||||||
result.getBasicBlock().dominates(dom) and
|
result.getBasicBlock().dominates(dom) and
|
||||||
not this instanceof UnaryExprNode
|
not this instanceof UnaryExprNode
|
||||||
}
|
}
|
||||||
@@ -249,16 +249,16 @@ class ControlFlowNode extends @py_flow_node {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
private class AnyNode extends ControlFlowNode {
|
private class AnyNode extends ControlFlowNode {
|
||||||
override Py::AstNode getNode() { result = super.getNode() }
|
override AstNode getNode() { result = super.getNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to a call expression, such as `func(...)` */
|
/** A control flow node corresponding to a call expression, such as `func(...)` */
|
||||||
class CallNode extends ControlFlowNode {
|
class CallNode extends ControlFlowNode {
|
||||||
CallNode() { toAst(this) instanceof Py::Call }
|
CallNode() { toAst(this) instanceof Call }
|
||||||
|
|
||||||
/** Gets the flow node corresponding to the function expression for the call corresponding to this flow node */
|
/** Gets the flow node corresponding to the function expression for the call corresponding to this flow node */
|
||||||
ControlFlowNode getFunction() {
|
ControlFlowNode getFunction() {
|
||||||
exists(Py::Call c |
|
exists(Call c |
|
||||||
this.getNode() = c and
|
this.getNode() = c and
|
||||||
c.getFunc() = result.getNode() and
|
c.getFunc() = result.getNode() and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
@@ -267,7 +267,7 @@ class CallNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** Gets the flow node corresponding to the n'th positional argument of the call corresponding to this flow node */
|
/** Gets the flow node corresponding to the n'th positional argument of the call corresponding to this flow node */
|
||||||
ControlFlowNode getArg(int n) {
|
ControlFlowNode getArg(int n) {
|
||||||
exists(Py::Call c |
|
exists(Call c |
|
||||||
this.getNode() = c and
|
this.getNode() = c and
|
||||||
c.getArg(n) = result.getNode() and
|
c.getArg(n) = result.getNode() and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
@@ -276,7 +276,7 @@ class CallNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** Gets the flow node corresponding to the named argument of the call corresponding to this flow node */
|
/** Gets the flow node corresponding to the named argument of the call corresponding to this flow node */
|
||||||
ControlFlowNode getArgByName(string name) {
|
ControlFlowNode getArgByName(string name) {
|
||||||
exists(Py::Call c, Py::Keyword k |
|
exists(Call c, Keyword k |
|
||||||
this.getNode() = c and
|
this.getNode() = c and
|
||||||
k = c.getANamedArg() and
|
k = c.getANamedArg() and
|
||||||
k.getValue() = result.getNode() and
|
k.getValue() = result.getNode() and
|
||||||
@@ -292,7 +292,7 @@ class CallNode extends ControlFlowNode {
|
|||||||
result = this.getArgByName(_)
|
result = this.getArgByName(_)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Py::Call getNode() { result = super.getNode() }
|
override Call getNode() { result = super.getNode() }
|
||||||
|
|
||||||
predicate isDecoratorCall() {
|
predicate isDecoratorCall() {
|
||||||
this.isClassDecoratorCall()
|
this.isClassDecoratorCall()
|
||||||
@@ -301,11 +301,11 @@ class CallNode extends ControlFlowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate isClassDecoratorCall() {
|
predicate isClassDecoratorCall() {
|
||||||
exists(Py::ClassExpr cls | this.getNode() = cls.getADecoratorCall())
|
exists(ClassExpr cls | this.getNode() = cls.getADecoratorCall())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isFunctionDecoratorCall() {
|
predicate isFunctionDecoratorCall() {
|
||||||
exists(Py::FunctionExpr func | this.getNode() = func.getADecoratorCall())
|
exists(FunctionExpr func | this.getNode() = func.getADecoratorCall())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the first tuple (*) argument of this call, if any. */
|
/** Gets the first tuple (*) argument of this call, if any. */
|
||||||
@@ -323,11 +323,11 @@ class CallNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** A control flow corresponding to an attribute expression, such as `value.attr` */
|
/** A control flow corresponding to an attribute expression, such as `value.attr` */
|
||||||
class AttrNode extends ControlFlowNode {
|
class AttrNode extends ControlFlowNode {
|
||||||
AttrNode() { toAst(this) instanceof Py::Attribute }
|
AttrNode() { toAst(this) instanceof Attribute }
|
||||||
|
|
||||||
/** Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node */
|
/** Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node */
|
||||||
ControlFlowNode getObject() {
|
ControlFlowNode getObject() {
|
||||||
exists(Py::Attribute a |
|
exists(Attribute a |
|
||||||
this.getNode() = a and
|
this.getNode() = a and
|
||||||
a.getObject() = result.getNode() and
|
a.getObject() = result.getNode() and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
@@ -339,7 +339,7 @@ class AttrNode extends ControlFlowNode {
|
|||||||
* with the matching name
|
* with the matching name
|
||||||
*/
|
*/
|
||||||
ControlFlowNode getObject(string name) {
|
ControlFlowNode getObject(string name) {
|
||||||
exists(Py::Attribute a |
|
exists(Attribute a |
|
||||||
this.getNode() = a and
|
this.getNode() = a and
|
||||||
a.getObject() = result.getNode() and
|
a.getObject() = result.getNode() and
|
||||||
a.getName() = name and
|
a.getName() = name and
|
||||||
@@ -348,57 +348,57 @@ class AttrNode extends ControlFlowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the attribute name of the attribute expression corresponding to this flow node */
|
/** Gets the attribute name of the attribute expression corresponding to this flow node */
|
||||||
string getName() { exists(Py::Attribute a | this.getNode() = a and a.getName() = result) }
|
string getName() { exists(Attribute a | this.getNode() = a and a.getName() = result) }
|
||||||
|
|
||||||
override Py::Attribute getNode() { result = super.getNode() }
|
override Attribute getNode() { result = super.getNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to a `from ... import ...` expression */
|
/** A control flow node corresponding to a `from ... import ...` expression */
|
||||||
class ImportMemberNode extends ControlFlowNode {
|
class ImportMemberNode extends ControlFlowNode {
|
||||||
ImportMemberNode() { toAst(this) instanceof Py::ImportMember }
|
ImportMemberNode() { toAst(this) instanceof ImportMember }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the flow node corresponding to the module in the import-member expression corresponding to this flow node,
|
* Gets the flow node corresponding to the module in the import-member expression corresponding to this flow node,
|
||||||
* with the matching name
|
* with the matching name
|
||||||
*/
|
*/
|
||||||
ControlFlowNode getModule(string name) {
|
ControlFlowNode getModule(string name) {
|
||||||
exists(Py::ImportMember i | this.getNode() = i and i.getModule() = result.getNode() |
|
exists(ImportMember i | this.getNode() = i and i.getModule() = result.getNode() |
|
||||||
i.getName() = name and
|
i.getName() = name and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Py::ImportMember getNode() { result = super.getNode() }
|
override ImportMember getNode() { result = super.getNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to an artificial expression representing an import */
|
/** A control flow node corresponding to an artificial expression representing an import */
|
||||||
class ImportExprNode extends ControlFlowNode {
|
class ImportExprNode extends ControlFlowNode {
|
||||||
ImportExprNode() { toAst(this) instanceof Py::ImportExpr }
|
ImportExprNode() { toAst(this) instanceof ImportExpr }
|
||||||
|
|
||||||
override Py::ImportExpr getNode() { result = super.getNode() }
|
override ImportExpr getNode() { result = super.getNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to a `from ... import *` statement */
|
/** A control flow node corresponding to a `from ... import *` statement */
|
||||||
class ImportStarNode extends ControlFlowNode {
|
class ImportStarNode extends ControlFlowNode {
|
||||||
ImportStarNode() { toAst(this) instanceof Py::ImportStar }
|
ImportStarNode() { toAst(this) instanceof ImportStar }
|
||||||
|
|
||||||
/** Gets the flow node corresponding to the module in the import-star corresponding to this flow node */
|
/** Gets the flow node corresponding to the module in the import-star corresponding to this flow node */
|
||||||
ControlFlowNode getModule() {
|
ControlFlowNode getModule() {
|
||||||
exists(Py::ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() |
|
exists(ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() |
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Py::ImportStar getNode() { result = super.getNode() }
|
override ImportStar getNode() { result = super.getNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to a subscript expression, such as `value[slice]` */
|
/** A control flow node corresponding to a subscript expression, such as `value[slice]` */
|
||||||
class SubscriptNode extends ControlFlowNode {
|
class SubscriptNode extends ControlFlowNode {
|
||||||
SubscriptNode() { toAst(this) instanceof Py::Subscript }
|
SubscriptNode() { toAst(this) instanceof Subscript }
|
||||||
|
|
||||||
/** flow node corresponding to the value of the sequence in a subscript operation */
|
/** flow node corresponding to the value of the sequence in a subscript operation */
|
||||||
ControlFlowNode getObject() {
|
ControlFlowNode getObject() {
|
||||||
exists(Py::Subscript s |
|
exists(Subscript s |
|
||||||
this.getNode() = s and
|
this.getNode() = s and
|
||||||
s.getObject() = result.getNode() and
|
s.getObject() = result.getNode() and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
@@ -407,23 +407,23 @@ class SubscriptNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** flow node corresponding to the index in a subscript operation */
|
/** flow node corresponding to the index in a subscript operation */
|
||||||
ControlFlowNode getIndex() {
|
ControlFlowNode getIndex() {
|
||||||
exists(Py::Subscript s |
|
exists(Subscript s |
|
||||||
this.getNode() = s and
|
this.getNode() = s and
|
||||||
s.getIndex() = result.getNode() and
|
s.getIndex() = result.getNode() and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Py::Subscript getNode() { result = super.getNode() }
|
override Subscript getNode() { result = super.getNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to a comparison operation, such as `x<y` */
|
/** A control flow node corresponding to a comparison operation, such as `x<y` */
|
||||||
class CompareNode extends ControlFlowNode {
|
class CompareNode extends ControlFlowNode {
|
||||||
CompareNode() { toAst(this) instanceof Py::Compare }
|
CompareNode() { toAst(this) instanceof Compare }
|
||||||
|
|
||||||
/** Whether left and right are a pair of operands for this comparison */
|
/** Whether left and right are a pair of operands for this comparison */
|
||||||
predicate operands(ControlFlowNode left, Py::Cmpop op, ControlFlowNode right) {
|
predicate operands(ControlFlowNode left, Cmpop op, ControlFlowNode right) {
|
||||||
exists(Py::Compare c, Py::Expr eleft, Py::Expr eright |
|
exists(Compare c, Expr eleft, Expr eright |
|
||||||
this.getNode() = c and left.getNode() = eleft and right.getNode() = eright
|
this.getNode() = c and left.getNode() = eleft and right.getNode() = eright
|
||||||
|
|
|
|
||||||
eleft = c.getLeft() and eright = c.getComparator(0) and op = c.getOp(0)
|
eleft = c.getLeft() and eright = c.getComparator(0) and op = c.getOp(0)
|
||||||
@@ -436,26 +436,26 @@ class CompareNode extends ControlFlowNode {
|
|||||||
right.getBasicBlock().dominates(this.getBasicBlock())
|
right.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
}
|
}
|
||||||
|
|
||||||
override Py::Compare getNode() { result = super.getNode() }
|
override Compare getNode() { result = super.getNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to a conditional expression such as, `body if test else orelse` */
|
/** A control flow node corresponding to a conditional expression such as, `body if test else orelse` */
|
||||||
class IfExprNode extends ControlFlowNode {
|
class IfExprNode extends ControlFlowNode {
|
||||||
IfExprNode() { toAst(this) instanceof Py::IfExp }
|
IfExprNode() { toAst(this) instanceof IfExp }
|
||||||
|
|
||||||
/** flow node corresponding to one of the operands of an if-expression */
|
/** flow node corresponding to one of the operands of an if-expression */
|
||||||
ControlFlowNode getAnOperand() { result = this.getAPredecessor() }
|
ControlFlowNode getAnOperand() { result = this.getAPredecessor() }
|
||||||
|
|
||||||
override Py::IfExp getNode() { result = super.getNode() }
|
override IfExp getNode() { result = super.getNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to an assignment expression such as `lhs := rhs`. */
|
/** A control flow node corresponding to an assignment expression such as `lhs := rhs`. */
|
||||||
class AssignmentExprNode extends ControlFlowNode {
|
class AssignmentExprNode extends ControlFlowNode {
|
||||||
AssignmentExprNode() { toAst(this) instanceof Py::AssignExpr }
|
AssignmentExprNode() { toAst(this) instanceof AssignExpr }
|
||||||
|
|
||||||
/** Gets the flow node corresponding to the left-hand side of the assignment expression */
|
/** Gets the flow node corresponding to the left-hand side of the assignment expression */
|
||||||
ControlFlowNode getTarget() {
|
ControlFlowNode getTarget() {
|
||||||
exists(Py::AssignExpr a |
|
exists(AssignExpr a |
|
||||||
this.getNode() = a and
|
this.getNode() = a and
|
||||||
a.getTarget() = result.getNode() and
|
a.getTarget() = result.getNode() and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
@@ -464,27 +464,27 @@ class AssignmentExprNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** Gets the flow node corresponding to the right-hand side of the assignment expression */
|
/** Gets the flow node corresponding to the right-hand side of the assignment expression */
|
||||||
ControlFlowNode getValue() {
|
ControlFlowNode getValue() {
|
||||||
exists(Py::AssignExpr a |
|
exists(AssignExpr a |
|
||||||
this.getNode() = a and
|
this.getNode() = a and
|
||||||
a.getValue() = result.getNode() and
|
a.getValue() = result.getNode() and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Py::AssignExpr getNode() { result = super.getNode() }
|
override AssignExpr getNode() { result = super.getNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to a binary expression, such as `x + y` */
|
/** A control flow node corresponding to a binary expression, such as `x + y` */
|
||||||
class BinaryExprNode extends ControlFlowNode {
|
class BinaryExprNode extends ControlFlowNode {
|
||||||
BinaryExprNode() { toAst(this) instanceof Py::BinaryExpr }
|
BinaryExprNode() { toAst(this) instanceof BinaryExpr }
|
||||||
|
|
||||||
/** flow node corresponding to one of the operands of a binary expression */
|
/** flow node corresponding to one of the operands of a binary expression */
|
||||||
ControlFlowNode getAnOperand() { result = this.getLeft() or result = this.getRight() }
|
ControlFlowNode getAnOperand() { result = this.getLeft() or result = this.getRight() }
|
||||||
|
|
||||||
override Py::BinaryExpr getNode() { result = super.getNode() }
|
override BinaryExpr getNode() { result = super.getNode() }
|
||||||
|
|
||||||
ControlFlowNode getLeft() {
|
ControlFlowNode getLeft() {
|
||||||
exists(Py::BinaryExpr b |
|
exists(BinaryExpr b |
|
||||||
this.getNode() = b and
|
this.getNode() = b and
|
||||||
result.getNode() = b.getLeft() and
|
result.getNode() = b.getLeft() and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
@@ -492,7 +492,7 @@ class BinaryExprNode extends ControlFlowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ControlFlowNode getRight() {
|
ControlFlowNode getRight() {
|
||||||
exists(Py::BinaryExpr b |
|
exists(BinaryExpr b |
|
||||||
this.getNode() = b and
|
this.getNode() = b and
|
||||||
result.getNode() = b.getRight() and
|
result.getNode() = b.getRight() and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
@@ -500,11 +500,11 @@ class BinaryExprNode extends ControlFlowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the operator of this binary expression node. */
|
/** Gets the operator of this binary expression node. */
|
||||||
Py::Operator getOp() { result = this.getNode().getOp() }
|
Operator getOp() { result = this.getNode().getOp() }
|
||||||
|
|
||||||
/** Whether left and right are a pair of operands for this binary expression */
|
/** Whether left and right are a pair of operands for this binary expression */
|
||||||
predicate operands(ControlFlowNode left, Py::Operator op, ControlFlowNode right) {
|
predicate operands(ControlFlowNode left, Operator op, ControlFlowNode right) {
|
||||||
exists(Py::BinaryExpr b, Py::Expr eleft, Py::Expr eright |
|
exists(BinaryExpr b, Expr eleft, Expr eright |
|
||||||
this.getNode() = b and left.getNode() = eleft and right.getNode() = eright
|
this.getNode() = b and left.getNode() = eleft and right.getNode() = eright
|
||||||
|
|
|
|
||||||
eleft = b.getLeft() and eright = b.getRight() and op = b.getOp()
|
eleft = b.getLeft() and eright = b.getRight() and op = b.getOp()
|
||||||
@@ -516,20 +516,20 @@ class BinaryExprNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** A control flow node corresponding to a boolean shortcut (and/or) operation */
|
/** A control flow node corresponding to a boolean shortcut (and/or) operation */
|
||||||
class BoolExprNode extends ControlFlowNode {
|
class BoolExprNode extends ControlFlowNode {
|
||||||
BoolExprNode() { toAst(this) instanceof Py::BoolExpr }
|
BoolExprNode() { toAst(this) instanceof BoolExpr }
|
||||||
|
|
||||||
/** flow node corresponding to one of the operands of a boolean expression */
|
/** flow node corresponding to one of the operands of a boolean expression */
|
||||||
ControlFlowNode getAnOperand() {
|
ControlFlowNode getAnOperand() {
|
||||||
exists(Py::BoolExpr b | this.getNode() = b and result.getNode() = b.getAValue()) and
|
exists(BoolExpr b | this.getNode() = b and result.getNode() = b.getAValue()) and
|
||||||
this.getBasicBlock().dominates(result.getBasicBlock())
|
this.getBasicBlock().dominates(result.getBasicBlock())
|
||||||
}
|
}
|
||||||
|
|
||||||
override Py::BoolExpr getNode() { result = super.getNode() }
|
override BoolExpr getNode() { result = super.getNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to a unary expression: (`+x`), (`-x`) or (`~x`) */
|
/** A control flow node corresponding to a unary expression: (`+x`), (`-x`) or (`~x`) */
|
||||||
class UnaryExprNode extends ControlFlowNode {
|
class UnaryExprNode extends ControlFlowNode {
|
||||||
UnaryExprNode() { toAst(this) instanceof Py::UnaryExpr }
|
UnaryExprNode() { toAst(this) instanceof UnaryExpr }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets flow node corresponding to the operand of a unary expression.
|
* Gets flow node corresponding to the operand of a unary expression.
|
||||||
@@ -540,7 +540,7 @@ class UnaryExprNode extends ControlFlowNode {
|
|||||||
*/
|
*/
|
||||||
ControlFlowNode getOperand() { result = this.getAPredecessor() }
|
ControlFlowNode getOperand() { result = this.getAPredecessor() }
|
||||||
|
|
||||||
override Py::UnaryExpr getNode() { result = super.getNode() }
|
override UnaryExpr getNode() { result = super.getNode() }
|
||||||
|
|
||||||
override ControlFlowNode getAChild() { result = this.getAPredecessor() }
|
override ControlFlowNode getAChild() { result = this.getAPredecessor() }
|
||||||
}
|
}
|
||||||
@@ -555,22 +555,22 @@ class DefinitionNode extends ControlFlowNode {
|
|||||||
cached
|
cached
|
||||||
DefinitionNode() {
|
DefinitionNode() {
|
||||||
Stages::AST::ref() and
|
Stages::AST::ref() and
|
||||||
exists(Py::Assign a | this.getNode() = a.getATarget())
|
exists(Assign a | this.getNode() = a.getATarget())
|
||||||
or
|
or
|
||||||
exists(Py::AssignExpr a | this.getNode() = a.getTarget())
|
exists(AssignExpr a | this.getNode() = a.getTarget())
|
||||||
or
|
or
|
||||||
exists(Py::AnnAssign a | this.getNode() = a.getTarget() and exists(a.getValue()))
|
exists(AnnAssign a | this.getNode() = a.getTarget() and exists(a.getValue()))
|
||||||
or
|
or
|
||||||
exists(Py::Alias a | this.getNode() = a.getAsname())
|
exists(Alias a | this.getNode() = a.getAsname())
|
||||||
or
|
or
|
||||||
augstore(_, this)
|
augstore(_, this)
|
||||||
or
|
or
|
||||||
// `x, y = 1, 2` where LHS is a combination of list or tuples
|
// `x, y = 1, 2` where LHS is a combination of list or tuples
|
||||||
exists(Py::Assign a | this.getNode() = list_or_tuple_nested_element(a.getATarget()))
|
exists(Assign a | this.getNode() = list_or_tuple_nested_element(a.getATarget()))
|
||||||
or
|
or
|
||||||
exists(Py::For for | this.getNode() = for.getTarget())
|
exists(For for | this.getNode() = for.getTarget())
|
||||||
or
|
or
|
||||||
exists(Py::Parameter param | this.getNode() = param.asName() and exists(param.getDefault()))
|
exists(Parameter param | this.getNode() = param.asName() and exists(param.getDefault()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** flow node corresponding to the value assigned for the definition corresponding to this flow node */
|
/** flow node corresponding to the value assigned for the definition corresponding to this flow node */
|
||||||
@@ -584,16 +584,16 @@ class DefinitionNode extends ControlFlowNode {
|
|||||||
// since the default value for a parameter is evaluated in the same basic block as
|
// since the default value for a parameter is evaluated in the same basic block as
|
||||||
// the function definition, but the parameter belongs to the basic block of the function,
|
// the function definition, but the parameter belongs to the basic block of the function,
|
||||||
// there is no dominance relationship between the two.
|
// there is no dominance relationship between the two.
|
||||||
exists(Py::Parameter param | this.getNode() = param.asName())
|
exists(Parameter param | this.getNode() = param.asName())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Py::Expr list_or_tuple_nested_element(Py::Expr list_or_tuple) {
|
private Expr list_or_tuple_nested_element(Expr list_or_tuple) {
|
||||||
exists(Py::Expr elt |
|
exists(Expr elt |
|
||||||
elt = list_or_tuple.(Py::Tuple).getAnElt()
|
elt = list_or_tuple.(Tuple).getAnElt()
|
||||||
or
|
or
|
||||||
elt = list_or_tuple.(Py::List).getAnElt()
|
elt = list_or_tuple.(List).getAnElt()
|
||||||
|
|
|
|
||||||
result = elt
|
result = elt
|
||||||
or
|
or
|
||||||
@@ -603,12 +603,12 @@ private Py::Expr list_or_tuple_nested_element(Py::Expr list_or_tuple) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A control flow node corresponding to a deletion statement, such as `del x`.
|
* A control flow node corresponding to a deletion statement, such as `del x`.
|
||||||
* There can be multiple `DeletionNode`s for each `Py::Delete` such that each
|
* There can be multiple `DeletionNode`s for each `Delete` such that each
|
||||||
* target has own `DeletionNode`. The CFG for `del a, x.y` looks like:
|
* target has own `DeletionNode`. The CFG for `del a, x.y` looks like:
|
||||||
* `NameNode('a') -> DeletionNode -> NameNode('b') -> AttrNode('y') -> DeletionNode`.
|
* `NameNode('a') -> DeletionNode -> NameNode('b') -> AttrNode('y') -> DeletionNode`.
|
||||||
*/
|
*/
|
||||||
class DeletionNode extends ControlFlowNode {
|
class DeletionNode extends ControlFlowNode {
|
||||||
DeletionNode() { toAst(this) instanceof Py::Delete }
|
DeletionNode() { toAst(this) instanceof Delete }
|
||||||
|
|
||||||
/** Gets the unique target of this deletion node. */
|
/** Gets the unique target of this deletion node. */
|
||||||
ControlFlowNode getTarget() { result.getASuccessor() = this }
|
ControlFlowNode getTarget() { result.getASuccessor() = this }
|
||||||
@@ -617,9 +617,9 @@ class DeletionNode extends ControlFlowNode {
|
|||||||
/** A control flow node corresponding to a sequence (tuple or list) literal */
|
/** A control flow node corresponding to a sequence (tuple or list) literal */
|
||||||
abstract class SequenceNode extends ControlFlowNode {
|
abstract class SequenceNode extends ControlFlowNode {
|
||||||
SequenceNode() {
|
SequenceNode() {
|
||||||
toAst(this) instanceof Py::Tuple
|
toAst(this) instanceof Tuple
|
||||||
or
|
or
|
||||||
toAst(this) instanceof Py::List
|
toAst(this) instanceof List
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the control flow node for an element of this sequence */
|
/** Gets the control flow node for an element of this sequence */
|
||||||
@@ -632,11 +632,11 @@ abstract class SequenceNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** A control flow node corresponding to a tuple expression such as `( 1, 3, 5, 7, 9 )` */
|
/** A control flow node corresponding to a tuple expression such as `( 1, 3, 5, 7, 9 )` */
|
||||||
class TupleNode extends SequenceNode {
|
class TupleNode extends SequenceNode {
|
||||||
TupleNode() { toAst(this) instanceof Py::Tuple }
|
TupleNode() { toAst(this) instanceof Tuple }
|
||||||
|
|
||||||
override ControlFlowNode getElement(int n) {
|
override ControlFlowNode getElement(int n) {
|
||||||
Stages::AST::ref() and
|
Stages::AST::ref() and
|
||||||
exists(Py::Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and
|
exists(Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and
|
||||||
(
|
(
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
or
|
or
|
||||||
@@ -647,10 +647,10 @@ class TupleNode extends SequenceNode {
|
|||||||
|
|
||||||
/** A control flow node corresponding to a list expression, such as `[ 1, 3, 5, 7, 9 ]` */
|
/** A control flow node corresponding to a list expression, such as `[ 1, 3, 5, 7, 9 ]` */
|
||||||
class ListNode extends SequenceNode {
|
class ListNode extends SequenceNode {
|
||||||
ListNode() { toAst(this) instanceof Py::List }
|
ListNode() { toAst(this) instanceof List }
|
||||||
|
|
||||||
override ControlFlowNode getElement(int n) {
|
override ControlFlowNode getElement(int n) {
|
||||||
exists(Py::List l | this.getNode() = l and result.getNode() = l.getElt(n)) and
|
exists(List l | this.getNode() = l and result.getNode() = l.getElt(n)) and
|
||||||
(
|
(
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
or
|
or
|
||||||
@@ -661,10 +661,10 @@ class ListNode extends SequenceNode {
|
|||||||
|
|
||||||
/** A control flow node corresponding to a set expression, such as `{ 1, 3, 5, 7, 9 }` */
|
/** A control flow node corresponding to a set expression, such as `{ 1, 3, 5, 7, 9 }` */
|
||||||
class SetNode extends ControlFlowNode {
|
class SetNode extends ControlFlowNode {
|
||||||
SetNode() { toAst(this) instanceof Py::Set }
|
SetNode() { toAst(this) instanceof Set }
|
||||||
|
|
||||||
ControlFlowNode getAnElement() {
|
ControlFlowNode getAnElement() {
|
||||||
exists(Py::Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and
|
exists(Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and
|
||||||
(
|
(
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
or
|
or
|
||||||
@@ -675,20 +675,20 @@ class SetNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** A control flow node corresponding to a dictionary literal, such as `{ 'a': 1, 'b': 2 }` */
|
/** A control flow node corresponding to a dictionary literal, such as `{ 'a': 1, 'b': 2 }` */
|
||||||
class DictNode extends ControlFlowNode {
|
class DictNode extends ControlFlowNode {
|
||||||
DictNode() { toAst(this) instanceof Py::Dict }
|
DictNode() { toAst(this) instanceof Dict }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a key of this dictionary literal node, for those items that have keys
|
* Gets a key of this dictionary literal node, for those items that have keys
|
||||||
* E.g, in {'a':1, **b} this returns only 'a'
|
* E.g, in {'a':1, **b} this returns only 'a'
|
||||||
*/
|
*/
|
||||||
ControlFlowNode getAKey() {
|
ControlFlowNode getAKey() {
|
||||||
exists(Py::Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and
|
exists(Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a value of this dictionary literal node */
|
/** Gets a value of this dictionary literal node */
|
||||||
ControlFlowNode getAValue() {
|
ControlFlowNode getAValue() {
|
||||||
exists(Py::Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and
|
exists(Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -712,23 +712,21 @@ class IterableNode extends ControlFlowNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Py::AstNode assigned_value(Py::Expr lhs) {
|
private AstNode assigned_value(Expr lhs) {
|
||||||
/* lhs = result */
|
/* lhs = result */
|
||||||
exists(Py::Assign a | a.getATarget() = lhs and result = a.getValue())
|
exists(Assign a | a.getATarget() = lhs and result = a.getValue())
|
||||||
or
|
or
|
||||||
/* lhs := result */
|
/* lhs := result */
|
||||||
exists(Py::AssignExpr a | a.getTarget() = lhs and result = a.getValue())
|
exists(AssignExpr a | a.getTarget() = lhs and result = a.getValue())
|
||||||
or
|
or
|
||||||
/* lhs : annotation = result */
|
/* lhs : annotation = result */
|
||||||
exists(Py::AnnAssign a | a.getTarget() = lhs and result = a.getValue())
|
exists(AnnAssign a | a.getTarget() = lhs and result = a.getValue())
|
||||||
or
|
or
|
||||||
/* import result as lhs */
|
/* import result as lhs */
|
||||||
exists(Py::Alias a | a.getAsname() = lhs and result = a.getValue())
|
exists(Alias a | a.getAsname() = lhs and result = a.getValue())
|
||||||
or
|
or
|
||||||
/* lhs += x => result = (lhs + x) */
|
/* lhs += x => result = (lhs + x) */
|
||||||
exists(Py::AugAssign a, Py::BinaryExpr b |
|
exists(AugAssign a, BinaryExpr b | b = a.getOperation() and result = b and lhs = b.getLeft())
|
||||||
b = a.getOperation() and result = b and lhs = b.getLeft()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
/*
|
/*
|
||||||
* ..., lhs, ... = ..., result, ...
|
* ..., lhs, ... = ..., result, ...
|
||||||
@@ -736,31 +734,31 @@ private Py::AstNode assigned_value(Py::Expr lhs) {
|
|||||||
* ..., (..., lhs, ...), ... = ..., (..., result, ...), ...
|
* ..., (..., lhs, ...), ... = ..., (..., result, ...), ...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exists(Py::Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result))
|
exists(Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result))
|
||||||
or
|
or
|
||||||
/* for lhs in seq: => `result` is the `for` node, representing the `iter(next(seq))` operation. */
|
/* for lhs in seq: => `result` is the `for` node, representing the `iter(next(seq))` operation. */
|
||||||
result.(Py::For).getTarget() = lhs
|
result.(For).getTarget() = lhs
|
||||||
or
|
or
|
||||||
exists(Py::Parameter param | lhs = param.asName() and result = param.getDefault())
|
exists(Parameter param | lhs = param.asName() and result = param.getDefault())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate nested_sequence_assign(
|
predicate nested_sequence_assign(
|
||||||
Py::Expr left_parent, Py::Expr right_parent, Py::Expr left_result, Py::Expr right_result
|
Expr left_parent, Expr right_parent, Expr left_result, Expr right_result
|
||||||
) {
|
) {
|
||||||
exists(Py::Assign a |
|
exists(Assign a |
|
||||||
a.getATarget().getASubExpression*() = left_parent and
|
a.getATarget().getASubExpression*() = left_parent and
|
||||||
a.getValue().getASubExpression*() = right_parent
|
a.getValue().getASubExpression*() = right_parent
|
||||||
) and
|
) and
|
||||||
exists(int i, Py::Expr left_elem, Py::Expr right_elem |
|
exists(int i, Expr left_elem, Expr right_elem |
|
||||||
(
|
(
|
||||||
left_elem = left_parent.(Py::Tuple).getElt(i)
|
left_elem = left_parent.(Tuple).getElt(i)
|
||||||
or
|
or
|
||||||
left_elem = left_parent.(Py::List).getElt(i)
|
left_elem = left_parent.(List).getElt(i)
|
||||||
) and
|
) and
|
||||||
(
|
(
|
||||||
right_elem = right_parent.(Py::Tuple).getElt(i)
|
right_elem = right_parent.(Tuple).getElt(i)
|
||||||
or
|
or
|
||||||
right_elem = right_parent.(Py::List).getElt(i)
|
right_elem = right_parent.(List).getElt(i)
|
||||||
)
|
)
|
||||||
|
|
|
|
||||||
left_result = left_elem and right_result = right_elem
|
left_result = left_elem and right_result = right_elem
|
||||||
@@ -771,9 +769,9 @@ predicate nested_sequence_assign(
|
|||||||
|
|
||||||
/** A flow node for a `for` statement. */
|
/** A flow node for a `for` statement. */
|
||||||
class ForNode extends ControlFlowNode {
|
class ForNode extends ControlFlowNode {
|
||||||
ForNode() { toAst(this) instanceof Py::For }
|
ForNode() { toAst(this) instanceof For }
|
||||||
|
|
||||||
override Py::For getNode() { result = super.getNode() }
|
override For getNode() { result = super.getNode() }
|
||||||
|
|
||||||
/** Holds if this `for` statement causes iteration over `sequence` storing each step of the iteration in `target` */
|
/** Holds if this `for` statement causes iteration over `sequence` storing each step of the iteration in `target` */
|
||||||
predicate iterates(ControlFlowNode target, ControlFlowNode sequence) {
|
predicate iterates(ControlFlowNode target, ControlFlowNode sequence) {
|
||||||
@@ -784,7 +782,7 @@ class ForNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** Gets the sequence node for this `for` statement. */
|
/** Gets the sequence node for this `for` statement. */
|
||||||
ControlFlowNode getSequence() {
|
ControlFlowNode getSequence() {
|
||||||
exists(Py::For for |
|
exists(For for |
|
||||||
toAst(this) = for and
|
toAst(this) = for and
|
||||||
for.getIter() = result.getNode()
|
for.getIter() = result.getNode()
|
||||||
|
|
|
|
||||||
@@ -794,7 +792,7 @@ class ForNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** A possible `target` for this `for` statement, not accounting for loop unrolling */
|
/** A possible `target` for this `for` statement, not accounting for loop unrolling */
|
||||||
private ControlFlowNode possibleTarget() {
|
private ControlFlowNode possibleTarget() {
|
||||||
exists(Py::For for |
|
exists(For for |
|
||||||
toAst(this) = for and
|
toAst(this) = for and
|
||||||
for.getTarget() = result.getNode() and
|
for.getTarget() = result.getNode() and
|
||||||
this.getBasicBlock().dominates(result.getBasicBlock())
|
this.getBasicBlock().dominates(result.getBasicBlock())
|
||||||
@@ -811,11 +809,11 @@ class ForNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** A flow node for a `raise` statement */
|
/** A flow node for a `raise` statement */
|
||||||
class RaiseStmtNode extends ControlFlowNode {
|
class RaiseStmtNode extends ControlFlowNode {
|
||||||
RaiseStmtNode() { toAst(this) instanceof Py::Raise }
|
RaiseStmtNode() { toAst(this) instanceof Raise }
|
||||||
|
|
||||||
/** Gets the control flow node for the exception raised by this raise statement */
|
/** Gets the control flow node for the exception raised by this raise statement */
|
||||||
ControlFlowNode getException() {
|
ControlFlowNode getException() {
|
||||||
exists(Py::Raise r |
|
exists(Raise r |
|
||||||
r = toAst(this) and
|
r = toAst(this) and
|
||||||
r.getException() = toAst(result) and
|
r.getException() = toAst(result) and
|
||||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
@@ -829,36 +827,36 @@ class RaiseStmtNode extends ControlFlowNode {
|
|||||||
*/
|
*/
|
||||||
class NameNode extends ControlFlowNode {
|
class NameNode extends ControlFlowNode {
|
||||||
NameNode() {
|
NameNode() {
|
||||||
exists(Py::Name n | py_flow_bb_node(this, n, _, _))
|
exists(Name n | py_flow_bb_node(this, n, _, _))
|
||||||
or
|
or
|
||||||
exists(Py::PlaceHolder p | py_flow_bb_node(this, p, _, _))
|
exists(PlaceHolder p | py_flow_bb_node(this, p, _, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this flow node defines the variable `v`. */
|
/** Whether this flow node defines the variable `v`. */
|
||||||
predicate defines(Py::Variable v) {
|
predicate defines(Variable v) {
|
||||||
exists(Py::Name d | this.getNode() = d and d.defines(v)) and
|
exists(Name d | this.getNode() = d and d.defines(v)) and
|
||||||
not this.isLoad()
|
not this.isLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this flow node deletes the variable `v`. */
|
/** Whether this flow node deletes the variable `v`. */
|
||||||
predicate deletes(Py::Variable v) { exists(Py::Name d | this.getNode() = d and d.deletes(v)) }
|
predicate deletes(Variable v) { exists(Name d | this.getNode() = d and d.deletes(v)) }
|
||||||
|
|
||||||
/** Whether this flow node uses the variable `v`. */
|
/** Whether this flow node uses the variable `v`. */
|
||||||
predicate uses(Py::Variable v) {
|
predicate uses(Variable v) {
|
||||||
this.isLoad() and
|
this.isLoad() and
|
||||||
exists(Py::Name u | this.getNode() = u and u.uses(v))
|
exists(Name u | this.getNode() = u and u.uses(v))
|
||||||
or
|
or
|
||||||
exists(Py::PlaceHolder u |
|
exists(PlaceHolder u |
|
||||||
this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Py::Load
|
this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Load
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Scopes::use_of_global_variable(this, v.getScope(), v.getId())
|
Scopes::use_of_global_variable(this, v.getScope(), v.getId())
|
||||||
}
|
}
|
||||||
|
|
||||||
string getId() {
|
string getId() {
|
||||||
result = this.getNode().(Py::Name).getId()
|
result = this.getNode().(Name).getId()
|
||||||
or
|
or
|
||||||
result = this.getNode().(Py::PlaceHolder).getId()
|
result = this.getNode().(PlaceHolder).getId()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this is a use of a local variable. */
|
/** Whether this is a use of a local variable. */
|
||||||
@@ -870,39 +868,37 @@ class NameNode extends ControlFlowNode {
|
|||||||
/** Whether this is a use of a global (including builtin) variable. */
|
/** Whether this is a use of a global (including builtin) variable. */
|
||||||
predicate isGlobal() { Scopes::use_of_global_variable(this, _, _) }
|
predicate isGlobal() { Scopes::use_of_global_variable(this, _, _) }
|
||||||
|
|
||||||
predicate isSelf() {
|
predicate isSelf() { exists(SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this) }
|
||||||
exists(Py::SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to a named constant, one of `None`, `True` or `False`. */
|
/** A control flow node corresponding to a named constant, one of `None`, `True` or `False`. */
|
||||||
class NameConstantNode extends NameNode {
|
class NameConstantNode extends NameNode {
|
||||||
NameConstantNode() { exists(Py::NameConstant n | py_flow_bb_node(this, n, _, _)) }
|
NameConstantNode() { exists(NameConstant n | py_flow_bb_node(this, n, _, _)) }
|
||||||
/*
|
/*
|
||||||
* We ought to override uses as well, but that has
|
* We ought to override uses as well, but that has
|
||||||
* a serious performance impact.
|
* a serious performance impact.
|
||||||
* deprecated predicate uses(Py::Variable v) { none() }
|
* deprecated predicate uses(Variable v) { none() }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to a starred expression, `*a`. */
|
/** A control flow node corresponding to a starred expression, `*a`. */
|
||||||
class StarredNode extends ControlFlowNode {
|
class StarredNode extends ControlFlowNode {
|
||||||
StarredNode() { toAst(this) instanceof Py::Starred }
|
StarredNode() { toAst(this) instanceof Starred }
|
||||||
|
|
||||||
ControlFlowNode getValue() { toAst(result) = toAst(this).(Py::Starred).getValue() }
|
ControlFlowNode getValue() { toAst(result) = toAst(this).(Starred).getValue() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The ControlFlowNode for an 'except' statement. */
|
/** The ControlFlowNode for an 'except' statement. */
|
||||||
class ExceptFlowNode extends ControlFlowNode {
|
class ExceptFlowNode extends ControlFlowNode {
|
||||||
ExceptFlowNode() { this.getNode() instanceof Py::ExceptStmt }
|
ExceptFlowNode() { this.getNode() instanceof ExceptStmt }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type handled by this exception handler.
|
* Gets the type handled by this exception handler.
|
||||||
* `Py::ExceptionType` in `except Py::ExceptionType as e:`
|
* `ExceptionType` in `except ExceptionType as e:`
|
||||||
*/
|
*/
|
||||||
ControlFlowNode getType() {
|
ControlFlowNode getType() {
|
||||||
exists(Py::ExceptStmt ex |
|
exists(ExceptStmt ex |
|
||||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||||
ex = this.getNode() and
|
ex = this.getNode() and
|
||||||
result.getNode() = ex.getType()
|
result.getNode() = ex.getType()
|
||||||
@@ -911,10 +907,10 @@ class ExceptFlowNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name assigned to the handled exception, if any.
|
* Gets the name assigned to the handled exception, if any.
|
||||||
* `e` in `except Py::ExceptionType as e:`
|
* `e` in `except ExceptionType as e:`
|
||||||
*/
|
*/
|
||||||
ControlFlowNode getName() {
|
ControlFlowNode getName() {
|
||||||
exists(Py::ExceptStmt ex |
|
exists(ExceptStmt ex |
|
||||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||||
ex = this.getNode() and
|
ex = this.getNode() and
|
||||||
result.getNode() = ex.getName()
|
result.getNode() = ex.getName()
|
||||||
@@ -924,30 +920,30 @@ class ExceptFlowNode extends ControlFlowNode {
|
|||||||
|
|
||||||
/** The ControlFlowNode for an 'except*' statement. */
|
/** The ControlFlowNode for an 'except*' statement. */
|
||||||
class ExceptGroupFlowNode extends ControlFlowNode {
|
class ExceptGroupFlowNode extends ControlFlowNode {
|
||||||
ExceptGroupFlowNode() { this.getNode() instanceof Py::ExceptGroupStmt }
|
ExceptGroupFlowNode() { this.getNode() instanceof ExceptGroupStmt }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type handled by this exception handler.
|
* Gets the type handled by this exception handler.
|
||||||
* `Py::ExceptionType` in `except* Py::ExceptionType as e:`
|
* `ExceptionType` in `except* ExceptionType as e:`
|
||||||
*/
|
*/
|
||||||
ControlFlowNode getType() {
|
ControlFlowNode getType() {
|
||||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||||
result.getNode() = this.getNode().(Py::ExceptGroupStmt).getType()
|
result.getNode() = this.getNode().(ExceptGroupStmt).getType()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name assigned to the handled exception, if any.
|
* Gets the name assigned to the handled exception, if any.
|
||||||
* `e` in `except* Py::ExceptionType as e:`
|
* `e` in `except* ExceptionType as e:`
|
||||||
*/
|
*/
|
||||||
ControlFlowNode getName() {
|
ControlFlowNode getName() {
|
||||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||||
result.getNode() = this.getNode().(Py::ExceptGroupStmt).getName()
|
result.getNode() = this.getNode().(ExceptGroupStmt).getName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Scopes {
|
private module Scopes {
|
||||||
private predicate fast_local(NameNode n) {
|
private predicate fast_local(NameNode n) {
|
||||||
exists(Py::FastLocalVariable v |
|
exists(FastLocalVariable v |
|
||||||
n.uses(v) and
|
n.uses(v) and
|
||||||
v.getScope() = n.getScope()
|
v.getScope() = n.getScope()
|
||||||
)
|
)
|
||||||
@@ -956,15 +952,15 @@ private module Scopes {
|
|||||||
predicate local(NameNode n) {
|
predicate local(NameNode n) {
|
||||||
fast_local(n)
|
fast_local(n)
|
||||||
or
|
or
|
||||||
exists(Py::SsaVariable var |
|
exists(SsaVariable var |
|
||||||
var.getAUse() = n and
|
var.getAUse() = n and
|
||||||
n.getScope() instanceof Py::Class and
|
n.getScope() instanceof Class and
|
||||||
exists(var.getDefinition())
|
exists(var.getDefinition())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate non_local(NameNode n) {
|
predicate non_local(NameNode n) {
|
||||||
exists(Py::FastLocalVariable flv |
|
exists(FastLocalVariable flv |
|
||||||
flv.getALoad() = n.getNode() and
|
flv.getALoad() = n.getNode() and
|
||||||
not flv.getScope() = n.getScope()
|
not flv.getScope() = n.getScope()
|
||||||
)
|
)
|
||||||
@@ -972,20 +968,20 @@ private module Scopes {
|
|||||||
|
|
||||||
// magic is fine, but we get questionable join-ordering of it
|
// magic is fine, but we get questionable join-ordering of it
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate use_of_global_variable(NameNode n, Py::Module scope, string name) {
|
predicate use_of_global_variable(NameNode n, Module scope, string name) {
|
||||||
n.isLoad() and
|
n.isLoad() and
|
||||||
not non_local(n) and
|
not non_local(n) and
|
||||||
not exists(Py::SsaVariable var | var.getAUse() = n |
|
not exists(SsaVariable var | var.getAUse() = n |
|
||||||
var.getVariable() instanceof Py::FastLocalVariable
|
var.getVariable() instanceof FastLocalVariable
|
||||||
or
|
or
|
||||||
n.getScope() instanceof Py::Class and
|
n.getScope() instanceof Class and
|
||||||
not maybe_undefined(var)
|
not maybe_undefined(var)
|
||||||
) and
|
) and
|
||||||
name = n.getId() and
|
name = n.getId() and
|
||||||
scope = n.getEnclosingModule()
|
scope = n.getEnclosingModule()
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate maybe_undefined(Py::SsaVariable var) {
|
private predicate maybe_undefined(SsaVariable var) {
|
||||||
not exists(var.getDefinition()) and not py_ssa_phi(var, _)
|
not exists(var.getDefinition()) and not py_ssa_phi(var, _)
|
||||||
or
|
or
|
||||||
var.getDefinition().isDelete()
|
var.getDefinition().isDelete()
|
||||||
@@ -1062,13 +1058,13 @@ class BasicBlock extends @py_flow_node {
|
|||||||
private predicate oneNodeBlock() { this.firstNode() = this.getLastNode() }
|
private predicate oneNodeBlock() { this.firstNode() = this.getLastNode() }
|
||||||
|
|
||||||
private predicate startLocationInfo(string file, int line, int col) {
|
private predicate startLocationInfo(string file, int line, int col) {
|
||||||
if this.firstNode().getNode() instanceof Py::Scope
|
if this.firstNode().getNode() instanceof Scope
|
||||||
then this.firstNode().getASuccessor().getLocation().hasLocationInfo(file, line, col, _, _)
|
then this.firstNode().getASuccessor().getLocation().hasLocationInfo(file, line, col, _, _)
|
||||||
else this.firstNode().getLocation().hasLocationInfo(file, line, col, _, _)
|
else this.firstNode().getLocation().hasLocationInfo(file, line, col, _, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate endLocationInfo(int endl, int endc) {
|
private predicate endLocationInfo(int endl, int endc) {
|
||||||
if this.getLastNode().getNode() instanceof Py::Scope and not this.oneNodeBlock()
|
if this.getLastNode().getNode() instanceof Scope and not this.oneNodeBlock()
|
||||||
then this.getLastNode().getAPredecessor().getLocation().hasLocationInfo(_, _, _, endl, endc)
|
then this.getLastNode().getAPredecessor().getLocation().hasLocationInfo(_, _, _, endl, endc)
|
||||||
else this.getLastNode().getLocation().hasLocationInfo(_, _, _, endl, endc)
|
else this.getLastNode().getLocation().hasLocationInfo(_, _, _, endl, endc)
|
||||||
}
|
}
|
||||||
@@ -1085,7 +1081,7 @@ class BasicBlock extends @py_flow_node {
|
|||||||
|
|
||||||
/** Whether flow from this basic block reaches a normal exit from its scope */
|
/** Whether flow from this basic block reaches a normal exit from its scope */
|
||||||
predicate reachesExit() {
|
predicate reachesExit() {
|
||||||
exists(Py::Scope s | s.getANormalExit().getBasicBlock() = this)
|
exists(Scope s | s.getANormalExit().getBasicBlock() = this)
|
||||||
or
|
or
|
||||||
this.getASuccessor().reachesExit()
|
this.getASuccessor().reachesExit()
|
||||||
}
|
}
|
||||||
@@ -1126,7 +1122,7 @@ class BasicBlock extends @py_flow_node {
|
|||||||
|
|
||||||
/** Gets the scope of this block */
|
/** Gets the scope of this block */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
Py::Scope getScope() {
|
Scope getScope() {
|
||||||
exists(ControlFlowNode n | n.getBasicBlock() = this |
|
exists(ControlFlowNode n | n.getBasicBlock() = this |
|
||||||
/* Take care not to use an entry or exit node as that node's scope will be the outer scope */
|
/* Take care not to use an entry or exit node as that node's scope will be the outer scope */
|
||||||
not py_scope_flow(n, _, -1) and
|
not py_scope_flow(n, _, -1) and
|
||||||
@@ -1149,17 +1145,17 @@ class BasicBlock extends @py_flow_node {
|
|||||||
predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) }
|
predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `Py::ConditionBlock`, if any, that controls this block and
|
* Gets the `ConditionBlock`, if any, that controls this block and
|
||||||
* does not control any other `Py::ConditionBlock`s that control this block.
|
* does not control any other `ConditionBlock`s that control this block.
|
||||||
* That is the `Py::ConditionBlock` that is closest dominator.
|
* That is the `ConditionBlock` that is closest dominator.
|
||||||
*/
|
*/
|
||||||
Py::ConditionBlock getImmediatelyControllingBlock() {
|
ConditionBlock getImmediatelyControllingBlock() {
|
||||||
result = this.nonControllingImmediateDominator*().getImmediateDominator()
|
result = this.nonControllingImmediateDominator*().getImmediateDominator()
|
||||||
}
|
}
|
||||||
|
|
||||||
private BasicBlock nonControllingImmediateDominator() {
|
private BasicBlock nonControllingImmediateDominator() {
|
||||||
result = this.getImmediateDominator() and
|
result = this.getImmediateDominator() and
|
||||||
not result.(Py::ConditionBlock).controls(this, _)
|
not result.(ConditionBlock).controls(this, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1179,7 +1175,7 @@ private class ControlFlowNodeAlias = ControlFlowNode;
|
|||||||
|
|
||||||
final private class FinalBasicBlock = BasicBlock;
|
final private class FinalBasicBlock = BasicBlock;
|
||||||
|
|
||||||
module Cfg implements BB::CfgSig<Py::Location> {
|
module Cfg implements BB::CfgSig<Location> {
|
||||||
private import codeql.controlflow.SuccessorType
|
private import codeql.controlflow.SuccessorType
|
||||||
|
|
||||||
class ControlFlowNode = ControlFlowNodeAlias;
|
class ControlFlowNode = ControlFlowNodeAlias;
|
||||||
@@ -1190,7 +1186,7 @@ module Cfg implements BB::CfgSig<Py::Location> {
|
|||||||
// Using the location of the first node is simple
|
// Using the location of the first node is simple
|
||||||
// and we just need a way to identify the basic block
|
// and we just need a way to identify the basic block
|
||||||
// during debugging, so this will be serviceable.
|
// during debugging, so this will be serviceable.
|
||||||
Py::Location getLocation() { result = super.getNode(0).getLocation() }
|
Location getLocation() { result = super.getNode(0).getLocation() }
|
||||||
|
|
||||||
int length() { result = count(int i | exists(this.getNode(i))) }
|
int length() { result = count(int i | exists(this.getNode(i))) }
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ overlay[local]
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
import python
|
import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function, independent of defaults and binding.
|
* A function, independent of defaults and binding.
|
||||||
@@ -158,12 +157,12 @@ class Function extends Function_, Scope, AstNode {
|
|||||||
* DEPRECATED: bind a `Return` node explicitly instead, e.g.
|
* DEPRECATED: bind a `Return` node explicitly instead, e.g.
|
||||||
* `exists(Return ret | ret.getScope() = this and n.getNode() = ret.getValue())`.
|
* `exists(Return ret | ret.getScope() = this and n.getNode() = ret.getValue())`.
|
||||||
* This API is being phased out together with `AstNode.getAFlowNode()` to
|
* This API is being phased out together with `AstNode.getAFlowNode()` to
|
||||||
* untangle the AST and CFG hierarchies.
|
* untangle the AST and CFG hierarchies in preparation for migrating the
|
||||||
|
* dataflow library off the legacy CFG.
|
||||||
*
|
*
|
||||||
* Gets a control flow node for a return value of this function, from the
|
* Gets a control flow node for a return value of this function.
|
||||||
* new (shared) CFG.
|
|
||||||
*/
|
*/
|
||||||
deprecated Cfg::ControlFlowNode getAReturnValueFlowNode() {
|
deprecated ControlFlowNode getAReturnValueFlowNode() {
|
||||||
exists(Return ret |
|
exists(Return ret |
|
||||||
ret.getScope() = this and
|
ret.getScope() = this and
|
||||||
ret.getValue() = result.getNode()
|
ret.getValue() = result.getNode()
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ module;
|
|||||||
import python
|
import python
|
||||||
private import semmle.python.types.Builtins
|
private import semmle.python.types.Builtins
|
||||||
private import semmle.python.internal.CachedStages
|
private import semmle.python.internal.CachedStages
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An alias in an import statement, the `mod as name` part of `import mod as name`. May be artificial;
|
* An alias in an import statement, the `mod as name` part of `import mod as name`. May be artificial;
|
||||||
@@ -164,7 +163,7 @@ class ImportMember extends ImportMember_ {
|
|||||||
result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName()
|
result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName()
|
||||||
}
|
}
|
||||||
|
|
||||||
deprecated override Cfg::ImportMemberNode getAFlowNode() { result = super.getAFlowNode() }
|
deprecated override ImportMemberNode getAFlowNode() { result = super.getAFlowNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An import statement */
|
/** An import statement */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,11 @@
|
|||||||
/** Provides commonly used BarrierGuards. */
|
/** Provides commonly used BarrierGuards. */
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import semmle.python.dataflow.new.DataFlow
|
private import semmle.python.dataflow.new.DataFlow
|
||||||
|
|
||||||
private predicate constCompare(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) {
|
private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) {
|
||||||
exists(Cfg::CompareNode cn | cn = g |
|
exists(CompareNode cn | cn = g |
|
||||||
exists(ImmutableLiteral const, Cmpop op, Cfg::ControlFlowNode c |
|
exists(ImmutableLiteral const, Cmpop op, ControlFlowNode c |
|
||||||
c.getNode() = const and
|
c.getNode() = const and
|
||||||
(
|
(
|
||||||
op = any(Eq eq) and branch = true
|
op = any(Eq eq) and branch = true
|
||||||
@@ -19,7 +18,7 @@ private predicate constCompare(DataFlow::GuardNode g, Cfg::ControlFlowNode node,
|
|||||||
cn.operands(node, op, c)
|
cn.operands(node, op, c)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NameConstant const, Cmpop op, Cfg::ControlFlowNode c |
|
exists(NameConstant const, Cmpop op, ControlFlowNode c |
|
||||||
c.getNode() = const and
|
c.getNode() = const and
|
||||||
(
|
(
|
||||||
op = any(Is is_) and branch = true
|
op = any(Is is_) and branch = true
|
||||||
@@ -32,12 +31,12 @@ private predicate constCompare(DataFlow::GuardNode g, Cfg::ControlFlowNode node,
|
|||||||
cn.operands(node, op, c)
|
cn.operands(node, op, c)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(Cfg::IterableNode const_iterable, Cmpop op |
|
exists(IterableNode const_iterable, Cmpop op |
|
||||||
op = any(In in_) and branch = true
|
op = any(In in_) and branch = true
|
||||||
or
|
or
|
||||||
op = any(NotIn ni) and branch = false
|
op = any(NotIn ni) and branch = false
|
||||||
|
|
|
|
||||||
forall(Cfg::ControlFlowNode elem | elem = const_iterable.getAnElement() |
|
forall(ControlFlowNode elem | elem = const_iterable.getAnElement() |
|
||||||
elem.getNode() instanceof ImmutableLiteral
|
elem.getNode() instanceof ImmutableLiteral
|
||||||
) and
|
) and
|
||||||
cn.operands(node, op, const_iterable)
|
cn.operands(node, op, const_iterable)
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import semmle.python.dataflow.new.DataFlow
|
private import semmle.python.dataflow.new.DataFlow
|
||||||
// Need to import `semmle.python.Frameworks` since frameworks can extend `SensitiveDataSource::Range`
|
// Need to import `semmle.python.Frameworks` since frameworks can extend `SensitiveDataSource::Range`
|
||||||
private import semmle.python.Frameworks
|
private import semmle.python.Frameworks
|
||||||
@@ -106,7 +105,7 @@ private module SensitiveDataModeling {
|
|||||||
or
|
or
|
||||||
// to cover functions that we don't have the definition for, and where the
|
// to cover functions that we don't have the definition for, and where the
|
||||||
// reference to the function has not already been marked as being sensitive
|
// reference to the function has not already been marked as being sensitive
|
||||||
this.getFunction().asCfgNode().(Cfg::NameNode).getId() = sensitiveString(classification)
|
this.getFunction().asCfgNode().(NameNode).getId() = sensitiveString(classification)
|
||||||
}
|
}
|
||||||
|
|
||||||
override SensitiveDataClassification getClassification() { result = classification }
|
override SensitiveDataClassification getClassification() { result = classification }
|
||||||
@@ -252,12 +251,12 @@ private module SensitiveDataModeling {
|
|||||||
SensitiveDataClassification classification;
|
SensitiveDataClassification classification;
|
||||||
|
|
||||||
SensitiveVariableAssignment() {
|
SensitiveVariableAssignment() {
|
||||||
exists(Cfg::DefinitionNode def |
|
exists(DefinitionNode def |
|
||||||
def.(Cfg::NameNode).getId() = sensitiveString(classification) and
|
def.(NameNode).getId() = sensitiveString(classification) and
|
||||||
(
|
(
|
||||||
this.asCfgNode() = def.getValue()
|
this.asCfgNode() = def.getValue()
|
||||||
or
|
or
|
||||||
this.asCfgNode() = def.getValue().(Cfg::ForNode).getSequence()
|
this.asCfgNode() = def.getValue().(ForNode).getSequence()
|
||||||
) and
|
) and
|
||||||
not this.asExpr() instanceof FunctionExpr and
|
not this.asExpr() instanceof FunctionExpr and
|
||||||
not this.asExpr() instanceof ClassExpr
|
not this.asExpr() instanceof ClassExpr
|
||||||
@@ -294,7 +293,7 @@ private module SensitiveDataModeling {
|
|||||||
SensitiveDataClassification classification;
|
SensitiveDataClassification classification;
|
||||||
|
|
||||||
SensitiveSubscript() {
|
SensitiveSubscript() {
|
||||||
this.asCfgNode().(Cfg::SubscriptNode).getIndex() =
|
this.asCfgNode().(SubscriptNode).getIndex() =
|
||||||
sensitiveLookupStringConst(classification).asCfgNode()
|
sensitiveLookupStringConst(classification).asCfgNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ overlay[local]
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
import DataFlowUtil
|
import DataFlowUtil
|
||||||
import DataFlowPublic
|
import DataFlowPublic
|
||||||
private import DataFlowPrivate
|
private import DataFlowPrivate
|
||||||
@@ -84,9 +83,9 @@ abstract class AttrWrite extends AttrRef {
|
|||||||
* ```python
|
* ```python
|
||||||
* object.attr = value
|
* object.attr = value
|
||||||
* ```
|
* ```
|
||||||
* Also gives access to the `value` being written, by extending `Cfg::DefinitionNode`.
|
* Also gives access to the `value` being written, by extending `DefinitionNode`.
|
||||||
*/
|
*/
|
||||||
private class AttributeAssignmentNode extends Cfg::DefinitionNode, Cfg::AttrNode { }
|
private class AttributeAssignmentNode extends DefinitionNode, AttrNode { }
|
||||||
|
|
||||||
/** A simple attribute assignment: `object.attr = value`. */
|
/** A simple attribute assignment: `object.attr = value`. */
|
||||||
private class AttributeAssignmentAsAttrWrite extends AttrWrite, CfgNode {
|
private class AttributeAssignmentAsAttrWrite extends AttrWrite, CfgNode {
|
||||||
@@ -132,13 +131,13 @@ private class GlobalAttributeAssignmentAsAttrWrite extends AttrWrite, CfgNode {
|
|||||||
override string getAttributeName() { result = node.getName() }
|
override string getAttributeName() { result = node.getName() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Represents `Cfg::CallNode`s that may refer to calls to built-in functions or classes. */
|
/** Represents `CallNode`s that may refer to calls to built-in functions or classes. */
|
||||||
private class BuiltInCallNode extends Cfg::CallNode {
|
private class BuiltInCallNode extends CallNode {
|
||||||
string name;
|
string name;
|
||||||
|
|
||||||
BuiltInCallNode() {
|
BuiltInCallNode() {
|
||||||
// TODO disallow instances where the name of the built-in may refer to an in-scope variable of that name.
|
// TODO disallow instances where the name of the built-in may refer to an in-scope variable of that name.
|
||||||
exists(Cfg::NameNode id |
|
exists(NameNode id |
|
||||||
name = Builtins::getBuiltinName() and
|
name = Builtins::getBuiltinName() and
|
||||||
this.getFunction() = id and
|
this.getFunction() = id and
|
||||||
id.getId() = name and
|
id.getId() = name and
|
||||||
@@ -146,7 +145,7 @@ private class BuiltInCallNode extends Cfg::CallNode {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the name of the built-in function that is called at this `Cfg::CallNode` */
|
/** Gets the name of the built-in function that is called at this `CallNode` */
|
||||||
string getBuiltinName() { result = name }
|
string getBuiltinName() { result = name }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,20 +157,20 @@ private class BuiltinAttrCallNode extends BuiltInCallNode {
|
|||||||
BuiltinAttrCallNode() { name in ["setattr", "getattr", "hasattr", "delattr"] }
|
BuiltinAttrCallNode() { name in ["setattr", "getattr", "hasattr", "delattr"] }
|
||||||
|
|
||||||
/** Gets the control flow node for object on which the attribute is accessed. */
|
/** Gets the control flow node for object on which the attribute is accessed. */
|
||||||
Cfg::ControlFlowNode getObject() { result in [this.getArg(0), this.getArgByName("object")] }
|
ControlFlowNode getObject() { result in [this.getArg(0), this.getArgByName("object")] }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the control flow node for the value that is being written to the attribute.
|
* Gets the control flow node for the value that is being written to the attribute.
|
||||||
* Only relevant for `setattr` calls.
|
* Only relevant for `setattr` calls.
|
||||||
*/
|
*/
|
||||||
Cfg::ControlFlowNode getValue() {
|
ControlFlowNode getValue() {
|
||||||
// only valid for `setattr`
|
// only valid for `setattr`
|
||||||
name = "setattr" and
|
name = "setattr" and
|
||||||
result in [this.getArg(2), this.getArgByName("value")]
|
result in [this.getArg(2), this.getArgByName("value")]
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the control flow node that defines the name of the attribute being accessed. */
|
/** Gets the control flow node that defines the name of the attribute being accessed. */
|
||||||
Cfg::ControlFlowNode getName() { result in [this.getArg(1), this.getArgByName("name")] }
|
ControlFlowNode getName() { result in [this.getArg(1), this.getArgByName("name")] }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Represents calls to the built-in `setattr`. */
|
/** Represents calls to the built-in `setattr`. */
|
||||||
@@ -206,10 +205,10 @@ private class SetAttrCallAsAttrWrite extends AttrWrite, CfgNode {
|
|||||||
* attr = value
|
* attr = value
|
||||||
* ...
|
* ...
|
||||||
* ```
|
* ```
|
||||||
* Instances of this class correspond to the `Cfg::NameNode` for `attr`, and also gives access to `value` by
|
* Instances of this class correspond to the `NameNode` for `attr`, and also gives access to `value` by
|
||||||
* virtue of being a `Cfg::DefinitionNode`.
|
* virtue of being a `DefinitionNode`.
|
||||||
*/
|
*/
|
||||||
private class ClassAttributeAssignmentNode extends Cfg::DefinitionNode, Cfg::NameNode {
|
private class ClassAttributeAssignmentNode extends DefinitionNode, NameNode {
|
||||||
ClassAttributeAssignmentNode() { this.getScope() = any(ClassExpr c).getInnerScope() }
|
ClassAttributeAssignmentNode() { this.getScope() = any(ClassExpr c).getInnerScope() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +248,7 @@ abstract class AttrRead extends AttrRef, Node, LocalSourceNode {
|
|||||||
|
|
||||||
/** A simple attribute read, e.g. `object.attr` */
|
/** A simple attribute read, e.g. `object.attr` */
|
||||||
private class AttributeReadAsAttrRead extends AttrRead, CfgNode {
|
private class AttributeReadAsAttrRead extends AttrRead, CfgNode {
|
||||||
override Cfg::AttrNode node;
|
override AttrNode node;
|
||||||
|
|
||||||
AttributeReadAsAttrRead() { node.isLoad() }
|
AttributeReadAsAttrRead() { node.isLoad() }
|
||||||
|
|
||||||
@@ -286,7 +285,7 @@ private class GetAttrCallAsAttrRead extends AttrRead, CfgNode {
|
|||||||
* is treated as if it is a read of the attribute `module.attr`, even if `module` is not imported directly.
|
* is treated as if it is a read of the attribute `module.attr`, even if `module` is not imported directly.
|
||||||
*/
|
*/
|
||||||
private class ModuleAttributeImportAsAttrRead extends AttrRead, CfgNode {
|
private class ModuleAttributeImportAsAttrRead extends AttrRead, CfgNode {
|
||||||
override Cfg::ImportMemberNode node;
|
override ImportMemberNode node;
|
||||||
|
|
||||||
override Node getObject() { result.asCfgNode() = node.getModule(_) }
|
override Node getObject() { result.asCfgNode() = node.getModule(_) }
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ overlay[local]
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import semmle.python.dataflow.new.DataFlow
|
private import semmle.python.dataflow.new.DataFlow
|
||||||
private import semmle.python.dataflow.new.internal.ImportStar
|
private import semmle.python.dataflow.new.internal.ImportStar
|
||||||
|
|
||||||
@@ -68,7 +67,7 @@ module Builtins {
|
|||||||
DataFlow::CfgNode likelyBuiltin(string name) {
|
DataFlow::CfgNode likelyBuiltin(string name) {
|
||||||
exists(Module m |
|
exists(Module m |
|
||||||
result.getNode() =
|
result.getNode() =
|
||||||
any(Cfg::NameNode n |
|
any(NameNode n |
|
||||||
possible_builtin_accessed_in_module(n, name, m) and
|
possible_builtin_accessed_in_module(n, name, m) and
|
||||||
not possible_builtin_defined_in_module(name, m)
|
not possible_builtin_defined_in_module(name, m)
|
||||||
)
|
)
|
||||||
@@ -88,7 +87,7 @@ module Builtins {
|
|||||||
* Holds if `n` is an access of a global variable called `name` (which is also the name of a
|
* Holds if `n` is an access of a global variable called `name` (which is also the name of a
|
||||||
* built-in) inside the module `m`.
|
* built-in) inside the module `m`.
|
||||||
*/
|
*/
|
||||||
private predicate possible_builtin_accessed_in_module(Cfg::NameNode n, string name, Module m) {
|
private predicate possible_builtin_accessed_in_module(NameNode n, string name, Module m) {
|
||||||
n.isGlobal() and
|
n.isGlobal() and
|
||||||
n.isLoad() and
|
n.isLoad() and
|
||||||
name = n.getId() and
|
name = n.getId() and
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
* what callable this call might end up targeting.
|
* what callable this call might end up targeting.
|
||||||
*
|
*
|
||||||
* Specifically this means that we cannot use type-backtrackers from the function of a
|
* Specifically this means that we cannot use type-backtrackers from the function of a
|
||||||
* `Cfg::CallNode`, since there is no `Cfg::CallNode` to backtrack from for `func` in the example
|
* `CallNode`, since there is no `CallNode` to backtrack from for `func` in the example
|
||||||
* above.
|
* above.
|
||||||
*
|
*
|
||||||
* Note: This hasn't been 100% realized yet, so we don't currently expose a predicate to
|
* Note: This hasn't been 100% realized yet, so we don't currently expose a predicate to
|
||||||
@@ -35,7 +35,6 @@ overlay[local?]
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import DataFlowPublic
|
private import DataFlowPublic
|
||||||
private import DataFlowPrivate
|
private import DataFlowPrivate
|
||||||
private import FlowSummaryImpl as FlowSummaryImpl
|
private import FlowSummaryImpl as FlowSummaryImpl
|
||||||
@@ -163,7 +162,7 @@ newtype TArgumentPosition =
|
|||||||
*/
|
*/
|
||||||
TLambdaSelfArgumentPosition() or
|
TLambdaSelfArgumentPosition() or
|
||||||
TPositionalArgumentPosition(int index) {
|
TPositionalArgumentPosition(int index) {
|
||||||
exists(any(Cfg::CallNode c).getArg(index))
|
exists(any(CallNode c).getArg(index))
|
||||||
or
|
or
|
||||||
// since synthetic calls within a summarized callable could use a unique argument
|
// since synthetic calls within a summarized callable could use a unique argument
|
||||||
// position, we need to ensure we make these available (these are specified as
|
// position, we need to ensure we make these available (these are specified as
|
||||||
@@ -175,7 +174,7 @@ newtype TArgumentPosition =
|
|||||||
index = 0
|
index = 0
|
||||||
} or
|
} or
|
||||||
TKeywordArgumentPosition(string name) {
|
TKeywordArgumentPosition(string name) {
|
||||||
exists(any(Cfg::CallNode c).getArgByName(name))
|
exists(any(CallNode c).getArgByName(name))
|
||||||
or
|
or
|
||||||
// see comment for TPositionalArgumentPosition
|
// see comment for TPositionalArgumentPosition
|
||||||
FlowSummaryImpl::ParsePositions::isParsedKeywordParameterPosition(_, name)
|
FlowSummaryImpl::ParsePositions::isParsedKeywordParameterPosition(_, name)
|
||||||
@@ -298,12 +297,10 @@ predicate hasPropertyDecorator(Function func) {
|
|||||||
*/
|
*/
|
||||||
overlay[local]
|
overlay[local]
|
||||||
predicate hasContextmanagerDecorator(Function func) {
|
predicate hasContextmanagerDecorator(Function func) {
|
||||||
exists(Cfg::ControlFlowNode contextmanager |
|
exists(ControlFlowNode contextmanager |
|
||||||
contextmanager.(Cfg::NameNode).getId() = "contextmanager" and
|
contextmanager.(NameNode).getId() = "contextmanager" and contextmanager.(NameNode).isGlobal()
|
||||||
contextmanager.(Cfg::NameNode).isGlobal()
|
|
||||||
or
|
or
|
||||||
contextmanager.(Cfg::AttrNode).getObject("contextmanager").(Cfg::NameNode).getId() =
|
contextmanager.(AttrNode).getObject("contextmanager").(NameNode).getId() = "contextlib"
|
||||||
"contextlib"
|
|
||||||
|
|
|
|
||||||
func.getADecorator() = contextmanager.getNode()
|
func.getADecorator() = contextmanager.getNode()
|
||||||
)
|
)
|
||||||
@@ -319,10 +316,10 @@ predicate hasContextmanagerDecorator(Function func) {
|
|||||||
*/
|
*/
|
||||||
overlay[local]
|
overlay[local]
|
||||||
private predicate hasOverloadDecorator(Function func) {
|
private predicate hasOverloadDecorator(Function func) {
|
||||||
exists(Cfg::ControlFlowNode overload |
|
exists(ControlFlowNode overload |
|
||||||
overload.(Cfg::NameNode).getId() = "overload" and overload.(Cfg::NameNode).isGlobal()
|
overload.(NameNode).getId() = "overload" and overload.(NameNode).isGlobal()
|
||||||
or
|
or
|
||||||
overload.(Cfg::AttrNode).getObject("overload").(Cfg::NameNode).isGlobal()
|
overload.(AttrNode).getObject("overload").(NameNode).isGlobal()
|
||||||
|
|
|
|
||||||
func.getADecorator() = overload.getNode()
|
func.getADecorator() = overload.getNode()
|
||||||
)
|
)
|
||||||
@@ -541,7 +538,7 @@ class LibraryCallableValue extends DataFlowCallable, TLibraryCallable {
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
/** Gets a call to `type`. */
|
/** Gets a call to `type`. */
|
||||||
private CallCfgNode getTypeCall() {
|
private CallCfgNode getTypeCall() {
|
||||||
exists(Cfg::NameNode id | id.getId() = "type" and id.isGlobal() |
|
exists(NameNode id | id.getId() = "type" and id.isGlobal() |
|
||||||
result.getFunction().asCfgNode() = id
|
result.getFunction().asCfgNode() = id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -553,7 +550,7 @@ private CallCfgNode getSuperCall() {
|
|||||||
// link below), but otherwise only 2 edgecases. Overall it seems ok to ignore this complexity.
|
// link below), but otherwise only 2 edgecases. Overall it seems ok to ignore this complexity.
|
||||||
//
|
//
|
||||||
// https://github.com/python/cpython/blob/18b1782192f85bd26db89f5bc850f8bee4247c1a/Lib/unittest/mock.py#L48-L50
|
// https://github.com/python/cpython/blob/18b1782192f85bd26db89f5bc850f8bee4247c1a/Lib/unittest/mock.py#L48-L50
|
||||||
exists(Cfg::NameNode id | id.getId() = "super" and id.isGlobal() |
|
exists(NameNode id | id.getId() = "super" and id.isGlobal() |
|
||||||
result.getFunction().asCfgNode() = id
|
result.getFunction().asCfgNode() = id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1039,7 +1036,7 @@ private module MethodCalls {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate directCall(
|
private predicate directCall(
|
||||||
Cfg::CallNode call, Function target, string functionName, Class cls, AttrRead attr, Node self
|
CallNode call, Function target, string functionName, Class cls, AttrRead attr, Node self
|
||||||
) {
|
) {
|
||||||
target = findFunctionAccordingToMroKnownStartingClass(cls, functionName) and
|
target = findFunctionAccordingToMroKnownStartingClass(cls, functionName) and
|
||||||
directCall_join(call, functionName, cls, attr, self)
|
directCall_join(call, functionName, cls, attr, self)
|
||||||
@@ -1048,7 +1045,7 @@ private module MethodCalls {
|
|||||||
/** Extracted to give good join order */
|
/** Extracted to give good join order */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate directCall_join(
|
private predicate directCall_join(
|
||||||
Cfg::CallNode call, string functionName, Class cls, AttrRead attr, Node self
|
CallNode call, string functionName, Class cls, AttrRead attr, Node self
|
||||||
) {
|
) {
|
||||||
call.getFunction() = attrReadTracker(attr).asCfgNode() and
|
call.getFunction() = attrReadTracker(attr).asCfgNode() and
|
||||||
attr.accesses(self, functionName) and
|
attr.accesses(self, functionName) and
|
||||||
@@ -1065,7 +1062,7 @@ private module MethodCalls {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate callWithinMethodImplicitSelfOrCls(
|
private predicate callWithinMethodImplicitSelfOrCls(
|
||||||
Cfg::CallNode call, Function target, string functionName, Class classWithMethod, AttrRead attr,
|
CallNode call, Function target, string functionName, Class classWithMethod, AttrRead attr,
|
||||||
Node self
|
Node self
|
||||||
) {
|
) {
|
||||||
target = findFunctionAccordingToMro(getADirectSubclass*(classWithMethod), functionName) and
|
target = findFunctionAccordingToMro(getADirectSubclass*(classWithMethod), functionName) and
|
||||||
@@ -1075,7 +1072,7 @@ private module MethodCalls {
|
|||||||
/** Extracted to give good join order */
|
/** Extracted to give good join order */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate callWithinMethodImplicitSelfOrCls_join(
|
private predicate callWithinMethodImplicitSelfOrCls_join(
|
||||||
Cfg::CallNode call, string functionName, Class classWithMethod, AttrRead attr, Node self
|
CallNode call, string functionName, Class classWithMethod, AttrRead attr, Node self
|
||||||
) {
|
) {
|
||||||
call.getFunction() = attrReadTracker(attr).asCfgNode() and
|
call.getFunction() = attrReadTracker(attr).asCfgNode() and
|
||||||
attr.accesses(self, functionName) and
|
attr.accesses(self, functionName) and
|
||||||
@@ -1087,7 +1084,7 @@ private module MethodCalls {
|
|||||||
* resolve the call to a known target (since the only super class might be the
|
* resolve the call to a known target (since the only super class might be the
|
||||||
* builtin `object`, so we never have the implementation of `__new__` in the DB).
|
* builtin `object`, so we never have the implementation of `__new__` in the DB).
|
||||||
*/
|
*/
|
||||||
predicate fromSuperNewCall(Cfg::CallNode call, Class classUsedInSuper, AttrRead attr, Node self) {
|
predicate fromSuperNewCall(CallNode call, Class classUsedInSuper, AttrRead attr, Node self) {
|
||||||
fromSuper_join(call, "__new__", classUsedInSuper, attr, self) and
|
fromSuper_join(call, "__new__", classUsedInSuper, attr, self) and
|
||||||
self in [classTracker(_), clsArgumentTracker(_)]
|
self in [classTracker(_), clsArgumentTracker(_)]
|
||||||
}
|
}
|
||||||
@@ -1109,7 +1106,7 @@ private module MethodCalls {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate fromSuper(
|
predicate fromSuper(
|
||||||
Cfg::CallNode call, Function target, string functionName, Class classUsedInSuper, AttrRead attr,
|
CallNode call, Function target, string functionName, Class classUsedInSuper, AttrRead attr,
|
||||||
Node self
|
Node self
|
||||||
) {
|
) {
|
||||||
target = findFunctionAccordingToMro(getNextClassInMro(classUsedInSuper), functionName) and
|
target = findFunctionAccordingToMro(getNextClassInMro(classUsedInSuper), functionName) and
|
||||||
@@ -1119,7 +1116,7 @@ private module MethodCalls {
|
|||||||
/** Extracted to give good join order */
|
/** Extracted to give good join order */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fromSuper_join(
|
private predicate fromSuper_join(
|
||||||
Cfg::CallNode call, string functionName, Class classUsedInSuper, AttrRead attr, Node self
|
CallNode call, string functionName, Class classUsedInSuper, AttrRead attr, Node self
|
||||||
) {
|
) {
|
||||||
call.getFunction() = attrReadTracker(attr).asCfgNode() and
|
call.getFunction() = attrReadTracker(attr).asCfgNode() and
|
||||||
(
|
(
|
||||||
@@ -1138,7 +1135,7 @@ private module MethodCalls {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate resolveMethodCall(Cfg::CallNode call, Function target, CallType type, Node self) {
|
predicate resolveMethodCall(CallNode call, Function target, CallType type, Node self) {
|
||||||
(
|
(
|
||||||
directCall(call, target, _, _, _, self)
|
directCall(call, target, _, _, _, self)
|
||||||
or
|
or
|
||||||
@@ -1185,7 +1182,7 @@ import MethodCalls
|
|||||||
* NOTE: We have this predicate mostly to be able to compare with old point-to
|
* NOTE: We have this predicate mostly to be able to compare with old point-to
|
||||||
* call-graph resolution. So it could be removed in the future.
|
* call-graph resolution. So it could be removed in the future.
|
||||||
*/
|
*/
|
||||||
predicate resolveClassCall(Cfg::CallNode call, Class cls) {
|
predicate resolveClassCall(CallNode call, Class cls) {
|
||||||
call.getFunction() = classTracker(cls).asCfgNode()
|
call.getFunction() = classTracker(cls).asCfgNode()
|
||||||
or
|
or
|
||||||
// `cls()` inside a classmethod (which also contains `type(self)()` inside a method)
|
// `cls()` inside a classmethod (which also contains `type(self)()` inside a method)
|
||||||
@@ -1215,7 +1212,7 @@ Function invokedFunctionFromClassConstruction(Class cls, string funcName) {
|
|||||||
*
|
*
|
||||||
* See https://docs.python.org/3/reference/datamodel.html#object.__call__
|
* See https://docs.python.org/3/reference/datamodel.html#object.__call__
|
||||||
*/
|
*/
|
||||||
predicate resolveClassInstanceCall(Cfg::CallNode call, Function target, Node self) {
|
predicate resolveClassInstanceCall(CallNode call, Function target, Node self) {
|
||||||
exists(Class cls |
|
exists(Class cls |
|
||||||
call.getFunction() = classInstanceTracker(cls).asCfgNode() and
|
call.getFunction() = classInstanceTracker(cls).asCfgNode() and
|
||||||
target = findFunctionAccordingToMroKnownStartingClass(cls, "__call__")
|
target = findFunctionAccordingToMroKnownStartingClass(cls, "__call__")
|
||||||
@@ -1234,7 +1231,7 @@ predicate resolveClassInstanceCall(Cfg::CallNode call, Function target, Node sel
|
|||||||
* Holds if `call` is a call to the `target`, with call-type `type`.
|
* Holds if `call` is a call to the `target`, with call-type `type`.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate resolveCall(Cfg::CallNode call, Function target, CallType type) {
|
predicate resolveCall(CallNode call, Function target, CallType type) {
|
||||||
Stages::DataFlow::ref() and
|
Stages::DataFlow::ref() and
|
||||||
(
|
(
|
||||||
type instanceof CallTypePlainFunction and
|
type instanceof CallTypePlainFunction and
|
||||||
@@ -1259,11 +1256,11 @@ predicate resolveCall(Cfg::CallNode call, Function target, CallType type) {
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
/**
|
/**
|
||||||
* Holds if the argument of `call` at position `apos` is `arg`. This is just a helper
|
* 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 `Cfg::CallNode`.
|
* predicate that maps ArgumentPositions to the arguments of the underlying `CallNode`.
|
||||||
*/
|
*/
|
||||||
overlay[local]
|
overlay[local]
|
||||||
cached
|
cached
|
||||||
predicate normalCallArg(Cfg::CallNode call, Node arg, ArgumentPosition apos) {
|
predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) {
|
||||||
exists(int index |
|
exists(int index |
|
||||||
apos.isPositional(index) and
|
apos.isPositional(index) and
|
||||||
arg.asCfgNode() = call.getArg(index)
|
arg.asCfgNode() = call.getArg(index)
|
||||||
@@ -1278,7 +1275,7 @@ predicate normalCallArg(Cfg::CallNode call, Node arg, ArgumentPosition apos) {
|
|||||||
exists(int index |
|
exists(int index |
|
||||||
apos.isStarArgs(index) and
|
apos.isStarArgs(index) and
|
||||||
arg.asCfgNode() = call.getStarArg() and
|
arg.asCfgNode() = call.getStarArg() and
|
||||||
// since `Cfg::CallNode.getArg` doesn't include `*args`, we need to drop to the AST level
|
// since `CallNode.getArg` doesn't include `*args`, we need to drop to the AST level
|
||||||
// to get the index. Notice that we only use the AST for getting the index, so we
|
// to get the index. Notice that we only use the AST for getting the index, so we
|
||||||
// don't need to check for dominance in regards to splitting.
|
// don't need to check for dominance in regards to splitting.
|
||||||
call.getStarArg().getNode() = call.getNode().getPositionalArg(index).(Starred).getValue()
|
call.getStarArg().getNode() = call.getNode().getPositionalArg(index).(Starred).getValue()
|
||||||
@@ -1352,9 +1349,7 @@ predicate normalCallArg(Cfg::CallNode call, Node arg, ArgumentPosition apos) {
|
|||||||
* translated into `l.clear()`, and we can still have use-use flow.
|
* translated into `l.clear()`, and we can still have use-use flow.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate getCallArg(
|
predicate getCallArg(CallNode call, Function target, CallType type, Node arg, ArgumentPosition apos) {
|
||||||
Cfg::CallNode call, Function target, CallType type, Node arg, ArgumentPosition apos
|
|
||||||
) {
|
|
||||||
Stages::DataFlow::ref() and
|
Stages::DataFlow::ref() and
|
||||||
resolveCall(call, target, type) and
|
resolveCall(call, target, type) and
|
||||||
(
|
(
|
||||||
@@ -1447,12 +1442,10 @@ private predicate sameEnclosingCallable(Node node1, Node node2) {
|
|||||||
// DataFlowCall
|
// DataFlowCall
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
newtype TDataFlowCall =
|
newtype TDataFlowCall =
|
||||||
TNormalCall(Cfg::CallNode call, Function target, CallType type) {
|
TNormalCall(CallNode call, Function target, CallType type) { resolveCall(call, target, type) } or
|
||||||
call.injects(_) and resolveCall(call, target, type)
|
|
||||||
} or
|
|
||||||
/** A call to the generated function inside a comprehension */
|
/** A call to the generated function inside a comprehension */
|
||||||
TComprehensionCall(Comp c) or
|
TComprehensionCall(Comp c) or
|
||||||
TPotentialLibraryCall(Cfg::CallNode call) { call.injects(_) } or
|
TPotentialLibraryCall(CallNode call) or
|
||||||
/** A synthesized call inside a summarized callable */
|
/** A synthesized call inside a summarized callable */
|
||||||
TSummaryCall(
|
TSummaryCall(
|
||||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||||
@@ -1472,7 +1465,7 @@ abstract class DataFlowCall extends TDataFlowCall {
|
|||||||
abstract ArgumentNode getArgument(ArgumentPosition apos);
|
abstract ArgumentNode getArgument(ArgumentPosition apos);
|
||||||
|
|
||||||
/** Get the control flow node representing this call, if any. */
|
/** Get the control flow node representing this call, if any. */
|
||||||
abstract Cfg::ControlFlowNode getNode();
|
abstract ControlFlowNode getNode();
|
||||||
|
|
||||||
/** Gets the enclosing callable of this call. */
|
/** Gets the enclosing callable of this call. */
|
||||||
DataFlowCallable getEnclosingCallable() { result = getCallableScope(this.getScope()) }
|
DataFlowCallable getEnclosingCallable() { result = getCallableScope(this.getScope()) }
|
||||||
@@ -1503,28 +1496,28 @@ abstract class ExtractedDataFlowCall extends DataFlowCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A resolved call in source code with an underlying `Cfg::CallNode`.
|
* A resolved call in source code with an underlying `CallNode`.
|
||||||
*
|
*
|
||||||
* This is considered normal, compared with special calls such as `obj[0]` calling the
|
* This is considered normal, compared with special calls such as `obj[0]` calling the
|
||||||
* `__getitem__` method on the object. However, this also includes calls that go to the
|
* `__getitem__` method on the object. However, this also includes calls that go to the
|
||||||
* `__call__` special method.
|
* `__call__` special method.
|
||||||
*/
|
*/
|
||||||
class NormalCall extends ExtractedDataFlowCall, TNormalCall {
|
class NormalCall extends ExtractedDataFlowCall, TNormalCall {
|
||||||
Cfg::CallNode call;
|
CallNode call;
|
||||||
Function target;
|
Function target;
|
||||||
CallType type;
|
CallType type;
|
||||||
|
|
||||||
NormalCall() { this = TNormalCall(call, target, type) }
|
NormalCall() { this = TNormalCall(call, target, type) }
|
||||||
|
|
||||||
override string toString() {
|
override string toString() {
|
||||||
// note: if we used toString directly on the Cfg::CallNode we would get
|
// note: if we used toString directly on the CallNode we would get
|
||||||
// `Cfg::ControlFlowNode for func()`
|
// `ControlFlowNode for func()`
|
||||||
// but the `Cfg::ControlFlowNode` part is just clutter, so we go directly to the AST node
|
// but the `ControlFlowNode` part is just clutter, so we go directly to the AST node
|
||||||
// instead.
|
// instead.
|
||||||
result = call.getNode().toString()
|
result = call.getNode().toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override Cfg::ControlFlowNode getNode() { result = call }
|
override ControlFlowNode getNode() { result = call }
|
||||||
|
|
||||||
override Scope getScope() { result = call.getScope() }
|
override Scope getScope() { result = call.getScope() }
|
||||||
|
|
||||||
@@ -1552,7 +1545,7 @@ class ComprehensionCall extends ExtractedDataFlowCall, TComprehensionCall {
|
|||||||
|
|
||||||
override string toString() { result = "comprehension call" }
|
override string toString() { result = "comprehension call" }
|
||||||
|
|
||||||
override Cfg::ControlFlowNode getNode() { result.getNode() = c }
|
override ControlFlowNode getNode() { result.getNode() = c }
|
||||||
|
|
||||||
override Scope getScope() { result = c.getScope() }
|
override Scope getScope() { result = c.getScope() }
|
||||||
|
|
||||||
@@ -1575,14 +1568,14 @@ class ComprehensionCall extends ExtractedDataFlowCall, TComprehensionCall {
|
|||||||
* in this class.
|
* in this class.
|
||||||
*/
|
*/
|
||||||
class PotentialLibraryCall extends ExtractedDataFlowCall, TPotentialLibraryCall {
|
class PotentialLibraryCall extends ExtractedDataFlowCall, TPotentialLibraryCall {
|
||||||
Cfg::CallNode call;
|
CallNode call;
|
||||||
|
|
||||||
PotentialLibraryCall() { this = TPotentialLibraryCall(call) }
|
PotentialLibraryCall() { this = TPotentialLibraryCall(call) }
|
||||||
|
|
||||||
override string toString() {
|
override string toString() {
|
||||||
// note: if we used toString directly on the Cfg::CallNode we would get
|
// note: if we used toString directly on the CallNode we would get
|
||||||
// `Cfg::ControlFlowNode for func()`
|
// `ControlFlowNode for func()`
|
||||||
// but the `Cfg::ControlFlowNode` part is just clutter, so we go directly to the AST node
|
// but the `ControlFlowNode` part is just clutter, so we go directly to the AST node
|
||||||
// instead.
|
// instead.
|
||||||
result = call.getNode().toString()
|
result = call.getNode().toString()
|
||||||
}
|
}
|
||||||
@@ -1599,10 +1592,10 @@ class PotentialLibraryCall extends ExtractedDataFlowCall, TPotentialLibraryCall
|
|||||||
// potential self argument, from `foo.bar()` -- note that this could also just be a
|
// potential self argument, from `foo.bar()` -- note that this could also just be a
|
||||||
// module reference, but we really don't have a good way of knowing :|
|
// module reference, but we really don't have a good way of knowing :|
|
||||||
apos.isSelf() and
|
apos.isSelf() and
|
||||||
result.asCfgNode() = call.getFunction().(Cfg::AttrNode).getObject()
|
result.asCfgNode() = call.getFunction().(AttrNode).getObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
override Cfg::ControlFlowNode getNode() { result = call }
|
override ControlFlowNode getNode() { result = call }
|
||||||
|
|
||||||
override Scope getScope() { result = call.getScope() }
|
override Scope getScope() { result = call.getScope() }
|
||||||
}
|
}
|
||||||
@@ -1634,7 +1627,7 @@ class SummaryCall extends DataFlowCall, TSummaryCall {
|
|||||||
|
|
||||||
override ArgumentNode getArgument(ArgumentPosition apos) { none() }
|
override ArgumentNode getArgument(ArgumentPosition apos) { none() }
|
||||||
|
|
||||||
override Cfg::ControlFlowNode getNode() { none() }
|
override ControlFlowNode getNode() { none() }
|
||||||
|
|
||||||
override string toString() { result = "[summary] call to " + receiver + " in " + c }
|
override string toString() { result = "[summary] call to " + receiver + " in " + c }
|
||||||
|
|
||||||
@@ -1776,12 +1769,12 @@ private class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNodeImpl
|
|||||||
* This is used for tracking flow through captured variables.
|
* This is used for tracking flow through captured variables.
|
||||||
*/
|
*/
|
||||||
class SynthCapturedVariablesArgumentNode extends Node, TSynthCapturedVariablesArgumentNode {
|
class SynthCapturedVariablesArgumentNode extends Node, TSynthCapturedVariablesArgumentNode {
|
||||||
Cfg::ControlFlowNode callable;
|
ControlFlowNode callable;
|
||||||
|
|
||||||
SynthCapturedVariablesArgumentNode() { this = TSynthCapturedVariablesArgumentNode(callable) }
|
SynthCapturedVariablesArgumentNode() { this = TSynthCapturedVariablesArgumentNode(callable) }
|
||||||
|
|
||||||
/** Gets the `Cfg::CallNode` corresponding to this captured variables argument node. */
|
/** Gets the `CallNode` corresponding to this captured variables argument node. */
|
||||||
Cfg::CallNode getCallNode() { result.getFunction() = callable }
|
CallNode getCallNode() { result.getFunction() = callable }
|
||||||
|
|
||||||
/** Gets the `CfgNode` that corresponds to this synthetic node. */
|
/** Gets the `CfgNode` that corresponds to this synthetic node. */
|
||||||
CfgNode getUnderlyingNode() { result.asCfgNode() = callable }
|
CfgNode getUnderlyingNode() { result.asCfgNode() = callable }
|
||||||
@@ -1799,7 +1792,7 @@ class CapturedVariablesArgumentNodeAsArgumentNode extends ArgumentNode,
|
|||||||
{
|
{
|
||||||
overlay[global]
|
overlay[global]
|
||||||
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||||
exists(Cfg::CallNode callNode | callNode = this.getCallNode() |
|
exists(CallNode callNode | callNode = this.getCallNode() |
|
||||||
callNode = call.getNode() and
|
callNode = call.getNode() and
|
||||||
exists(Function target | resolveCall(callNode, target, _) |
|
exists(Function target | resolveCall(callNode, target, _) |
|
||||||
target = any(VariableCapture::CapturedVariable v).getACapturingScope()
|
target = any(VariableCapture::CapturedVariable v).getACapturingScope()
|
||||||
@@ -1813,7 +1806,7 @@ class CapturedVariablesArgumentNodeAsArgumentNode extends ArgumentNode,
|
|||||||
class SynthCapturedVariablesArgumentPostUpdateNode extends PostUpdateNodeImpl,
|
class SynthCapturedVariablesArgumentPostUpdateNode extends PostUpdateNodeImpl,
|
||||||
TSynthCapturedVariablesArgumentPostUpdateNode
|
TSynthCapturedVariablesArgumentPostUpdateNode
|
||||||
{
|
{
|
||||||
Cfg::ControlFlowNode callable;
|
ControlFlowNode callable;
|
||||||
|
|
||||||
SynthCapturedVariablesArgumentPostUpdateNode() {
|
SynthCapturedVariablesArgumentPostUpdateNode() {
|
||||||
this = TSynthCapturedVariablesArgumentPostUpdateNode(callable)
|
this = TSynthCapturedVariablesArgumentPostUpdateNode(callable)
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ overlay[local?]
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import DataFlowPublic
|
private import DataFlowPublic
|
||||||
private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl
|
private import semmle.python.essa.SsaCompute
|
||||||
private import semmle.python.dataflow.new.internal.ImportResolution
|
private import semmle.python.dataflow.new.internal.ImportResolution
|
||||||
private import FlowSummaryImpl as FlowSummaryImpl
|
private import FlowSummaryImpl as FlowSummaryImpl
|
||||||
private import semmle.python.frameworks.data.ModelsAsData
|
private import semmle.python.frameworks.data.ModelsAsData
|
||||||
@@ -44,28 +43,13 @@ predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos)
|
|||||||
// Nodes
|
// Nodes
|
||||||
//--------
|
//--------
|
||||||
overlay[local]
|
overlay[local]
|
||||||
predicate isExpressionNode(Cfg::ControlFlowNode node) {
|
predicate isExpressionNode(ControlFlowNode node) { node.getNode() instanceof Expr }
|
||||||
// Restrict to the `injects` representative so the dataflow layer creates
|
|
||||||
// exactly one `TCfgNode` per AST expression.
|
|
||||||
node.injects(_) and
|
|
||||||
(
|
|
||||||
node.getNode() instanceof Expr
|
|
||||||
or
|
|
||||||
// `Cfg::ForNode` wraps a `For` statement's iter position, but
|
|
||||||
// overrides `.getNode()` to return the `Py::For` statement (for
|
|
||||||
// legacy parity). The underlying AST is still an `Expr` (the iter
|
|
||||||
// expression); we want a dataflow node here so that for-loop
|
|
||||||
// content reads (`for y in l`) have a source expression node to
|
|
||||||
// read content from.
|
|
||||||
node instanceof Cfg::ForNode
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// SyntheticPreUpdateNode
|
// SyntheticPreUpdateNode
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode {
|
class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode {
|
||||||
Cfg::CallNode node;
|
CallNode node;
|
||||||
|
|
||||||
SyntheticPreUpdateNode() { this = TSyntheticPreUpdateNode(node) }
|
SyntheticPreUpdateNode() { this = TSyntheticPreUpdateNode(node) }
|
||||||
|
|
||||||
@@ -167,7 +151,7 @@ predicate synthStarArgsElementParameterNodeStoreStep(
|
|||||||
* been passed in a `**kwargs` argument.
|
* been passed in a `**kwargs` argument.
|
||||||
*/
|
*/
|
||||||
class SynthDictSplatArgumentNode extends Node, TSynthDictSplatArgumentNode {
|
class SynthDictSplatArgumentNode extends Node, TSynthDictSplatArgumentNode {
|
||||||
Cfg::CallNode node;
|
CallNode node;
|
||||||
|
|
||||||
SynthDictSplatArgumentNode() { this = TSynthDictSplatArgumentNode(node) }
|
SynthDictSplatArgumentNode() { this = TSynthDictSplatArgumentNode(node) }
|
||||||
|
|
||||||
@@ -181,7 +165,7 @@ class SynthDictSplatArgumentNode extends Node, TSynthDictSplatArgumentNode {
|
|||||||
private predicate synthDictSplatArgumentNodeStoreStep(
|
private predicate synthDictSplatArgumentNodeStoreStep(
|
||||||
ArgumentNode nodeFrom, DictionaryElementContent c, SynthDictSplatArgumentNode nodeTo
|
ArgumentNode nodeFrom, DictionaryElementContent c, SynthDictSplatArgumentNode nodeTo
|
||||||
) {
|
) {
|
||||||
exists(string name, Cfg::CallNode call, ArgumentPosition keywordPos |
|
exists(string name, CallNode call, ArgumentPosition keywordPos |
|
||||||
nodeTo = TSynthDictSplatArgumentNode(call) and
|
nodeTo = TSynthDictSplatArgumentNode(call) and
|
||||||
getCallArg(call, _, _, nodeFrom, keywordPos) and
|
getCallArg(call, _, _, nodeFrom, keywordPos) and
|
||||||
keywordPos.isKeyword(name) and
|
keywordPos.isKeyword(name) and
|
||||||
@@ -305,7 +289,7 @@ abstract class PostUpdateNodeImpl extends Node {
|
|||||||
* Synthetic post-update nodes for synthetic nodes need to be listed one by one.
|
* Synthetic post-update nodes for synthetic nodes need to be listed one by one.
|
||||||
*/
|
*/
|
||||||
class SyntheticPostUpdateNode extends PostUpdateNodeImpl, TSyntheticPostUpdateNode {
|
class SyntheticPostUpdateNode extends PostUpdateNodeImpl, TSyntheticPostUpdateNode {
|
||||||
Cfg::ControlFlowNode node;
|
ControlFlowNode node;
|
||||||
|
|
||||||
SyntheticPostUpdateNode() { this = TSyntheticPostUpdateNode(node) }
|
SyntheticPostUpdateNode() { this = TSyntheticPostUpdateNode(node) }
|
||||||
|
|
||||||
@@ -349,42 +333,16 @@ module LocalFlow {
|
|||||||
// `x = f(42)`
|
// `x = f(42)`
|
||||||
// nodeFrom is `f(42)`
|
// nodeFrom is `f(42)`
|
||||||
// nodeTo is `x`
|
// nodeTo is `x`
|
||||||
//
|
exists(AssignmentDefinition def |
|
||||||
// We use the CFG-level `DefinitionNode.getValue()` directly rather
|
|
||||||
// than going through SSA, because the new SSA library prunes write
|
|
||||||
// definitions that have no subsequent read in the same scope (e.g.
|
|
||||||
// a module-level `def f():` whose `f` is only read inside other
|
|
||||||
// functions). The CFG-level link is unconditional.
|
|
||||||
//
|
|
||||||
// The Name-target restriction mirrors legacy ESSA's
|
|
||||||
// `SsaDefinitions::assignment_definition`, which required
|
|
||||||
// `defn.(NameNode).defines(v)`. Subscript and attribute writes
|
|
||||||
// (`x[i] = 42`, `obj.attr = 42`) are intentionally excluded — their
|
|
||||||
// value flow is handled by the content-flow / `AttrWrite` machinery,
|
|
||||||
// not by a local-flow step *into* the Subscript/Attribute expression.
|
|
||||||
// Excluding them is essential for keeping augmented-assignment
|
|
||||||
// targets (`x[i] += 42`) classifiable as `LocalSourceNode` on the
|
|
||||||
// read side: the single canonical CFG node is both a load and a
|
|
||||||
// store, and any incoming local-flow step would disqualify it from
|
|
||||||
// being a local source.
|
|
||||||
exists(Cfg::DefinitionNode def |
|
|
||||||
nodeFrom.(CfgNode).getNode() = def.getValue() and
|
nodeFrom.(CfgNode).getNode() = def.getValue() and
|
||||||
nodeTo.(CfgNode).getNode() = def and
|
nodeTo.(CfgNode).getNode() = def.getDefiningNode()
|
||||||
def instanceof Cfg::NameNode and
|
|
||||||
// Parameter defaults are evaluated in the enclosing scope, while the
|
|
||||||
// parameter itself lives in the function's scope. The cross-scope
|
|
||||||
// edge is provided by `runtimeJumpStep` instead.
|
|
||||||
not exists(Py::Parameter param | def.getNode() = param.asName())
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// With definition
|
// With definition
|
||||||
// `with f(42) as x:`
|
// `with f(42) as x:`
|
||||||
// nodeFrom is `f(42)`
|
// nodeFrom is `f(42)`
|
||||||
// nodeTo is `x`
|
// nodeTo is `x`
|
||||||
exists(
|
exists(With with, ControlFlowNode contextManager, WithDefinition withDef, ControlFlowNode var |
|
||||||
With with, Cfg::ControlFlowNode contextManager, SsaImpl::WithDefinition withDef,
|
|
||||||
Cfg::ControlFlowNode var
|
|
||||||
|
|
|
||||||
var = withDef.getDefiningNode()
|
var = withDef.getDefiningNode()
|
||||||
|
|
|
|
||||||
nodeFrom.(CfgNode).getNode() = contextManager and
|
nodeFrom.(CfgNode).getNode() = contextManager and
|
||||||
@@ -403,13 +361,13 @@ module LocalFlow {
|
|||||||
|
|
||||||
predicate expressionFlowStep(Node nodeFrom, Node nodeTo) {
|
predicate expressionFlowStep(Node nodeFrom, Node nodeTo) {
|
||||||
// If expressions
|
// If expressions
|
||||||
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(Cfg::IfExprNode).getAnOperand()
|
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(IfExprNode).getAnOperand()
|
||||||
or
|
or
|
||||||
// Assignment expressions
|
// Assignment expressions
|
||||||
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(Cfg::AssignmentExprNode).getValue()
|
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(AssignmentExprNode).getValue()
|
||||||
or
|
or
|
||||||
// boolean inline expressions such as `x or y` or `x and y`
|
// boolean inline expressions such as `x or y` or `x and y`
|
||||||
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(Cfg::BoolExprNode).getAnOperand()
|
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(BoolExprNode).getAnOperand()
|
||||||
or
|
or
|
||||||
// Flow inside an unpacking assignment
|
// Flow inside an unpacking assignment
|
||||||
iterableUnpackingFlowStep(nodeFrom, nodeTo)
|
iterableUnpackingFlowStep(nodeFrom, nodeTo)
|
||||||
@@ -418,25 +376,12 @@ module LocalFlow {
|
|||||||
matchFlowStep(nodeFrom, nodeTo)
|
matchFlowStep(nodeFrom, nodeTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate useToNextUse(Cfg::NameNode nodeFrom, Cfg::NameNode nodeTo) {
|
predicate useToNextUse(NameNode nodeFrom, NameNode nodeTo) {
|
||||||
// The SSA-level adjacent-use predicate works on specific CFG variants
|
AdjacentUses::adjacentUseUse(nodeFrom, nodeTo)
|
||||||
// (e.g. boolean-outcome `[true]`/`[false]` or emptiness `[empty]`/`[non-empty]`
|
|
||||||
// splits of the same AST node), but dataflow values are insensitive to
|
|
||||||
// those splits — there is at most one `CfgNode` per AST. Project both
|
|
||||||
// ends through `.getNode()` so all variants contribute their use-use
|
|
||||||
// edges to the canonical pair.
|
|
||||||
exists(Cfg::NameNode fromVariant, Cfg::NameNode toVariant |
|
|
||||||
SsaImpl::AdjacentUses::adjacentUseUse(fromVariant, toVariant) and
|
|
||||||
fromVariant.getNode() = nodeFrom.getNode() and
|
|
||||||
toVariant.getNode() = nodeTo.getNode()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate defToFirstUse(SsaImpl::EssaVariable var, Cfg::NameNode nodeTo) {
|
predicate defToFirstUse(EssaVariable var, NameNode nodeTo) {
|
||||||
exists(Cfg::NameNode toVariant |
|
AdjacentUses::firstUse(var.getDefinition(), nodeTo)
|
||||||
SsaImpl::AdjacentUses::firstUse(var.getDefinition(), toVariant) and
|
|
||||||
toVariant.getNode() = nodeTo.getNode()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate useUseFlowStep(Node nodeFrom, Node nodeTo) {
|
predicate useUseFlowStep(Node nodeFrom, Node nodeTo) {
|
||||||
@@ -445,13 +390,12 @@ module LocalFlow {
|
|||||||
// `x = f(y)`
|
// `x = f(y)`
|
||||||
// nodeFrom is `y` on first line
|
// nodeFrom is `y` on first line
|
||||||
// nodeTo is `y` on second line
|
// nodeTo is `y` on second line
|
||||||
exists(SsaImpl::EssaDefinition def, Cfg::NameNode toVariant |
|
exists(EssaDefinition def |
|
||||||
nodeFrom.(CfgNode).getNode() = def.(SsaImpl::EssaNodeDefinition).getDefiningNode()
|
nodeFrom.(CfgNode).getNode() = def.(EssaNodeDefinition).getDefiningNode()
|
||||||
or
|
or
|
||||||
nodeFrom.(ScopeEntryDefinitionNode).getDefinition() = def
|
nodeFrom.(ScopeEntryDefinitionNode).getDefinition() = def
|
||||||
|
|
|
|
||||||
SsaImpl::AdjacentUses::firstUse(def, toVariant) and
|
AdjacentUses::firstUse(def, nodeTo.(CfgNode).getNode())
|
||||||
toVariant.getNode() = nodeTo.(CfgNode).getNode().getNode()
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// Next use after use
|
// Next use after use
|
||||||
@@ -613,9 +557,9 @@ predicate runtimeJumpStep(Node nodeFrom, Node nodeTo) {
|
|||||||
// a parameter with a default value, since the parameter will be in the scope of the
|
// a parameter with a default value, since the parameter will be in the scope of the
|
||||||
// function, while the default value itself will be in the scope that _defines_ the
|
// function, while the default value itself will be in the scope that _defines_ the
|
||||||
// function.
|
// function.
|
||||||
exists(SsaImpl::ParameterDefinition param |
|
exists(ParameterDefinition param |
|
||||||
// note: we go to the _control-flow node_ of the parameter, and not the ESSA node of the parameter, since for type-tracking, the ESSA node is not a LocalSourceNode, so we would get in trouble.
|
// note: we go to the _control-flow node_ of the parameter, and not the ESSA node of the parameter, since for type-tracking, the ESSA node is not a LocalSourceNode, so we would get in trouble.
|
||||||
nodeFrom.asCfgNode().getNode() = param.getParameter().(Parameter).getDefault() and
|
nodeFrom.asCfgNode() = param.getDefault() and
|
||||||
nodeTo.asCfgNode() = param.getDefiningNode()
|
nodeTo.asCfgNode() = param.getDefiningNode()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -719,7 +663,7 @@ predicate neverSkipInPathGraph(Node n) {
|
|||||||
// ```
|
// ```
|
||||||
// we would end up saying that the path MUST not skip the x in `y = x`, which is just
|
// we would end up saying that the path MUST not skip the x in `y = x`, which is just
|
||||||
// annoying and doesn't help the path explanation become clearer.
|
// annoying and doesn't help the path explanation become clearer.
|
||||||
n.asCfgNode() = any(SsaImpl::EssaNodeDefinition def).getDefiningNode()
|
n.asCfgNode() = any(EssaNodeDefinition def).getDefiningNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -930,7 +874,7 @@ predicate listStoreStep(CfgNode nodeFrom, ListElementContent c, CfgNode nodeTo)
|
|||||||
// nodeFrom is `42`, cfg node
|
// nodeFrom is `42`, cfg node
|
||||||
// nodeTo is the list, `[..., 42, ...]`, cfg node
|
// nodeTo is the list, `[..., 42, ...]`, cfg node
|
||||||
// c denotes element of list
|
// c denotes element of list
|
||||||
nodeTo.getNode().(Cfg::ListNode).getAnElement() = nodeFrom.getNode() and
|
nodeTo.getNode().(ListNode).getAnElement() = nodeFrom.getNode() and
|
||||||
not nodeTo.getNode() instanceof UnpackingAssignmentSequenceTarget and
|
not nodeTo.getNode() instanceof UnpackingAssignmentSequenceTarget and
|
||||||
// Suppress unused variable warning
|
// Suppress unused variable warning
|
||||||
c = c
|
c = c
|
||||||
@@ -943,7 +887,7 @@ predicate setStoreStep(CfgNode nodeFrom, SetElementContent c, CfgNode nodeTo) {
|
|||||||
// nodeFrom is `42`, cfg node
|
// nodeFrom is `42`, cfg node
|
||||||
// nodeTo is the set, `{..., 42, ...}`, cfg node
|
// nodeTo is the set, `{..., 42, ...}`, cfg node
|
||||||
// c denotes element of list
|
// c denotes element of list
|
||||||
nodeTo.getNode().(Cfg::SetNode).getAnElement() = nodeFrom.getNode() and
|
nodeTo.getNode().(SetNode).getAnElement() = nodeFrom.getNode() and
|
||||||
// Suppress unused variable warning
|
// Suppress unused variable warning
|
||||||
c = c
|
c = c
|
||||||
}
|
}
|
||||||
@@ -956,7 +900,7 @@ predicate tupleStoreStep(CfgNode nodeFrom, TupleElementContent c, CfgNode nodeTo
|
|||||||
// nodeTo is the tuple, `(..., 42, ...)`, cfg node
|
// nodeTo is the tuple, `(..., 42, ...)`, cfg node
|
||||||
// c denotes element of tuple and index of nodeFrom
|
// c denotes element of tuple and index of nodeFrom
|
||||||
exists(int n |
|
exists(int n |
|
||||||
nodeTo.getNode().(Cfg::TupleNode).getElement(n) = nodeFrom.getNode() and
|
nodeTo.getNode().(TupleNode).getElement(n) = nodeFrom.getNode() and
|
||||||
not nodeTo.getNode() instanceof UnpackingAssignmentSequenceTarget and
|
not nodeTo.getNode() instanceof UnpackingAssignmentSequenceTarget and
|
||||||
c.getIndex() = n
|
c.getIndex() = n
|
||||||
)
|
)
|
||||||
@@ -970,7 +914,7 @@ predicate dictStoreStep(CfgNode nodeFrom, DictionaryElementContent c, Node nodeT
|
|||||||
// nodeTo is the dict, `{..., "key" = 42, ...}`, cfg node
|
// nodeTo is the dict, `{..., "key" = 42, ...}`, cfg node
|
||||||
// c denotes element of dictionary and the key `"key"`
|
// c denotes element of dictionary and the key `"key"`
|
||||||
exists(KeyValuePair item |
|
exists(KeyValuePair item |
|
||||||
item = nodeTo.asCfgNode().(Cfg::DictNode).getNode().(Dict).getAnItem() and
|
item = nodeTo.asCfgNode().(DictNode).getNode().(Dict).getAnItem() and
|
||||||
nodeFrom.getNode().getNode() = item.getValue() and
|
nodeFrom.getNode().getNode() = item.getValue() and
|
||||||
c.getKey() = item.getKey().(StringLiteral).getS()
|
c.getKey() = item.getKey().(StringLiteral).getS()
|
||||||
)
|
)
|
||||||
@@ -985,9 +929,9 @@ predicate dictStoreStep(CfgNode nodeFrom, DictionaryElementContent c, Node nodeT
|
|||||||
private predicate moreDictStoreSteps(CfgNode nodeFrom, DictionaryElementContent c, Node nodeTo) {
|
private predicate moreDictStoreSteps(CfgNode nodeFrom, DictionaryElementContent c, Node nodeTo) {
|
||||||
// NOTE: It's important to add logic to the newtype definition of
|
// NOTE: It's important to add logic to the newtype definition of
|
||||||
// DictionaryElementContent if you add new cases here.
|
// DictionaryElementContent if you add new cases here.
|
||||||
exists(Cfg::SubscriptNode subscript |
|
exists(SubscriptNode subscript |
|
||||||
nodeTo.(PostUpdateNode).getPreUpdateNode().asCfgNode() = subscript.getObject() and
|
nodeTo.(PostUpdateNode).getPreUpdateNode().asCfgNode() = subscript.getObject() and
|
||||||
nodeFrom.asCfgNode() = subscript.(Cfg::DefinitionNode).getValue() and
|
nodeFrom.asCfgNode() = subscript.(DefinitionNode).getValue() and
|
||||||
c.getKey() = subscript.getIndex().getNode().(StringLiteral).getText()
|
c.getKey() = subscript.getIndex().getNode().(StringLiteral).getText()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -1000,8 +944,8 @@ private predicate moreDictStoreSteps(CfgNode nodeFrom, DictionaryElementContent
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate dictClearStep(Node node, DictionaryElementContent c) {
|
predicate dictClearStep(Node node, DictionaryElementContent c) {
|
||||||
exists(Cfg::SubscriptNode subscript |
|
exists(SubscriptNode subscript |
|
||||||
subscript instanceof Cfg::DefinitionNode and
|
subscript instanceof DefinitionNode and
|
||||||
node.asCfgNode() = subscript.getObject() and
|
node.asCfgNode() = subscript.getObject() and
|
||||||
c.getKey() = subscript.getIndex().getNode().(StringLiteral).getText()
|
c.getKey() = subscript.getIndex().getNode().(StringLiteral).getText()
|
||||||
)
|
)
|
||||||
@@ -1080,7 +1024,7 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
|
|||||||
// nodeFrom is `l`, cfg node
|
// nodeFrom is `l`, cfg node
|
||||||
// nodeTo is `l[3]`, cfg node
|
// nodeTo is `l[3]`, cfg node
|
||||||
// c is compatible with 3
|
// c is compatible with 3
|
||||||
nodeFrom.getNode() = nodeTo.getNode().(Cfg::SubscriptNode).getObject() and
|
nodeFrom.getNode() = nodeTo.getNode().(SubscriptNode).getObject() and
|
||||||
(
|
(
|
||||||
c instanceof ListElementContent
|
c instanceof ListElementContent
|
||||||
or
|
or
|
||||||
@@ -1089,10 +1033,10 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
|
|||||||
c instanceof DictionaryElementAnyContent
|
c instanceof DictionaryElementAnyContent
|
||||||
or
|
or
|
||||||
c.(TupleElementContent).getIndex() =
|
c.(TupleElementContent).getIndex() =
|
||||||
nodeTo.getNode().(Cfg::SubscriptNode).getIndex().getNode().(IntegerLiteral).getValue()
|
nodeTo.getNode().(SubscriptNode).getIndex().getNode().(IntegerLiteral).getValue()
|
||||||
or
|
or
|
||||||
c.(DictionaryElementContent).getKey() =
|
c.(DictionaryElementContent).getKey() =
|
||||||
nodeTo.getNode().(Cfg::SubscriptNode).getIndex().getNode().(StringLiteral).getS()
|
nodeTo.getNode().(SubscriptNode).getIndex().getNode().(StringLiteral).getS()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1147,7 +1091,7 @@ module Conversions {
|
|||||||
|
|
||||||
predicate formatReadStep(Node nodeFrom, ContentSet c, Node nodeTo) {
|
predicate formatReadStep(Node nodeFrom, ContentSet c, Node nodeTo) {
|
||||||
// % formatting
|
// % formatting
|
||||||
exists(Cfg::BinaryExprNode fmt | fmt = nodeTo.asCfgNode() |
|
exists(BinaryExprNode fmt | fmt = nodeTo.asCfgNode() |
|
||||||
fmt.getOp() instanceof Mod and
|
fmt.getOp() instanceof Mod and
|
||||||
fmt.getRight() = nodeFrom.asCfgNode()
|
fmt.getRight() = nodeFrom.asCfgNode()
|
||||||
) and
|
) and
|
||||||
|
|||||||
@@ -5,14 +5,11 @@ overlay[local]
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl
|
|
||||||
private import codeql.controlflow.SuccessorType
|
|
||||||
private import DataFlowPrivate
|
private import DataFlowPrivate
|
||||||
import semmle.python.dataflow.new.TypeTracking
|
import semmle.python.dataflow.new.TypeTracking
|
||||||
import Attributes
|
import Attributes
|
||||||
import LocalSources
|
import LocalSources
|
||||||
private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl
|
private import semmle.python.essa.SsaCompute
|
||||||
private import semmle.python.dataflow.new.internal.ImportStar
|
private import semmle.python.dataflow.new.internal.ImportStar
|
||||||
private import semmle.python.frameworks.data.ModelsAsData
|
private import semmle.python.frameworks.data.ModelsAsData
|
||||||
private import FlowSummaryImpl as FlowSummaryImpl
|
private import FlowSummaryImpl as FlowSummaryImpl
|
||||||
@@ -30,18 +27,16 @@ private import semmle.python.frameworks.data.ModelsAsData
|
|||||||
overlay[local]
|
overlay[local]
|
||||||
newtype TNode =
|
newtype TNode =
|
||||||
/** A node corresponding to a control flow node. */
|
/** A node corresponding to a control flow node. */
|
||||||
TCfgNode(Cfg::ControlFlowNode node) {
|
TCfgNode(ControlFlowNode node) {
|
||||||
isExpressionNode(node)
|
isExpressionNode(node)
|
||||||
or
|
or
|
||||||
node.injects(_) and node.getNode() instanceof Pattern
|
node.getNode() instanceof Pattern
|
||||||
} or
|
} or
|
||||||
/**
|
/**
|
||||||
* A node corresponding to a scope entry definition. That is, the value of a variable
|
* A node corresponding to a scope entry definition. That is, the value of a variable
|
||||||
* as it enters a scope.
|
* as it enters a scope.
|
||||||
*/
|
*/
|
||||||
TScopeEntryDefinitionNode(SsaImpl::ScopeEntryDefinition def) {
|
TScopeEntryDefinitionNode(ScopeEntryDefinition def) { not def.getScope() instanceof Module } or
|
||||||
not def.getScope() instanceof Module
|
|
||||||
} or
|
|
||||||
/**
|
/**
|
||||||
* A synthetic node representing the value of an object before a state change.
|
* A synthetic node representing the value of an object before a state change.
|
||||||
*
|
*
|
||||||
@@ -52,15 +47,13 @@ newtype TNode =
|
|||||||
// NOTE: since we can't rely on the call graph, but we want to have synthetic
|
// NOTE: since we can't rely on the call graph, but we want to have synthetic
|
||||||
// pre-update nodes for class calls, we end up getting synthetic pre-update nodes for
|
// pre-update nodes for class calls, we end up getting synthetic pre-update nodes for
|
||||||
// ALL calls :|
|
// ALL calls :|
|
||||||
TSyntheticPreUpdateNode(Cfg::CallNode call) { call.injects(_) } or
|
TSyntheticPreUpdateNode(CallNode call) or
|
||||||
/**
|
/**
|
||||||
* A synthetic node representing the value of an object after a state change.
|
* A synthetic node representing the value of an object after a state change.
|
||||||
* See QLDoc for `PostUpdateNode`.
|
* See QLDoc for `PostUpdateNode`.
|
||||||
*/
|
*/
|
||||||
TSyntheticPostUpdateNode(Cfg::ControlFlowNode node) {
|
TSyntheticPostUpdateNode(ControlFlowNode node) {
|
||||||
node.injects(_) and
|
exists(CallNode call |
|
||||||
(
|
|
||||||
exists(Cfg::CallNode call |
|
|
||||||
node = call.getArg(_)
|
node = call.getArg(_)
|
||||||
or
|
or
|
||||||
node = call.getArgByName(_)
|
node = call.getArgByName(_)
|
||||||
@@ -69,12 +62,12 @@ newtype TNode =
|
|||||||
node = call.getFunction()
|
node = call.getFunction()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
node = any(Cfg::AttrNode a).getObject()
|
node = any(AttrNode a).getObject()
|
||||||
or
|
or
|
||||||
node = any(Cfg::SubscriptNode s).getObject()
|
node = any(SubscriptNode s).getObject()
|
||||||
or
|
or
|
||||||
// self parameter when used implicitly in `super()`
|
// self parameter when used implicitly in `super()`
|
||||||
exists(Class cls, Function func, SsaImpl::ParameterDefinition def |
|
exists(Class cls, Function func, ParameterDefinition def |
|
||||||
func = cls.getAMethod() and
|
func = cls.getAMethod() and
|
||||||
not isStaticmethod(func) and
|
not isStaticmethod(func) and
|
||||||
// this matches what we do in ExtractedParameterNode
|
// this matches what we do in ExtractedParameterNode
|
||||||
@@ -84,7 +77,6 @@ newtype TNode =
|
|||||||
or
|
or
|
||||||
// the iterable argument to the implicit comprehension function
|
// the iterable argument to the implicit comprehension function
|
||||||
node.getNode() = any(Comp c).getIterable()
|
node.getNode() = any(Comp c).getIterable()
|
||||||
)
|
|
||||||
} or
|
} or
|
||||||
/** A node representing a global (module-level) variable in a specific module. */
|
/** A node representing a global (module-level) variable in a specific module. */
|
||||||
TModuleVariableNode(Module m, GlobalVariable v) { v.getScope() = m } or
|
TModuleVariableNode(Module m, GlobalVariable v) { v.getScope() = m } or
|
||||||
@@ -120,9 +112,7 @@ newtype TNode =
|
|||||||
exists(ParameterPosition ppos | ppos.isStarArgs(_) | exists(callable.getParameter(ppos)))
|
exists(ParameterPosition ppos | ppos.isStarArgs(_) | exists(callable.getParameter(ppos)))
|
||||||
} or
|
} or
|
||||||
/** A synthetic node to capture keyword arguments that are passed to a `**kwargs` parameter. */
|
/** A synthetic node to capture keyword arguments that are passed to a `**kwargs` parameter. */
|
||||||
TSynthDictSplatArgumentNode(Cfg::CallNode call) {
|
TSynthDictSplatArgumentNode(CallNode call) { exists(call.getArgByName(_)) } or
|
||||||
call.injects(_) and exists(call.getArgByName(_))
|
|
||||||
} or
|
|
||||||
/** A synthetic node to allow flow to keyword parameters from a `**kwargs` argument. */
|
/** A synthetic node to allow flow to keyword parameters from a `**kwargs` argument. */
|
||||||
TSynthDictSplatParameterNode(DataFlowCallable callable) {
|
TSynthDictSplatParameterNode(DataFlowCallable callable) {
|
||||||
exists(ParameterPosition ppos | ppos.isKeyword(_) | exists(callable.getParameter(ppos)))
|
exists(ParameterPosition ppos | ppos.isKeyword(_) | exists(callable.getParameter(ppos)))
|
||||||
@@ -138,15 +128,15 @@ newtype TNode =
|
|||||||
* A synthetic node representing the values of the variables captured
|
* A synthetic node representing the values of the variables captured
|
||||||
* by the callable being called.
|
* by the callable being called.
|
||||||
*/
|
*/
|
||||||
TSynthCapturedVariablesArgumentNode(Cfg::ControlFlowNode callable) {
|
TSynthCapturedVariablesArgumentNode(ControlFlowNode callable) {
|
||||||
callable.injects(_) and callable = any(Cfg::CallNode c).getFunction()
|
callable = any(CallNode c).getFunction()
|
||||||
} or
|
} or
|
||||||
/**
|
/**
|
||||||
* A synthetic node representing the values of the variables captured
|
* A synthetic node representing the values of the variables captured
|
||||||
* by the callable being called, after the output has been computed.
|
* by the callable being called, after the output has been computed.
|
||||||
*/
|
*/
|
||||||
TSynthCapturedVariablesArgumentPostUpdateNode(Cfg::ControlFlowNode callable) {
|
TSynthCapturedVariablesArgumentPostUpdateNode(ControlFlowNode callable) {
|
||||||
callable.injects(_) and callable = any(Cfg::CallNode c).getFunction()
|
callable = any(CallNode c).getFunction()
|
||||||
} or
|
} or
|
||||||
/** A synthetic node representing the values of variables captured by a comprehension. */
|
/** A synthetic node representing the values of variables captured by a comprehension. */
|
||||||
TSynthCompCapturedVariablesArgumentNode(Comp comp) {
|
TSynthCompCapturedVariablesArgumentNode(Comp comp) {
|
||||||
@@ -204,7 +194,7 @@ class Node extends TNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the control-flow node corresponding to this node, if any. */
|
/** Gets the control-flow node corresponding to this node, if any. */
|
||||||
Cfg::ControlFlowNode asCfgNode() { none() }
|
ControlFlowNode asCfgNode() { none() }
|
||||||
|
|
||||||
/** Gets the expression corresponding to this node, if any. */
|
/** Gets the expression corresponding to this node, if any. */
|
||||||
Expr asExpr() { none() }
|
Expr asExpr() { none() }
|
||||||
@@ -217,14 +207,14 @@ class Node extends TNode {
|
|||||||
|
|
||||||
/** A data-flow node corresponding to a control-flow node. */
|
/** A data-flow node corresponding to a control-flow node. */
|
||||||
class CfgNode extends Node, TCfgNode {
|
class CfgNode extends Node, TCfgNode {
|
||||||
Cfg::ControlFlowNode node;
|
ControlFlowNode node;
|
||||||
|
|
||||||
CfgNode() { this = TCfgNode(node) }
|
CfgNode() { this = TCfgNode(node) }
|
||||||
|
|
||||||
/** Gets the `Cfg::ControlFlowNode` represented by this data-flow node. */
|
/** Gets the `ControlFlowNode` represented by this data-flow node. */
|
||||||
Cfg::ControlFlowNode getNode() { result = node }
|
ControlFlowNode getNode() { result = node }
|
||||||
|
|
||||||
override Cfg::ControlFlowNode asCfgNode() { result = node }
|
override ControlFlowNode asCfgNode() { result = node }
|
||||||
|
|
||||||
/** Gets a textual representation of this element. */
|
/** Gets a textual representation of this element. */
|
||||||
override string toString() { result = node.toString() }
|
override string toString() { result = node.toString() }
|
||||||
@@ -234,9 +224,9 @@ class CfgNode extends Node, TCfgNode {
|
|||||||
override Location getLocation() { result = node.getLocation() }
|
override Location getLocation() { result = node.getLocation() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A data-flow node corresponding to a `Cfg::CallNode` in the control-flow graph. */
|
/** A data-flow node corresponding to a `CallNode` in the control-flow graph. */
|
||||||
class CallCfgNode extends CfgNode, LocalSourceNode {
|
class CallCfgNode extends CfgNode, LocalSourceNode {
|
||||||
override Cfg::CallNode node;
|
override CallNode node;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the data-flow node for the function component of the call corresponding to this data-flow
|
* Gets the data-flow node for the function component of the call corresponding to this data-flow
|
||||||
@@ -317,15 +307,15 @@ ExprNode exprNode(DataFlowExpr e) { result.getNode().getNode() = e }
|
|||||||
* as it enters a scope.
|
* as it enters a scope.
|
||||||
*/
|
*/
|
||||||
class ScopeEntryDefinitionNode extends Node, TScopeEntryDefinitionNode {
|
class ScopeEntryDefinitionNode extends Node, TScopeEntryDefinitionNode {
|
||||||
SsaImpl::ScopeEntryDefinition def;
|
ScopeEntryDefinition def;
|
||||||
|
|
||||||
ScopeEntryDefinitionNode() { this = TScopeEntryDefinitionNode(def) }
|
ScopeEntryDefinitionNode() { this = TScopeEntryDefinitionNode(def) }
|
||||||
|
|
||||||
/** Gets the `SsaImpl::ScopeEntryDefinition` associated with this node. */
|
/** Gets the `ScopeEntryDefinition` associated with this node. */
|
||||||
SsaImpl::ScopeEntryDefinition getDefinition() { result = def }
|
ScopeEntryDefinition getDefinition() { result = def }
|
||||||
|
|
||||||
/** Gets the source variable represented by this node. */
|
/** Gets the source variable represented by this node. */
|
||||||
SsaImpl::SsaSourceVariable getVariable() { result = def.getSourceVariable() }
|
SsaSourceVariable getVariable() { result = def.getSourceVariable() }
|
||||||
|
|
||||||
override Location getLocation() { result = def.getLocation() }
|
override Location getLocation() { result = def.getLocation() }
|
||||||
|
|
||||||
@@ -347,7 +337,7 @@ class ParameterNode extends Node instanceof ParameterNodeImpl {
|
|||||||
/** A parameter node found in the source code (not in a summary). */
|
/** A parameter node found in the source code (not in a summary). */
|
||||||
class ExtractedParameterNode extends ParameterNodeImpl, CfgNode {
|
class ExtractedParameterNode extends ParameterNodeImpl, CfgNode {
|
||||||
//, LocalSourceNode {
|
//, LocalSourceNode {
|
||||||
SsaImpl::ParameterDefinition def;
|
ParameterDefinition def;
|
||||||
|
|
||||||
ExtractedParameterNode() { node = def.getDefiningNode() }
|
ExtractedParameterNode() { node = def.getDefiningNode() }
|
||||||
|
|
||||||
@@ -378,10 +368,10 @@ Node getCallArgApproximation() {
|
|||||||
exists(Class c | result.asExpr() = c.getAMethod().getArg(0))
|
exists(Class c | result.asExpr() = c.getAMethod().getArg(0))
|
||||||
or
|
or
|
||||||
// the object part of an attribute expression (which might be a bound method)
|
// the object part of an attribute expression (which might be a bound method)
|
||||||
result.asCfgNode() = any(Cfg::AttrNode a).getObject()
|
result.asCfgNode() = any(AttrNode a).getObject()
|
||||||
or
|
or
|
||||||
// the function part of any call
|
// the function part of any call
|
||||||
result.asCfgNode() = any(Cfg::CallNode c).getFunction()
|
result.asCfgNode() = any(CallNode c).getFunction()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the extracted argument nodes that do not rely on `getCallArg`. */
|
/** Gets the extracted argument nodes that do not rely on `getCallArg`. */
|
||||||
@@ -390,7 +380,7 @@ private Node implicitArgumentNode() {
|
|||||||
normalCallArg(_, result, _)
|
normalCallArg(_, result, _)
|
||||||
or
|
or
|
||||||
// and self arguments
|
// and self arguments
|
||||||
result.asCfgNode() = any(Cfg::CallNode c).getFunction().(Cfg::AttrNode).getObject()
|
result.asCfgNode() = any(CallNode c).getFunction().(AttrNode).getObject()
|
||||||
or
|
or
|
||||||
// for comprehensions, we allow the synthetic `iterable` argument
|
// for comprehensions, we allow the synthetic `iterable` argument
|
||||||
result.asExpr() = any(Comp c).getIterable()
|
result.asExpr() = any(Comp c).getIterable()
|
||||||
@@ -499,20 +489,17 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
|
|||||||
not result.getScope() = mod
|
not result.getScope() = mod
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a CFG node that corresponds to an assignment of this global variable. */
|
/** Gets an `EssaNode` that corresponds to an assignment of this global variable. */
|
||||||
Node getAWrite() {
|
Node getAWrite() {
|
||||||
exists(Cfg::NameNode n |
|
any(EssaNodeDefinition def).definedBy(var, result.asCfgNode().(DefinitionNode))
|
||||||
n.defines(var) and
|
|
||||||
result.asCfgNode() = n
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the possible values of the variable at the end of import time */
|
/** Gets the possible values of the variable at the end of import time */
|
||||||
CfgNode getADefiningWrite() {
|
CfgNode getADefiningWrite() {
|
||||||
exists(SsaImpl::EssaVariable def |
|
exists(SsaVariable def |
|
||||||
def = any(SsaImpl::EssaVariable ssa_var).getAnUltimateDefinition() and
|
def = any(SsaVariable ssa_var).getAnUltimateDefinition() and
|
||||||
def.getDefinition().(SsaImpl::EssaNodeDefinition).getDefiningNode() = result.asCfgNode() and
|
def.getDefinition() = result.asCfgNode() and
|
||||||
def.getSourceVariable().getVariable() = var
|
def.getVariable() = var
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,7 +516,7 @@ private ModuleVariableNode import_star_read(Node n) {
|
|||||||
overlay[global]
|
overlay[global]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate resolved_import_star_module(Module m, string name, Node n) {
|
private predicate resolved_import_star_module(Module m, string name, Node n) {
|
||||||
exists(Cfg::NameNode nn | nn = n.asCfgNode() |
|
exists(NameNode nn | nn = n.asCfgNode() |
|
||||||
ImportStar::importStarResolvesTo(pragma[only_bind_into](nn), m) and
|
ImportStar::importStarResolvesTo(pragma[only_bind_into](nn), m) and
|
||||||
nn.getId() = name
|
nn.getId() = name
|
||||||
)
|
)
|
||||||
@@ -587,88 +574,88 @@ class StarPatternElementNode extends Node, TStarPatternElementNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node that participates in a conditional split: a CFG node whose
|
* Gets a node that controls whether other nodes are evaluated.
|
||||||
* evaluation outcome (true/false) is used to choose between two
|
|
||||||
* successor basic blocks. In the shared CFG, branching is detected
|
|
||||||
* via typed successor edges (boolean successor types) on the unique
|
|
||||||
* `injects` node for each AST expression.
|
|
||||||
*
|
*
|
||||||
* Users typically obtain a `GuardNode` by casting from a more specific
|
* In the base case, this is the last node of `conditionBlock`, and `flipped` is `false`.
|
||||||
* Cfg type: `g.(Cfg::CallNode)` for a call-based check, etc.
|
* This definition accounts for (short circuting) `and`- and `or`-expressions, as the structure
|
||||||
|
* of basic blocks will reflect their semantics.
|
||||||
|
*
|
||||||
|
* However, in the program
|
||||||
|
* ```python
|
||||||
|
* if not is_safe(path):
|
||||||
|
* return
|
||||||
|
* ```
|
||||||
|
* the last node in the `ConditionBlock` is `not is_safe(path)`.
|
||||||
|
*
|
||||||
|
* We would like to consider also `is_safe(path)` a guard node, albeit with `flipped` being `true`.
|
||||||
|
* Thus we recurse through `not`-expressions.
|
||||||
*/
|
*/
|
||||||
class GuardNode extends Cfg::ControlFlowNode {
|
ControlFlowNode guardNode(ConditionBlock conditionBlock, boolean flipped) {
|
||||||
GuardNode() {
|
// Base case: the last node truly does determine which successor is chosen
|
||||||
// This node has boolean successor edges (directly or via wrapping).
|
result = conditionBlock.getLastNode() and
|
||||||
outcomeOfGuard(this, _, _)
|
flipped = false
|
||||||
}
|
or
|
||||||
|
// Recursive cases:
|
||||||
/** Holds if this guard controls block `b` upon evaluating to `branch`. */
|
// if a guard node is a `not`-expression,
|
||||||
predicate controlsBlock(Cfg::BasicBlock b, boolean branch) {
|
// the operand is also a guard node, but with inverted polarity.
|
||||||
exists(CfgImpl::BasicBlock outcomeBB |
|
exists(UnaryExprNode notNode |
|
||||||
outcomeOfGuard(this, outcomeBB, branch) and
|
result = notNode.getOperand() and
|
||||||
outcomeBB.dominates(b)
|
notNode.getNode().getOp() instanceof Not
|
||||||
|
|
|
||||||
|
notNode = guardNode(conditionBlock, flipped.booleanNot())
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// if a guard node is compared to a boolean literal,
|
||||||
|
// the other operand is also a guard node,
|
||||||
|
// but with polarity depending on the literal (and on the comparison).
|
||||||
|
exists(CompareNode cmpNode, Cmpop op, ControlFlowNode b, boolean should_flip |
|
||||||
|
(
|
||||||
|
cmpNode.operands(result, op, b) or
|
||||||
|
cmpNode.operands(b, op, result)
|
||||||
|
) and
|
||||||
|
not result.getNode() instanceof BooleanLiteral and
|
||||||
|
(
|
||||||
|
// comparing to the boolean
|
||||||
|
(op instanceof Eq or op instanceof Is) and
|
||||||
|
// we should flip if the value compared against, here the value of `b`, is false
|
||||||
|
should_flip = b.getNode().(BooleanLiteral).booleanValue().booleanNot()
|
||||||
|
or
|
||||||
|
// comparing to the negation of the boolean
|
||||||
|
(op instanceof NotEq or op instanceof IsNot) and
|
||||||
|
// again, we should flip if the value compared against, here the value of `not b`, is false.
|
||||||
|
// That is, if the value of `b` is true.
|
||||||
|
should_flip = b.getNode().(BooleanLiteral).booleanValue()
|
||||||
|
)
|
||||||
|
|
|
||||||
|
// we flip `flipped` according to `should_flip` via the formula `flipped xor should_flip`.
|
||||||
|
flipped in [true, false] and
|
||||||
|
cmpNode = guardNode(conditionBlock, flipped.booleanXor(should_flip))
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `outcomeBB` is the basic block entered when `guard` evaluates
|
* A node that controls whether other nodes are evaluated.
|
||||||
* to `branch`.
|
|
||||||
*
|
*
|
||||||
* For a direct guard `if g:`, the outcome BB starts at the after-value
|
* The field `flipped` allows us to match `GuardNode`s underneath
|
||||||
* node for the matching branch. For wrapped guards like `not g` or
|
* `not`-expressions and still choose the appropriate branch.
|
||||||
* `g == True`, we follow those wrappers up the AST to find the
|
|
||||||
* outermost expression that actually branches, with an appropriate
|
|
||||||
* polarity transform.
|
|
||||||
*/
|
*/
|
||||||
private predicate outcomeOfGuard(
|
class GuardNode extends ControlFlowNode {
|
||||||
Cfg::ControlFlowNode guard, CfgImpl::BasicBlock outcomeBB, boolean branch
|
ConditionBlock conditionBlock;
|
||||||
) {
|
boolean flipped;
|
||||||
// Base case: the guard has boolean successor edges.
|
|
||||||
// Only the canonical representative (injects) can act as a guard base.
|
GuardNode() { this = guardNode(conditionBlock, flipped) }
|
||||||
guard.injects(_) and
|
|
||||||
exists(BooleanSuccessor t |
|
/** Holds if this guard controls block `b` upon evaluating to `branch`. */
|
||||||
t.getValue() = branch and
|
predicate controlsBlock(BasicBlock b, boolean branch) {
|
||||||
outcomeBB = guard.(CfgImpl::ControlFlowNode).getASuccessor(t).getBasicBlock()
|
branch in [true, false] and
|
||||||
)
|
conditionBlock.controls(b, branch.booleanXor(flipped))
|
||||||
or
|
}
|
||||||
// Recursive: `not guard` — same outcome split as `guard`, flipped.
|
|
||||||
exists(Cfg::UnaryExprNode notNode, boolean notBranch |
|
|
||||||
notNode.injects(_) and
|
|
||||||
notNode.getOperand().getNode() = guard.getNode() and
|
|
||||||
notNode.getNode().getOp() instanceof Not and
|
|
||||||
outcomeOfGuard(notNode, outcomeBB, notBranch) and
|
|
||||||
branch = notBranch.booleanNot()
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// Recursive: comparisons against a boolean literal.
|
|
||||||
exists(
|
|
||||||
Cfg::CompareNode cmpNode, Cmpop op, Cfg::ControlFlowNode otherOperand,
|
|
||||||
Cfg::ControlFlowNode guardOperand, boolean polarity, boolean cmpBranch
|
|
||||||
|
|
|
||||||
cmpNode.injects(_) and
|
|
||||||
guardOperand.getNode() = guard.getNode() and
|
|
||||||
(
|
|
||||||
cmpNode.operands(guardOperand, op, otherOperand) or
|
|
||||||
cmpNode.operands(otherOperand, op, guardOperand)
|
|
||||||
) and
|
|
||||||
not guard.getNode() instanceof BooleanLiteral and
|
|
||||||
(
|
|
||||||
(op instanceof Eq or op instanceof Is) and
|
|
||||||
polarity = otherOperand.getNode().(BooleanLiteral).booleanValue()
|
|
||||||
or
|
|
||||||
(op instanceof NotEq or op instanceof IsNot) and
|
|
||||||
polarity = otherOperand.getNode().(BooleanLiteral).booleanValue().booleanNot()
|
|
||||||
) and
|
|
||||||
outcomeOfGuard(cmpNode, outcomeBB, cmpBranch) and
|
|
||||||
branch = cmpBranch.booleanXor(polarity.booleanNot())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the guard `g` validates `node` upon evaluating to `branch`.
|
* Holds if the guard `g` validates `node` upon evaluating to `branch`.
|
||||||
*/
|
*/
|
||||||
signature predicate guardChecksSig(GuardNode g, Cfg::ControlFlowNode node, boolean branch);
|
signature predicate guardChecksSig(GuardNode g, ControlFlowNode node, boolean branch);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a set of barrier nodes for a guard that validates a node.
|
* Provides a set of barrier nodes for a guard that validates a node.
|
||||||
@@ -683,9 +670,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
|||||||
result = ParameterizedBarrierGuard<Unit, extendedGuardChecks/4>::getABarrierNode(_)
|
result = ParameterizedBarrierGuard<Unit, extendedGuardChecks/4>::getABarrierNode(_)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate extendedGuardChecks(
|
private predicate extendedGuardChecks(GuardNode g, ControlFlowNode node, boolean branch, Unit u) {
|
||||||
GuardNode g, Cfg::ControlFlowNode node, boolean branch, Unit u
|
|
||||||
) {
|
|
||||||
guardChecks(g, node, branch) and
|
guardChecks(g, node, branch) and
|
||||||
u = u
|
u = u
|
||||||
}
|
}
|
||||||
@@ -695,7 +680,7 @@ bindingset[this]
|
|||||||
private signature class ParamSig;
|
private signature class ParamSig;
|
||||||
|
|
||||||
private module WithParam<ParamSig P> {
|
private module WithParam<ParamSig P> {
|
||||||
signature predicate guardChecksSig(GuardNode g, Cfg::ControlFlowNode node, boolean branch, P param);
|
signature predicate guardChecksSig(GuardNode g, ControlFlowNode node, boolean branch, P param);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -708,16 +693,10 @@ module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guar
|
|||||||
/** Gets a node that is safely guarded by the given guard check with parameter `param`. */
|
/** Gets a node that is safely guarded by the given guard check with parameter `param`. */
|
||||||
overlay[global]
|
overlay[global]
|
||||||
ExprNode getABarrierNode(P param) {
|
ExprNode getABarrierNode(P param) {
|
||||||
exists(GuardNode g, SsaImpl::EssaDefinition def, Cfg::ControlFlowNode node, boolean branch |
|
exists(GuardNode g, EssaDefinition def, ControlFlowNode node, boolean branch |
|
||||||
SsaImpl::AdjacentUses::useOfDef(def, node) and
|
AdjacentUses::useOfDef(def, node) and
|
||||||
guardChecks(g, node, branch, param) and
|
guardChecks(g, node, branch, param) and
|
||||||
SsaImpl::AdjacentUses::useOfDef(def, result.asCfgNode()) and
|
AdjacentUses::useOfDef(def, result.asCfgNode()) and
|
||||||
// The protected use must be a different SSA position than the test
|
|
||||||
// position itself: `controlsBlock` is reflexive on dominance, and
|
|
||||||
// the test expression is an SSA-use position on the def-use chain.
|
|
||||||
// Without this guard, the test position would be returned as a
|
|
||||||
// barrier and block flow before it can reach genuine branch uses.
|
|
||||||
node != result.asCfgNode() and
|
|
||||||
g.controlsBlock(result.asCfgNode().getBasicBlock(), branch)
|
g.controlsBlock(result.asCfgNode().getBasicBlock(), branch)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -733,7 +712,7 @@ module ExternalBarrierGuard {
|
|||||||
private import semmle.python.ApiGraphs
|
private import semmle.python.ApiGraphs
|
||||||
|
|
||||||
overlay[global]
|
overlay[global]
|
||||||
private predicate guardCheck(GuardNode g, Cfg::ControlFlowNode node, boolean branch, string kind) {
|
private predicate guardCheck(GuardNode g, ControlFlowNode node, boolean branch, string kind) {
|
||||||
exists(API::CallNode call, API::Node parameter |
|
exists(API::CallNode call, API::Node parameter |
|
||||||
parameter = call.getAParameter() and
|
parameter = call.getAParameter() and
|
||||||
parameter = ModelOutput::getABarrierGuardNode(kind, branch)
|
parameter = ModelOutput::getABarrierGuardNode(kind, branch)
|
||||||
@@ -769,10 +748,10 @@ newtype TContent =
|
|||||||
TSetElementContent() or
|
TSetElementContent() or
|
||||||
/** An element of a tuple at a specific index. */
|
/** An element of a tuple at a specific index. */
|
||||||
TTupleElementContent(int index) {
|
TTupleElementContent(int index) {
|
||||||
exists(any(Cfg::TupleNode tn).getElement(index))
|
exists(any(TupleNode tn).getElement(index))
|
||||||
or
|
or
|
||||||
// Arguments can overflow and end up in the starred parameter tuple.
|
// Arguments can overflow and end up in the starred parameter tuple.
|
||||||
exists(any(Cfg::CallNode cn).getArg(index))
|
exists(any(CallNode cn).getArg(index))
|
||||||
or
|
or
|
||||||
// since flow summaries might use tuples, we ensure that we at least have valid
|
// since flow summaries might use tuples, we ensure that we at least have valid
|
||||||
// TTupleElementContent for the 0..7 (7 was picked to match `small_tuple` in
|
// TTupleElementContent for the 0..7 (7 was picked to match `small_tuple` in
|
||||||
@@ -789,14 +768,10 @@ newtype TContent =
|
|||||||
or
|
or
|
||||||
// d["key"] = ...
|
// d["key"] = ...
|
||||||
key =
|
key =
|
||||||
any(Cfg::SubscriptNode sub |
|
any(SubscriptNode sub | sub.isStore() | sub.getIndex().getNode().(StringLiteral).getText())
|
||||||
sub.isStore()
|
|
||||||
|
|
|
||||||
sub.getIndex().getNode().(StringLiteral).getText()
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// d.setdefault("key", ...)
|
// d.setdefault("key", ...)
|
||||||
exists(Cfg::CallNode call | call.getFunction().(Cfg::AttrNode).getName() = "setdefault" |
|
exists(CallNode call | call.getFunction().(AttrNode).getName() = "setdefault" |
|
||||||
key = call.getArg(0).getNode().(StringLiteral).getText()
|
key = call.getArg(0).getNode().(StringLiteral).getText()
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
|
|||||||
@@ -5,18 +5,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl
|
|
||||||
private import semmle.python.dataflow.new.DataFlow
|
private import semmle.python.dataflow.new.DataFlow
|
||||||
private import semmle.python.dataflow.new.internal.ImportStar
|
private import semmle.python.dataflow.new.internal.ImportStar
|
||||||
private import semmle.python.dataflow.new.TypeTracking
|
private import semmle.python.dataflow.new.TypeTracking
|
||||||
private import semmle.python.dataflow.new.internal.DataFlowPrivate
|
private import semmle.python.dataflow.new.internal.DataFlowPrivate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the name of `var` refers to a submodule of a package and `init` is
|
* Holds if `init` is a package's `__init__.py` and `var` is a global variable in
|
||||||
* the `__init__` module of that package. Locally inlined replacement for the
|
* `init` whose name matches a submodule of the package.
|
||||||
* legacy `SsaSource::init_module_submodule_defn` so that this module has no
|
*
|
||||||
* direct dependency on `semmle.python.essa.SsaDefinitions`.
|
* Inlined from `SsaSource::init_module_submodule_defn` to avoid pulling
|
||||||
|
* `semmle.python.essa.SsaDefinitions` into the new dataflow stack.
|
||||||
*/
|
*/
|
||||||
private predicate initModuleSubmoduleDefn(GlobalVariable var, Module init) {
|
private predicate initModuleSubmoduleDefn(GlobalVariable var, Module init) {
|
||||||
init.isPackageInit() and
|
init.isPackageInit() and
|
||||||
@@ -82,19 +81,13 @@ module ImportResolution {
|
|||||||
* Holds if there is an ESSA step from `defFrom` to `defTo`, which should be allowed
|
* Holds if there is an ESSA step from `defFrom` to `defTo`, which should be allowed
|
||||||
* for import resolution.
|
* for import resolution.
|
||||||
*/
|
*/
|
||||||
private predicate allowedEssaImportStep(
|
private predicate allowedEssaImportStep(EssaDefinition defFrom, EssaDefinition defTo) {
|
||||||
SsaImpl::EssaDefinition defFrom, SsaImpl::EssaDefinition defTo
|
|
||||||
) {
|
|
||||||
// to handle definitions guarded by if-then-else
|
// to handle definitions guarded by if-then-else
|
||||||
defFrom = defTo.(SsaImpl::PhiFunction).getAnInput()
|
defFrom = defTo.(PhiFunction).getAnInput()
|
||||||
or
|
or
|
||||||
// to handle uncertain writes such as `from X import *`, which create an
|
// refined variable
|
||||||
// uncertain SSA definition for every name in the importing scope. The
|
// example: https://github.com/nvbn/thefuck/blob/ceeaeab94b5df5a4fe9d94d61e4f6b0bbea96378/thefuck/utils.py#L25-L45
|
||||||
// immediately preceding definition is still potentially the value of the
|
defFrom = defTo.(EssaNodeRefinement).getInput().getDefinition()
|
||||||
// module export.
|
|
||||||
SsaImpl::Ssa::uncertainWriteDefinitionInput(defTo, defFrom)
|
|
||||||
// Note: legacy ESSA refinement-step (e.g. for `foo.bar = X`) is
|
|
||||||
// not modelled in the new SSA beyond the cases handled above.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,32 +104,30 @@ module ImportResolution {
|
|||||||
// Definitions made inside `m` itself
|
// Definitions made inside `m` itself
|
||||||
//
|
//
|
||||||
// for code such as `foo = ...; foo.bar = ...` there will be TWO
|
// for code such as `foo = ...; foo.bar = ...` there will be TWO
|
||||||
// SsaImpl::EssaDefinition/SsaImpl::EssaVariable. One for `foo = ...` (SsaImpl::AssignmentDefinition) and one
|
// EssaDefinition/EssaVariable. One for `foo = ...` (AssignmentDefinition) and one
|
||||||
// for `foo.bar = ...`. The one for `foo.bar = ...` (EssaNodeRefinement). The
|
// for `foo.bar = ...`. The one for `foo.bar = ...` (EssaNodeRefinement). The
|
||||||
// EssaNodeRefinement is the one that will reach the end of the module (normal
|
// EssaNodeRefinement is the one that will reach the end of the module (normal
|
||||||
// exit).
|
// exit).
|
||||||
//
|
//
|
||||||
// However, we cannot just use the EssaNodeRefinement as the `val`, because the
|
// However, we cannot just use the EssaNodeRefinement as the `val`, because the
|
||||||
// normal data-flow depends on use-use flow, and use-use flow targets CFG nodes not
|
// normal data-flow depends on use-use flow, and use-use flow targets CFG nodes not
|
||||||
// EssaNodes. So we need to go back from the SsaImpl::EssaDefinition/SsaImpl::EssaVariable that
|
// EssaNodes. So we need to go back from the EssaDefinition/EssaVariable that
|
||||||
// reaches the end of the module, to the first definition of the variable, and then
|
// reaches the end of the module, to the first definition of the variable, and then
|
||||||
// track forwards using use-use flow to find a suitable CFG node that has flow into
|
// track forwards using use-use flow to find a suitable CFG node that has flow into
|
||||||
// it from use-use flow.
|
// it from use-use flow.
|
||||||
exists(SsaImpl::EssaVariable lastUseVar, SsaImpl::EssaVariable firstDef |
|
exists(EssaVariable lastUseVar, EssaVariable firstDef |
|
||||||
lastUseVar.getName() = name and
|
lastUseVar.getName() = name and
|
||||||
// we ignore special variable $ introduced by our analysis (not used for anything)
|
// we ignore special variable $ introduced by our analysis (not used for anything)
|
||||||
// we ignore special variable * introduced by `from <pkg> import *` -- TODO: understand why we even have this?
|
// we ignore special variable * introduced by `from <pkg> import *` -- TODO: understand why we even have this?
|
||||||
not name in ["$", "*"] and
|
not name in ["$", "*"] and
|
||||||
exists(Cfg::ControlFlowNode exit |
|
lastUseVar.getAUse() = m.getANormalExit() and
|
||||||
exit.isNormalExit() and exit.getScope() = m and lastUseVar.getAUse() = exit
|
|
||||||
) and
|
|
||||||
allowedEssaImportStep*(firstDef, lastUseVar) and
|
allowedEssaImportStep*(firstDef, lastUseVar) and
|
||||||
not allowedEssaImportStep(_, firstDef)
|
not allowedEssaImportStep(_, firstDef)
|
||||||
|
|
|
|
||||||
not LocalFlow::defToFirstUse(firstDef, _) and
|
not LocalFlow::defToFirstUse(firstDef, _) and
|
||||||
val.asCfgNode() = firstDef.getDefinition().(SsaImpl::EssaNodeDefinition).getDefiningNode()
|
val.asCfgNode() = firstDef.getDefinition().(EssaNodeDefinition).getDefiningNode()
|
||||||
or
|
or
|
||||||
exists(Cfg::ControlFlowNode mid, Cfg::ControlFlowNode end |
|
exists(ControlFlowNode mid, ControlFlowNode end |
|
||||||
LocalFlow::defToFirstUse(firstDef, mid) and
|
LocalFlow::defToFirstUse(firstDef, mid) and
|
||||||
LocalFlow::useToNextUse*(mid, end) and
|
LocalFlow::useToNextUse*(mid, end) and
|
||||||
not LocalFlow::useToNextUse(end, _) and
|
not LocalFlow::useToNextUse(end, _) and
|
||||||
@@ -164,9 +155,9 @@ module ImportResolution {
|
|||||||
* handles simple cases where we can statically tell that this is the case.
|
* handles simple cases where we can statically tell that this is the case.
|
||||||
*/
|
*/
|
||||||
private predicate all_mentions_name(Module m, string name) {
|
private predicate all_mentions_name(Module m, string name) {
|
||||||
exists(Cfg::DefinitionNode def, Cfg::SequenceNode n |
|
exists(DefinitionNode def, SequenceNode n |
|
||||||
def.getValue() = n and
|
def.getValue() = n and
|
||||||
def.(Cfg::NameNode).getId() = "__all__" and
|
def.(NameNode).getId() = "__all__" and
|
||||||
def.getScope() = m and
|
def.getScope() = m and
|
||||||
any(StringLiteral s | s.getText() = name) = n.getAnElement().getNode()
|
any(StringLiteral s | s.getText() = name) = n.getAnElement().getNode()
|
||||||
)
|
)
|
||||||
@@ -179,20 +170,18 @@ module ImportResolution {
|
|||||||
*/
|
*/
|
||||||
private predicate no_or_complicated_all(Module m) {
|
private predicate no_or_complicated_all(Module m) {
|
||||||
// No mention of `__all__` in the module
|
// No mention of `__all__` in the module
|
||||||
not exists(Cfg::DefinitionNode def |
|
not exists(DefinitionNode def | def.getScope() = m and def.(NameNode).getId() = "__all__")
|
||||||
def.getScope() = m and def.(Cfg::NameNode).getId() = "__all__"
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// `__all__` is set to a non-sequence value
|
// `__all__` is set to a non-sequence value
|
||||||
exists(Cfg::DefinitionNode def |
|
exists(DefinitionNode def |
|
||||||
def.(Cfg::NameNode).getId() = "__all__" and
|
def.(NameNode).getId() = "__all__" and
|
||||||
def.getScope() = m and
|
def.getScope() = m and
|
||||||
not def.getValue() instanceof Cfg::SequenceNode
|
not def.getValue() instanceof SequenceNode
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// `__all__` is used in some way that doesn't involve storing a value in it. This usually means
|
// `__all__` is used in some way that doesn't involve storing a value in it. This usually means
|
||||||
// it is being mutated through `append` or `extend`, which we don't handle.
|
// it is being mutated through `append` or `extend`, which we don't handle.
|
||||||
exists(Cfg::NameNode n | n.getId() = "__all__" and n.getScope() = m and n.isLoad())
|
exists(NameNode n | n.getId() = "__all__" and n.getScope() = m and n.isLoad())
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate potential_module_export(Module m, string name) {
|
private predicate potential_module_export(Module m, string name) {
|
||||||
@@ -200,7 +189,7 @@ module ImportResolution {
|
|||||||
or
|
or
|
||||||
no_or_complicated_all(m) and
|
no_or_complicated_all(m) and
|
||||||
(
|
(
|
||||||
exists(Cfg::NameNode n | n.getId() = name and n.getScope() = m and name.charAt(0) != "_")
|
exists(NameNode n | n.getId() = name and n.getScope() = m and name.charAt(0) != "_")
|
||||||
or
|
or
|
||||||
exists(Alias a | a.getAsname().(Name).getId() = name and a.getValue().getScope() = m)
|
exists(Alias a | a.getAsname().(Name).getId() = name and a.getValue().getScope() = m)
|
||||||
)
|
)
|
||||||
@@ -230,12 +219,12 @@ module ImportResolution {
|
|||||||
|
|
||||||
/** Gets a module that may have been added to `sys.modules`. */
|
/** Gets a module that may have been added to `sys.modules`. */
|
||||||
private Module sys_modules_module_with_name(string name) {
|
private Module sys_modules_module_with_name(string name) {
|
||||||
exists(Cfg::ControlFlowNode n, DataFlow::Node mod |
|
exists(ControlFlowNode n, DataFlow::Node mod |
|
||||||
exists(Cfg::SubscriptNode sub |
|
exists(SubscriptNode sub |
|
||||||
sub.getObject() = sys_modules_reference().asCfgNode() and
|
sub.getObject() = sys_modules_reference().asCfgNode() and
|
||||||
sub.getIndex() = n and
|
sub.getIndex() = n and
|
||||||
n.getNode().(StringLiteral).getText() = name and
|
n.getNode().(StringLiteral).getText() = name and
|
||||||
sub.(Cfg::DefinitionNode).getValue() = mod.asCfgNode() and
|
sub.(DefinitionNode).getValue() = mod.asCfgNode() and
|
||||||
mod = getModuleReference(result)
|
mod = getModuleReference(result)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -347,11 +336,11 @@ module ImportResolution {
|
|||||||
// name as a submodule, we always consider that this attribute _could_ be a
|
// name as a submodule, we always consider that this attribute _could_ be a
|
||||||
// reference to the submodule, even if we don't know that the submodule has been
|
// reference to the submodule, even if we don't know that the submodule has been
|
||||||
// imported yet.
|
// imported yet.
|
||||||
exists(string submodule, Module package, SsaImpl::EssaVariable var |
|
exists(string submodule, Module package, EssaVariable var |
|
||||||
submodule = var.getName() and
|
submodule = var.getName() and
|
||||||
initModuleSubmoduleDefn(var.getSourceVariable().getVariable(), package) and
|
initModuleSubmoduleDefn(var.getSourceVariable(), package) and
|
||||||
m = getModuleFromName(package.getPackageName() + "." + submodule) and
|
m = getModuleFromName(package.getPackageName() + "." + submodule) and
|
||||||
result.asCfgNode() = var.getDefinition().(SsaImpl::EssaNodeDefinition).getDefiningNode()
|
result.asCfgNode() = var.getDefinition().(EssaNodeDefinition).getDefiningNode()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ overlay[local]
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import semmle.python.dataflow.new.internal.Builtins
|
private import semmle.python.dataflow.new.internal.Builtins
|
||||||
private import semmle.python.dataflow.new.internal.ImportResolution
|
private import semmle.python.dataflow.new.internal.ImportResolution
|
||||||
private import semmle.python.dataflow.new.DataFlow
|
private import semmle.python.dataflow.new.DataFlow
|
||||||
@@ -16,7 +15,7 @@ module ImportStar {
|
|||||||
*/
|
*/
|
||||||
overlay[local]
|
overlay[local]
|
||||||
cached
|
cached
|
||||||
predicate namePossiblyDefinedInImportStar(Cfg::NameNode n, string name, Scope s) {
|
predicate namePossiblyDefinedInImportStar(NameNode n, string name, Scope s) {
|
||||||
n.isLoad() and
|
n.isLoad() and
|
||||||
name = n.getId() and
|
name = n.getId() and
|
||||||
s = n.getScope().getEnclosingScope*() and
|
s = n.getScope().getEnclosingScope*() and
|
||||||
@@ -53,7 +52,7 @@ module ImportStar {
|
|||||||
/** Holds if a global variable called `name` is assigned a value in the module `m`. */
|
/** Holds if a global variable called `name` is assigned a value in the module `m`. */
|
||||||
cached
|
cached
|
||||||
predicate globalNameDefinedInModule(string name, Module m) {
|
predicate globalNameDefinedInModule(string name, Module m) {
|
||||||
exists(Cfg::NameNode n |
|
exists(NameNode n |
|
||||||
not exists(LocalVariable v | n.defines(v)) and
|
not exists(LocalVariable v | n.defines(v)) and
|
||||||
n.isStore() and
|
n.isStore() and
|
||||||
name = n.getId() and
|
name = n.getId() and
|
||||||
@@ -67,7 +66,7 @@ module ImportStar {
|
|||||||
*/
|
*/
|
||||||
overlay[global]
|
overlay[global]
|
||||||
cached
|
cached
|
||||||
predicate importStarResolvesTo(Cfg::NameNode n, Module m) {
|
predicate importStarResolvesTo(NameNode n, Module m) {
|
||||||
m = getStarImported+(n.getEnclosingModule()) and
|
m = getStarImported+(n.getEnclosingModule()) and
|
||||||
globalNameDefinedInModule(n.getId(), m) and
|
globalNameDefinedInModule(n.getId(), m) and
|
||||||
not isDefinedLocally(n.getNode())
|
not isDefinedLocally(n.getNode())
|
||||||
@@ -100,7 +99,7 @@ module ImportStar {
|
|||||||
*/
|
*/
|
||||||
overlay[local]
|
overlay[local]
|
||||||
cached
|
cached
|
||||||
Cfg::ControlFlowNode potentialImportStarBase(Scope s) {
|
ControlFlowNode potentialImportStarBase(Scope s) {
|
||||||
result = any(Cfg::ImportStarNode n | n.getScope() = s).getModule()
|
result = any(ImportStarNode n | n.getScope() = s).getModule()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,8 +170,6 @@ overlay[local]
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl
|
|
||||||
private import DataFlowPublic
|
private import DataFlowPublic
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,7 +178,7 @@ private import DataFlowPublic
|
|||||||
* This class abstracts away the differing representations of comprehensions and
|
* This class abstracts away the differing representations of comprehensions and
|
||||||
* for statements.
|
* for statements.
|
||||||
*/
|
*/
|
||||||
class ForTarget extends Cfg::ControlFlowNode {
|
class ForTarget extends ControlFlowNode {
|
||||||
Expr source;
|
Expr source;
|
||||||
|
|
||||||
ForTarget() {
|
ForTarget() {
|
||||||
@@ -200,7 +198,7 @@ class ForTarget extends Cfg::ControlFlowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The LHS of an assignment, it also records the assigned value. */
|
/** The LHS of an assignment, it also records the assigned value. */
|
||||||
class AssignmentTarget extends Cfg::ControlFlowNode {
|
class AssignmentTarget extends ControlFlowNode {
|
||||||
Expr value;
|
Expr value;
|
||||||
|
|
||||||
AssignmentTarget() {
|
AssignmentTarget() {
|
||||||
@@ -211,7 +209,7 @@ class AssignmentTarget extends Cfg::ControlFlowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A direct (or top-level) target of an unpacking assignment. */
|
/** A direct (or top-level) target of an unpacking assignment. */
|
||||||
class UnpackingAssignmentDirectTarget extends Cfg::ControlFlowNode instanceof Cfg::SequenceNode {
|
class UnpackingAssignmentDirectTarget extends ControlFlowNode instanceof SequenceNode {
|
||||||
Expr value;
|
Expr value;
|
||||||
|
|
||||||
UnpackingAssignmentDirectTarget() {
|
UnpackingAssignmentDirectTarget() {
|
||||||
@@ -224,7 +222,7 @@ class UnpackingAssignmentDirectTarget extends Cfg::ControlFlowNode instanceof Cf
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A (possibly recursive) target of an unpacking assignment. */
|
/** A (possibly recursive) target of an unpacking assignment. */
|
||||||
class UnpackingAssignmentTarget extends Cfg::ControlFlowNode {
|
class UnpackingAssignmentTarget extends ControlFlowNode {
|
||||||
UnpackingAssignmentTarget() {
|
UnpackingAssignmentTarget() {
|
||||||
this instanceof UnpackingAssignmentDirectTarget
|
this instanceof UnpackingAssignmentDirectTarget
|
||||||
or
|
or
|
||||||
@@ -233,11 +231,10 @@ class UnpackingAssignmentTarget extends Cfg::ControlFlowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A (possibly recursive) target of an unpacking assignment which is also a sequence. */
|
/** A (possibly recursive) target of an unpacking assignment which is also a sequence. */
|
||||||
class UnpackingAssignmentSequenceTarget extends UnpackingAssignmentTarget instanceof Cfg::SequenceNode
|
class UnpackingAssignmentSequenceTarget extends UnpackingAssignmentTarget instanceof SequenceNode {
|
||||||
{
|
ControlFlowNode getElement(int i) { result = super.getElement(i) }
|
||||||
Cfg::ControlFlowNode getElement(int i) { result = super.getElement(i) }
|
|
||||||
|
|
||||||
Cfg::ControlFlowNode getAnElement() { result = this.getElement(_) }
|
ControlFlowNode getAnElement() { result = this.getElement(_) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -258,7 +255,7 @@ predicate iterableUnpackingAssignmentFlowStep(Node nodeFrom, Node nodeTo) {
|
|||||||
predicate iterableUnpackingForReadStep(CfgNode nodeFrom, Content c, Node nodeTo) {
|
predicate iterableUnpackingForReadStep(CfgNode nodeFrom, Content c, Node nodeTo) {
|
||||||
exists(ForTarget target |
|
exists(ForTarget target |
|
||||||
nodeFrom.getNode().getNode() = target.getSource() and
|
nodeFrom.getNode().getNode() = target.getSource() and
|
||||||
target instanceof Cfg::SequenceNode and
|
target instanceof SequenceNode and
|
||||||
nodeTo = TIterableSequenceNode(target)
|
nodeTo = TIterableSequenceNode(target)
|
||||||
) and
|
) and
|
||||||
(
|
(
|
||||||
@@ -326,11 +323,11 @@ predicate iterableUnpackingConvertingStoreStep(Node nodeFrom, Content c, Node no
|
|||||||
*/
|
*/
|
||||||
predicate iterableUnpackingElementReadStep(Node nodeFrom, Content c, Node nodeTo) {
|
predicate iterableUnpackingElementReadStep(Node nodeFrom, Content c, Node nodeTo) {
|
||||||
exists(
|
exists(
|
||||||
UnpackingAssignmentSequenceTarget target, int index, Cfg::ControlFlowNode element, int starIndex
|
UnpackingAssignmentSequenceTarget target, int index, ControlFlowNode element, int starIndex
|
||||||
|
|
|
|
||||||
target.getElement(starIndex) instanceof Cfg::StarredNode
|
target.getElement(starIndex) instanceof StarredNode
|
||||||
or
|
or
|
||||||
not exists(target.getAnElement().(Cfg::StarredNode)) and
|
not exists(target.getAnElement().(StarredNode)) and
|
||||||
starIndex = -1
|
starIndex = -1
|
||||||
|
|
|
|
||||||
nodeFrom.(CfgNode).getNode() = target and
|
nodeFrom.(CfgNode).getNode() = target and
|
||||||
@@ -345,18 +342,18 @@ predicate iterableUnpackingElementReadStep(Node nodeFrom, Content c, Node nodeTo
|
|||||||
else c.(TupleElementContent).getIndex() >= index - 1
|
else c.(TupleElementContent).getIndex() >= index - 1
|
||||||
) and
|
) and
|
||||||
(
|
(
|
||||||
if element instanceof Cfg::SequenceNode
|
if element instanceof SequenceNode
|
||||||
then
|
then
|
||||||
// Step 5b
|
// Step 5b
|
||||||
nodeTo = TIterableSequenceNode(element)
|
nodeTo = TIterableSequenceNode(element)
|
||||||
else
|
else
|
||||||
if element instanceof Cfg::StarredNode
|
if element instanceof StarredNode
|
||||||
then
|
then
|
||||||
// Step 5c
|
// Step 5c
|
||||||
nodeTo = TIterableElementNode(element)
|
nodeTo = TIterableElementNode(element)
|
||||||
else
|
else
|
||||||
// Step 5a
|
// Step 5a
|
||||||
exists(SsaImpl::MultiAssignmentDefinition mad | element = mad.getDefiningNode() |
|
exists(MultiAssignmentDefinition mad | element = mad.getDefiningNode() |
|
||||||
nodeTo.(CfgNode).getNode() = element
|
nodeTo.(CfgNode).getNode() = element
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -369,7 +366,7 @@ predicate iterableUnpackingElementReadStep(Node nodeFrom, Content c, Node nodeTo
|
|||||||
* content type `ListElementContent`.
|
* content type `ListElementContent`.
|
||||||
*/
|
*/
|
||||||
predicate iterableUnpackingStarredElementStoreStep(Node nodeFrom, Content c, Node nodeTo) {
|
predicate iterableUnpackingStarredElementStoreStep(Node nodeFrom, Content c, Node nodeTo) {
|
||||||
exists(Cfg::ControlFlowNode starred, SsaImpl::MultiAssignmentDefinition mad |
|
exists(ControlFlowNode starred, MultiAssignmentDefinition mad |
|
||||||
starred.getNode() instanceof Starred and
|
starred.getNode() instanceof Starred and
|
||||||
starred = mad.getDefiningNode()
|
starred = mad.getDefiningNode()
|
||||||
|
|
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ overlay[local]
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
import DataFlowPublic
|
import DataFlowPublic
|
||||||
private import DataFlowPrivate
|
private import DataFlowPrivate
|
||||||
private import semmle.python.internal.CachedStages
|
private import semmle.python.internal.CachedStages
|
||||||
@@ -315,7 +314,7 @@ private module Cached {
|
|||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate subscript(LocalSourceNode node, CfgNode subscript, CfgNode index) {
|
predicate subscript(LocalSourceNode node, CfgNode subscript, CfgNode index) {
|
||||||
exists(CfgNode seq, Cfg::SubscriptNode subscriptNode | subscriptNode = subscript.getNode() |
|
exists(CfgNode seq, SubscriptNode subscriptNode | subscriptNode = subscript.getNode() |
|
||||||
node.flowsTo(seq) and
|
node.flowsTo(seq) and
|
||||||
seq.getNode() = subscriptNode.getObject() and
|
seq.getNode() = subscriptNode.getObject() and
|
||||||
index.getNode() = subscriptNode.getIndex()
|
index.getNode() = subscriptNode.getIndex()
|
||||||
|
|||||||
@@ -91,7 +91,9 @@ predicate matchAsFlowStep(Node nodeFrom, Node nodeTo) {
|
|||||||
or
|
or
|
||||||
// the interior pattern flows to the alias
|
// the interior pattern flows to the alias
|
||||||
nodeFrom.(CfgNode).getNode().getNode() = subject.getPattern() and
|
nodeFrom.(CfgNode).getNode().getNode() = subject.getPattern() and
|
||||||
nodeTo.(CfgNode).getNode().getNode() = alias
|
exists(PatternAliasDefinition pad | pad.getDefiningNode().getNode() = alias |
|
||||||
|
nodeTo.(CfgNode).getNode() = pad.getDefiningNode()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,9 +124,11 @@ predicate matchLiteralFlowStep(Node nodeFrom, Node nodeTo) {
|
|||||||
* syntax (toplevel): `case var:`
|
* syntax (toplevel): `case var:`
|
||||||
*/
|
*/
|
||||||
predicate matchCaptureFlowStep(Node nodeFrom, Node nodeTo) {
|
predicate matchCaptureFlowStep(Node nodeFrom, Node nodeTo) {
|
||||||
exists(MatchCapturePattern capture |
|
exists(MatchCapturePattern capture, Name var | capture.getVariable() = var |
|
||||||
nodeFrom.(CfgNode).getNode().getNode() = capture and
|
nodeFrom.(CfgNode).getNode().getNode() = capture and
|
||||||
nodeTo.(CfgNode).getNode().getNode() = capture.getVariable()
|
exists(PatternCaptureDefinition pcd | pcd.getDefiningNode().getNode() = var |
|
||||||
|
nodeTo.(CfgNode).getNode() = pcd.getDefiningNode()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,548 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides the Python SSA implementation built on the new (shared) CFG.
|
|
||||||
*
|
|
||||||
* Mirrors the Java SSA adapter at
|
|
||||||
* `java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll`:
|
|
||||||
* an `InputSig` is defined in terms of positional `(BasicBlock, int)`
|
|
||||||
* variable references, and the shared
|
|
||||||
* `codeql.ssa.Ssa::Make<Location, Cfg, Input>` module is then
|
|
||||||
* instantiated.
|
|
||||||
*
|
|
||||||
* `SourceVariable` is the AST-level `Py::Variable`. Variable references
|
|
||||||
* are looked up via the CFG facade's `NameNode.defines`/`uses`/`deletes`
|
|
||||||
* predicates, which themselves are one-line bridges to AST-level
|
|
||||||
* `Name.defines`/`uses`/`deletes`.
|
|
||||||
*
|
|
||||||
* Implicit-entry definitions are inserted for:
|
|
||||||
* - non-local / global / builtin variables that are read in the scope
|
|
||||||
* but never assigned (no enclosing CFG node defines them),
|
|
||||||
* - captured variables (variables defined in an enclosing scope that
|
|
||||||
* are read inside the scope), and
|
|
||||||
* - parameters, but only if the corresponding parameter name is *not*
|
|
||||||
* itself a CFG node. With the C#-style parameter wiring already
|
|
||||||
* installed in `AstNodeImpl.qll`, parameter names *are* CFG nodes,
|
|
||||||
* so the regular `variableWrite` path handles them — no `i = -1`
|
|
||||||
* entry is needed for ordinary parameters.
|
|
||||||
*/
|
|
||||||
overlay[local?]
|
|
||||||
module;
|
|
||||||
|
|
||||||
private import python as Py
|
|
||||||
private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl
|
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import codeql.ssa.Ssa as SsaImplCommon
|
|
||||||
private import codeql.controlflow.BasicBlock as BB
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapts the Python `Cfg` facade to the shared SSA library's `CfgSig`.
|
|
||||||
* All members are inherited from `Cfg::ControlFlowNode` and
|
|
||||||
* `Cfg::BasicBlock`.
|
|
||||||
*/
|
|
||||||
private module CfgForSsa implements BB::CfgSig<Py::Location> {
|
|
||||||
class ControlFlowNode = CfgImpl::ControlFlowNode;
|
|
||||||
|
|
||||||
class BasicBlock = CfgImpl::BasicBlock;
|
|
||||||
|
|
||||||
class EntryBasicBlock = CfgImpl::Cfg::EntryBasicBlock;
|
|
||||||
|
|
||||||
predicate dominatingEdge = CfgImpl::Cfg::dominatingEdge/2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A source variable for SSA, wrapping a Python AST `Variable`.
|
|
||||||
*
|
|
||||||
* We only track variables that are read at least once in their scope —
|
|
||||||
* tracking write-only variables would be unnecessary work — *except*
|
|
||||||
* for module-scope globals, where the "read" can be external (e.g.
|
|
||||||
* `import mymodule; mymodule.x`). Such globals are tracked
|
|
||||||
* unconditionally so that import-resolution can find their defining
|
|
||||||
* write.
|
|
||||||
*/
|
|
||||||
private newtype TSsaSourceVariable =
|
|
||||||
TPyVar(Py::Variable v) {
|
|
||||||
// Has a use somewhere — read-relevant for SSA.
|
|
||||||
exists(Cfg::NameNode n | n.uses(v))
|
|
||||||
or
|
|
||||||
// Or has a deletion (treated as a write that destroys the value).
|
|
||||||
exists(Cfg::NameNode n | n.deletes(v))
|
|
||||||
or
|
|
||||||
// Or is a module-scope global written in this module — must be
|
|
||||||
// tracked even if never read locally, because importers may read
|
|
||||||
// it as an attribute on the module object.
|
|
||||||
v.getScope() instanceof Py::Module and
|
|
||||||
exists(Cfg::NameNode n | n.defines(v))
|
|
||||||
or
|
|
||||||
// Or is a parameter — parameters must always have a
|
|
||||||
// `ParameterDefinition` for dataflow argument-routing to work,
|
|
||||||
// even if the parameter is never read in its scope. Mirrors
|
|
||||||
// legacy ESSA's `ParameterDefinition` (which fired for every
|
|
||||||
// parameter binding regardless of liveness).
|
|
||||||
exists(Py::Parameter p | p.asName() = v.getAStore())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A source variable for SSA, wrapping a Python AST `Variable`.
|
|
||||||
*/
|
|
||||||
class SsaSourceVariable extends TSsaSourceVariable {
|
|
||||||
/** Gets the underlying Python AST variable. */
|
|
||||||
Py::Variable getVariable() { this = TPyVar(result) }
|
|
||||||
|
|
||||||
/** Gets the (textual) name of this variable. */
|
|
||||||
string getName() { result = this.getVariable().getId() }
|
|
||||||
|
|
||||||
/** Gets a textual representation of this source variable. */
|
|
||||||
string toString() { result = this.getVariable().toString() }
|
|
||||||
|
|
||||||
/** Gets the location of this source variable. */
|
|
||||||
Py::Location getLocation() { result = this.getVariable().getScope().getLocation() }
|
|
||||||
|
|
||||||
/** Gets the scope in which this variable lives. */
|
|
||||||
Py::Scope getScope() { result = this.getVariable().getScope() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a use of this variable as it appears in the source — a `NameNode`
|
|
||||||
* that loads or deletes the variable. Mirrors legacy
|
|
||||||
* `SsaSourceVariable.getASourceUse()`.
|
|
||||||
*/
|
|
||||||
Cfg::ControlFlowNode getASourceUse() {
|
|
||||||
exists(Cfg::NameNode n | result = n |
|
|
||||||
n.uses(this.getVariable()) or n.deletes(this.getVariable())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an implicit use of this variable. The new SSA does not have
|
|
||||||
* implicit-use refinements, but we keep this for API parity — every
|
|
||||||
* normal-exit of the variable's scope counts as a sink, ensuring
|
|
||||||
* variables stay live to scope exit for taint-tracking.
|
|
||||||
*/
|
|
||||||
Cfg::ControlFlowNode getAnImplicitUse() {
|
|
||||||
result.isNormalExit() and result.getScope() = this.getScope()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a use of this variable — either an explicit source use or an
|
|
||||||
* implicit use at scope exit. Mirrors legacy `SsaSourceVariable.getAUse()`.
|
|
||||||
*/
|
|
||||||
Cfg::ControlFlowNode getAUse() {
|
|
||||||
result = this.getASourceUse() or result = this.getAnImplicitUse()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `v` is a non-local read in scope `s`, in the sense that `s`
|
|
||||||
* uses `v` but does not write it within `s`. This includes globals,
|
|
||||||
* builtins, and variables captured from an enclosing function scope.
|
|
||||||
*
|
|
||||||
* The `Py::Variable` `v` lives in some defining scope (the module for
|
|
||||||
* globals, an outer function for closures, etc.); the reading scope
|
|
||||||
* `s` is the scope where the use of `v` occurs.
|
|
||||||
*/
|
|
||||||
private predicate nonLocalReadIn(Py::Variable v, Py::Scope s) {
|
|
||||||
exists(Cfg::NameNode n |
|
|
||||||
n.uses(v) and
|
|
||||||
n.getScope() = s and
|
|
||||||
not exists(Cfg::NameNode def | def.defines(v) and def.getScope() = s)
|
|
||||||
) and
|
|
||||||
// Match legacy ESSA: only create entry defs for variables that have
|
|
||||||
// at least one defining store somewhere — otherwise the entry def
|
|
||||||
// represents "nothing reaches here", which is the default anyway and
|
|
||||||
// introduces no useful flow. (Legacy's `ModuleVariable` required a
|
|
||||||
// store; this is the closure-aware generalisation.)
|
|
||||||
exists(Cfg::NameNode store | store.defines(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `bb` is the entry basic block of a scope where `v` should
|
|
||||||
* have an implicit entry definition. This covers:
|
|
||||||
* - non-local / global / builtin variables read in `s`, and
|
|
||||||
* - captured variables (defined in an enclosing scope but read in `s`).
|
|
||||||
*
|
|
||||||
* Each reading scope gets its own entry def, so a closure variable can
|
|
||||||
* have multiple entry defs across all functions/methods that read it.
|
|
||||||
*
|
|
||||||
* Parameters are *not* included: their bound `Name` is itself a CFG
|
|
||||||
* node (per the C#-style parameter wiring), so `variableWrite` fires at
|
|
||||||
* the parameter's natural CFG index.
|
|
||||||
*/
|
|
||||||
private predicate hasEntryDefIn(SsaSourceVariable v, CfgImpl::BasicBlock bb) {
|
|
||||||
exists(Py::Scope s |
|
|
||||||
nonLocalReadIn(v.getVariable(), s) and
|
|
||||||
bb = entryBlock(s)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the entry basic block of scope `s`, where implicit entry
|
|
||||||
* definitions are placed (at synthetic index `-1`).
|
|
||||||
*/
|
|
||||||
private CfgImpl::BasicBlock entryBlock(Py::Scope s) {
|
|
||||||
exists(CfgImpl::ControlFlowNode entry |
|
|
||||||
entry instanceof CfgImpl::ControlFlow::EntryNode and
|
|
||||||
entry.getEnclosingCallable().asScope() = s and
|
|
||||||
result = entry.getBasicBlock()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The SSA `InputSig` for Python. References are positional
|
|
||||||
* `(BasicBlock, int)` pairs into the new CFG.
|
|
||||||
*/
|
|
||||||
private module SsaImplInput implements SsaImplCommon::InputSig<Py::Location, CfgImpl::BasicBlock> {
|
|
||||||
class SourceVariable = SsaSourceVariable;
|
|
||||||
|
|
||||||
predicate variableWrite(CfgImpl::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
|
||||||
// Explicit binding at a CFG node — includes assignments,
|
|
||||||
// parameter Names (wired in via the C# pattern), exception-handler
|
|
||||||
// `as`-bindings, import aliases, and match-pattern captures.
|
|
||||||
exists(Cfg::NameNode n |
|
|
||||||
bb.getNode(i) = n and
|
|
||||||
n.defines(v.getVariable()) and
|
|
||||||
certain = true
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// `del x` — removes the binding. Modelled as a certain write that
|
|
||||||
// makes any subsequent read invalid.
|
|
||||||
exists(Cfg::NameNode n |
|
|
||||||
bb.getNode(i) = n and
|
|
||||||
n.deletes(v.getVariable()) and
|
|
||||||
certain = true
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// Implicit entry definition for non-local / captured / global /
|
|
||||||
// builtin variables read in some scope. Each reading scope's entry
|
|
||||||
// block gets one such write, allowing closures: e.g. when `x` is a
|
|
||||||
// parameter of an outer function and read inside a nested
|
|
||||||
// function, both scopes get entry defs for `x`.
|
|
||||||
hasEntryDefIn(v, bb) and
|
|
||||||
i = -1 and
|
|
||||||
certain = true
|
|
||||||
or
|
|
||||||
// `from X import *` — possibly rebinds every name in the importing
|
|
||||||
// scope. Modelled as an uncertain write at the import-star's CFG
|
|
||||||
// position for every variable that lives in (or is referenced
|
|
||||||
// from) the same scope as the import-star. Mirrors legacy ESSA's
|
|
||||||
// `ImportStarRefinement` (see `essa/SsaDefinitions.qll`'s
|
|
||||||
// `import_star_refinement` predicate). The write is uncertain so
|
|
||||||
// that prior definitions of the variable remain available — the
|
|
||||||
// shared-SSA `SsaUncertainWrite` merges the new value with the
|
|
||||||
// immediately preceding definition.
|
|
||||||
exists(Cfg::ImportStarNode imp |
|
|
||||||
imp.injects(_) and
|
|
||||||
bb.getNode(i) = imp and
|
|
||||||
certain = false and
|
|
||||||
(
|
|
||||||
v.getVariable().getScope() = imp.getScope()
|
|
||||||
or
|
|
||||||
// Variable is defined in some other scope but referenced in
|
|
||||||
// the same scope as the import-star (matches legacy clause 2:
|
|
||||||
// `other.uses(v) and def.getScope() = other.getScope()`).
|
|
||||||
exists(Cfg::NameNode other |
|
|
||||||
other.uses(v.getVariable()) and
|
|
||||||
imp.getScope() = other.getScope()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate variableRead(CfgImpl::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
|
||||||
// Explicit source use — a `Name` load or a `del x` of the variable.
|
|
||||||
exists(Cfg::NameNode n |
|
|
||||||
bb.getNode(i) = n and
|
|
||||||
n.uses(v.getVariable()) and
|
|
||||||
certain = true
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// Synthetic use at the normal exit of the variable's defining scope.
|
|
||||||
// This keeps every variable live to scope exit so that callers (e.g.
|
|
||||||
// `module_export` in ImportResolution.qll, or taint-tracking pass-through
|
|
||||||
// through unread locals) can ask "which definition reaches end of
|
|
||||||
// scope?". Mirrors legacy ESSA's `SsaSourceVariable.getAUse()` which
|
|
||||||
// included `getScope().getANormalExit()`.
|
|
||||||
exists(Cfg::ControlFlowNode exit |
|
|
||||||
exit.isNormalExit() and
|
|
||||||
exit.getScope() = v.getVariable().getScope() and
|
|
||||||
bb.getNode(i) = exit and
|
|
||||||
certain = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The shared SSA instantiation for Python.
|
|
||||||
*
|
|
||||||
* Members:
|
|
||||||
* - `Definition` — the union of explicit, uncertain, and phi definitions
|
|
||||||
* - `WriteDefinition`, `UncertainWriteDefinition`, `PhiNode`
|
|
||||||
* - the standard SSA predicates (`getAUse`, `getAnUltimateDefinition`, ...).
|
|
||||||
*/
|
|
||||||
module Ssa = SsaImplCommon::Make<Py::Location, CfgForSsa, SsaImplInput>;
|
|
||||||
|
|
||||||
final class Definition = Ssa::Definition;
|
|
||||||
|
|
||||||
final class WriteDefinition = Ssa::WriteDefinition;
|
|
||||||
|
|
||||||
final class UncertainWriteDefinition = Ssa::UncertainWriteDefinition;
|
|
||||||
|
|
||||||
final class PhiNode = Ssa::PhiNode;
|
|
||||||
|
|
||||||
// ===========================================================================
|
|
||||||
// ESSA-shaped adapter layer
|
|
||||||
//
|
|
||||||
// The dataflow library (`python/ql/lib/semmle/python/dataflow/new/`) and
|
|
||||||
// related modules (`ApiGraphs.qll`, etc.) consume the legacy ESSA API
|
|
||||||
// (`EssaVariable`, `EssaDefinition`, `AssignmentDefinition`,
|
|
||||||
// `ScopeEntryDefinition`, `ParameterDefinition`, `WithDefinition`,
|
|
||||||
// `PhiFunction`, plus the `AdjacentUses` module). To migrate them off
|
|
||||||
// the legacy CFG, we expose the same API surface on top of the
|
|
||||||
// shared SSA built above.
|
|
||||||
//
|
|
||||||
// This adapter is intentionally narrow: it covers only the predicates
|
|
||||||
// that new dataflow consumes. The richer legacy ESSA — refinement
|
|
||||||
// nodes, attribute refinements, edge refinements — stays available
|
|
||||||
// via `semmle.python.essa.Essa` for points-to / legacy code.
|
|
||||||
// ===========================================================================
|
|
||||||
/**
|
|
||||||
* Gets the CFG node at which a write definition's binding takes place.
|
|
||||||
*
|
|
||||||
* For ordinary writes (assignment, deletion, parameter) this is the
|
|
||||||
* canonical CFG node of the bound Name. For implicit entry definitions
|
|
||||||
* (synthesised at position `-1` of a scope's entry BB) this is the
|
|
||||||
* scope's entry node.
|
|
||||||
*/
|
|
||||||
private Cfg::ControlFlowNode writeDefNode(Ssa::WriteDefinition def) {
|
|
||||||
exists(CfgImpl::BasicBlock bb, int i | def.definesAt(_, bb, i) |
|
|
||||||
i >= 0 and result = bb.getNode(i)
|
|
||||||
or
|
|
||||||
i = -1 and result = bb.getNode(0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A write definition whose binding has a corresponding CFG node — i.e.
|
|
||||||
* everything that's not a phi node. Mirrors legacy ESSA's
|
|
||||||
* `EssaNodeDefinition`.
|
|
||||||
*/
|
|
||||||
class EssaNodeDefinition extends Ssa::WriteDefinition {
|
|
||||||
/** Gets the CFG node where this definition's binding takes place. */
|
|
||||||
Cfg::ControlFlowNode getDefiningNode() { result = writeDefNode(this) }
|
|
||||||
|
|
||||||
/** Gets the variable defined here (legacy name). */
|
|
||||||
SsaSourceVariable getVariable() { result = this.getSourceVariable() }
|
|
||||||
|
|
||||||
/** Gets the enclosing scope. */
|
|
||||||
Py::Scope getScope() {
|
|
||||||
exists(Cfg::ControlFlowNode n | n = this.getDefiningNode() | result = n.getScope())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this definition defines source variable `v` at CFG node
|
|
||||||
* `defNode`. Flatter form of `getSourceVariable()` +
|
|
||||||
* `getDefiningNode()`, matching legacy ESSA's `definedBy`.
|
|
||||||
*/
|
|
||||||
predicate definedBy(SsaSourceVariable v, Cfg::ControlFlowNode defNode) {
|
|
||||||
v = this.getSourceVariable() and defNode = this.getDefiningNode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An assignment definition: any binding where the value being assigned
|
|
||||||
* is statically known via `Cfg::DefinitionNode.getValue()`. Includes
|
|
||||||
* plain assignments, walrus, annotated assignments, augmented
|
|
||||||
* assignments, import aliases (`import x` / `from m import x [as y]`),
|
|
||||||
* `with ... as x`, and for-target bindings (where `getValue()` returns
|
|
||||||
* the iter expression's CFG node). Excludes parameter bindings —
|
|
||||||
* those are modelled by `ParameterDefinition`.
|
|
||||||
*/
|
|
||||||
class AssignmentDefinition extends EssaNodeDefinition {
|
|
||||||
AssignmentDefinition() {
|
|
||||||
exists(Cfg::NameNode n | n = this.getDefiningNode() |
|
|
||||||
exists(n.(Cfg::DefinitionNode).getValue()) and
|
|
||||||
not n.(Cfg::ControlFlowNode).isParameter()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the CFG node for the value being assigned, if statically known. */
|
|
||||||
Cfg::ControlFlowNode getValue() {
|
|
||||||
result = this.getDefiningNode().(Cfg::DefinitionNode).getValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A parameter definition — the binding of a parameter name in a
|
|
||||||
* function's scope.
|
|
||||||
*/
|
|
||||||
class ParameterDefinition extends EssaNodeDefinition {
|
|
||||||
ParameterDefinition() { this.getDefiningNode().isParameter() }
|
|
||||||
|
|
||||||
/** Gets the AST `Parameter` (a `Py::Name` in param context). */
|
|
||||||
Py::Name getParameter() { result = this.getDefiningNode().getNode() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A definition introduced by a `with ... as x:` clause.
|
|
||||||
*/
|
|
||||||
class WithDefinition extends EssaNodeDefinition {
|
|
||||||
WithDefinition() {
|
|
||||||
exists(Cfg::NameNode n, Py::With w |
|
|
||||||
n = this.getDefiningNode() and
|
|
||||||
w.getOptionalVars() = n.getNode()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An assignment where the LHS is a tuple/list and the RHS is unpacked:
|
|
||||||
* `a, b = (1, 2)` or `a, *rest = xs`. The SSA def lives at the inner
|
|
||||||
* `Name` CFG node, but for IterableUnpacking integration we expose
|
|
||||||
* the enclosing `StarredNode` as the `getDefiningNode()` for `*rest`
|
|
||||||
* patterns — mirroring legacy ESSA's `multi_assignment_definition`,
|
|
||||||
* which placed the def at the StarredNode CFG node.
|
|
||||||
*/
|
|
||||||
class MultiAssignmentDefinition extends EssaNodeDefinition {
|
|
||||||
MultiAssignmentDefinition() {
|
|
||||||
exists(Cfg::NameNode n | n = super.getDefiningNode() |
|
|
||||||
exists(Py::Assign a, Py::Expr lhs |
|
|
||||||
a.getATarget() = lhs and
|
|
||||||
(lhs instanceof Py::Tuple or lhs instanceof Py::List) and
|
|
||||||
lhs.getASubExpression+() = n.getNode()
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// For-loop with tuple/list target: `for a, b in xs:` —
|
|
||||||
// tuple-unpacking semantics applies to the for-target.
|
|
||||||
exists(Py::For f, Py::Expr lhs |
|
|
||||||
f.getTarget() = lhs and
|
|
||||||
(lhs instanceof Py::Tuple or lhs instanceof Py::List) and
|
|
||||||
lhs.getASubExpression+() = n.getNode()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override Cfg::ControlFlowNode getDefiningNode() {
|
|
||||||
// Default: the underlying `Name` CFG node (where the SSA def lives).
|
|
||||||
not exists(Cfg::StarredNode s |
|
|
||||||
s.getNode().(Py::Starred).getValue() = super.getDefiningNode().getNode()
|
|
||||||
) and
|
|
||||||
result = super.getDefiningNode()
|
|
||||||
or
|
|
||||||
// Exception: for `*rest`, expose the enclosing `Starred` CFG node
|
|
||||||
// so that `IterableUnpacking::iterableUnpackingStarredElementStoreStep`
|
|
||||||
// can attach the rest-list to it.
|
|
||||||
exists(Cfg::StarredNode s |
|
|
||||||
s.getNode().(Py::Starred).getValue() = super.getDefiningNode().getNode()
|
|
||||||
|
|
|
||||||
result = s
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An implicit entry definition for a non-local / captured / global /
|
|
||||||
* builtin variable read in a scope but not defined there.
|
|
||||||
*
|
|
||||||
* Inherits from `EssaNodeDefinition` and exposes the scope's entry node
|
|
||||||
* as its defining node (matching legacy ESSA semantics).
|
|
||||||
*/
|
|
||||||
class ScopeEntryDefinition extends EssaNodeDefinition {
|
|
||||||
ScopeEntryDefinition() {
|
|
||||||
exists(CfgImpl::BasicBlock bb |
|
|
||||||
this.definesAt(_, bb, -1) and
|
|
||||||
bb instanceof CfgImpl::Cfg::EntryBasicBlock
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the enclosing scope (the scope whose entry block this def is in). */
|
|
||||||
override Py::Scope getScope() {
|
|
||||||
exists(CfgImpl::BasicBlock bb |
|
|
||||||
this.definesAt(_, bb, -1) and
|
|
||||||
result = bb.getNode(0).(Cfg::ControlFlowNode).getScope()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A phi node (alias matching legacy naming). */
|
|
||||||
class PhiFunction extends PhiNode {
|
|
||||||
/**
|
|
||||||
* Gets an input to this phi function (a definition that flows into
|
|
||||||
* the phi from one of its predecessor blocks). Mirrors legacy
|
|
||||||
* ESSA's `PhiFunction.getAnInput()`.
|
|
||||||
*/
|
|
||||||
Ssa::Definition getAnInput() { Ssa::phiHasInputFromBlock(this, result, _) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Base class for all ESSA definitions (legacy-shaped). */
|
|
||||||
class EssaDefinition = Ssa::Definition;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An adapter representing a single SSA-defined "variable" — wrapping
|
|
||||||
* one `Ssa::Definition`. Mirrors legacy `EssaVariable` API.
|
|
||||||
*/
|
|
||||||
class EssaVariable extends Ssa::Definition {
|
|
||||||
/** Gets the underlying SSA definition (legacy name). */
|
|
||||||
Ssa::Definition getDefinition() { result = this }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a CFG node where this definition is used. Includes regular
|
|
||||||
* `Name` reads as well as the synthetic scope-exit "use" registered
|
|
||||||
* via `SsaImplInput::variableRead` — mirrors legacy ESSA's
|
|
||||||
* `EssaVariable.getAUse()` which inherited the synthetic exit-use
|
|
||||||
* from `SsaSourceVariable`.
|
|
||||||
*/
|
|
||||||
Cfg::ControlFlowNode getAUse() {
|
|
||||||
exists(CfgImpl::BasicBlock bb, int i |
|
|
||||||
Ssa::ssaDefReachesRead(this.getSourceVariable(), this, bb, i) and
|
|
||||||
bb.getNode(i) = result
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the (textual) name of the underlying variable. */
|
|
||||||
string getName() { result = this.getSourceVariable().getVariable().getId() }
|
|
||||||
|
|
||||||
/** Gets the scope in which this variable lives. */
|
|
||||||
Py::Scope getScope() { result = this.getSourceVariable().getVariable().getScope() }
|
|
||||||
|
|
||||||
/** Gets an ultimate non-phi ancestor of this definition. */
|
|
||||||
EssaVariable getAnUltimateDefinition() {
|
|
||||||
if this instanceof PhiNode
|
|
||||||
then
|
|
||||||
exists(Ssa::Definition input |
|
|
||||||
Ssa::phiHasInputFromBlock(this, input, _) and
|
|
||||||
result = input.(EssaVariable).getAnUltimateDefinition()
|
|
||||||
)
|
|
||||||
else result = this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjacent use-use and def-use relations exposed by the shared SSA
|
|
||||||
* library. Provides the same interface as legacy
|
|
||||||
* `semmle.python.essa.SsaCompute::AdjacentUses`.
|
|
||||||
*/
|
|
||||||
module AdjacentUses {
|
|
||||||
/** Holds if `nodeFrom` and `nodeTo` are adjacent uses of the same SSA variable. */
|
|
||||||
predicate adjacentUseUse(Cfg::NameNode nodeFrom, Cfg::NameNode nodeTo) {
|
|
||||||
exists(SsaSourceVariable v, CfgImpl::BasicBlock bb1, int i1, CfgImpl::BasicBlock bb2, int i2 |
|
|
||||||
Ssa::adjacentUseUse(bb1, i1, bb2, i2, v, _) and
|
|
||||||
nodeFrom = bb1.getNode(i1) and
|
|
||||||
nodeTo = bb2.getNode(i2)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `use` is a first use of definition `def`. */
|
|
||||||
predicate firstUse(Ssa::Definition def, Cfg::NameNode use) {
|
|
||||||
exists(CfgImpl::BasicBlock bb, int i |
|
|
||||||
Ssa::firstUse(def, bb, i, _) and
|
|
||||||
use = bb.getNode(i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `use` is any reachable use of definition `def`. Combines
|
|
||||||
* `firstUse` with transitive use-use adjacency.
|
|
||||||
*/
|
|
||||||
predicate useOfDef(Ssa::Definition def, Cfg::NameNode use) {
|
|
||||||
firstUse(def, use)
|
|
||||||
or
|
|
||||||
exists(Cfg::NameNode mid | useOfDef(def, mid) and adjacentUseUse(mid, use))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
private import python
|
private import python
|
||||||
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
||||||
private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl
|
|
||||||
private import semmle.python.dataflow.new.DataFlow
|
private import semmle.python.dataflow.new.DataFlow
|
||||||
private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate
|
private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate
|
||||||
private import FlowSummaryImpl as FlowSummaryImpl
|
private import FlowSummaryImpl as FlowSummaryImpl
|
||||||
@@ -99,7 +97,7 @@ import Cached
|
|||||||
* and isn't a big problem in practice.
|
* and isn't a big problem in practice.
|
||||||
*/
|
*/
|
||||||
predicate concatStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
|
predicate concatStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
|
||||||
exists(Cfg::BinaryExprNode add | add = nodeTo.getNode() |
|
exists(BinaryExprNode add | add = nodeTo.getNode() |
|
||||||
add.getOp() instanceof Add and add.getAnOperand() = nodeFrom.getNode()
|
add.getOp() instanceof Add and add.getAnOperand() = nodeFrom.getNode()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -108,7 +106,7 @@ predicate concatStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
|
|||||||
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to subscripting.
|
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to subscripting.
|
||||||
*/
|
*/
|
||||||
predicate subscriptStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
|
predicate subscriptStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
|
||||||
nodeTo.getNode().(Cfg::SubscriptNode).getObject() = nodeFrom.getNode()
|
nodeTo.getNode().(SubscriptNode).getObject() = nodeFrom.getNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,15 +122,15 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
|
|||||||
(
|
(
|
||||||
call = API::builtin(["str", "bytes", "unicode"]).getACall()
|
call = API::builtin(["str", "bytes", "unicode"]).getACall()
|
||||||
or
|
or
|
||||||
call.getFunction().asCfgNode().(Cfg::NameNode).getId() in ["str", "bytes", "unicode"]
|
call.getFunction().asCfgNode().(NameNode).getId() in ["str", "bytes", "unicode"]
|
||||||
) and
|
) and
|
||||||
nodeFrom in [call.getArg(0), call.getArgByName("object")]
|
nodeFrom in [call.getArg(0), call.getArgByName("object")]
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// String methods. Note that this doesn't recognize `meth = "foo".upper; meth()`
|
// String methods. Note that this doesn't recognize `meth = "foo".upper; meth()`
|
||||||
exists(Cfg::CallNode call, string method_name, Cfg::ControlFlowNode object |
|
exists(CallNode call, string method_name, ControlFlowNode object |
|
||||||
call = nodeTo.getNode() and
|
call = nodeTo.getNode() and
|
||||||
object = call.getFunction().(Cfg::AttrNode).getObject(method_name)
|
object = call.getFunction().(AttrNode).getObject(method_name)
|
||||||
|
|
|
|
||||||
nodeFrom.getNode() = object and
|
nodeFrom.getNode() = object and
|
||||||
method_name in [
|
method_name in [
|
||||||
@@ -158,7 +156,7 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// % formatting
|
// % formatting
|
||||||
exists(Cfg::BinaryExprNode fmt | fmt = nodeTo.getNode() |
|
exists(BinaryExprNode fmt | fmt = nodeTo.getNode() |
|
||||||
fmt.getOp() instanceof Mod and
|
fmt.getOp() instanceof Mod and
|
||||||
(
|
(
|
||||||
fmt.getLeft() = nodeFrom.getNode()
|
fmt.getLeft() = nodeFrom.getNode()
|
||||||
@@ -168,7 +166,7 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// string multiplication -- `"foo" * 10`
|
// string multiplication -- `"foo" * 10`
|
||||||
exists(Cfg::BinaryExprNode mult | mult = nodeTo.getNode() |
|
exists(BinaryExprNode mult | mult = nodeTo.getNode() |
|
||||||
mult.getOp() instanceof Mult and
|
mult.getOp() instanceof Mult and
|
||||||
mult.getLeft() = nodeFrom.getNode()
|
mult.getLeft() = nodeFrom.getNode()
|
||||||
)
|
)
|
||||||
@@ -215,8 +213,8 @@ predicate awaitStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
|||||||
* the variable `f` is tainted if the result of `open("foo")` is tainted.
|
* the variable `f` is tainted if the result of `open("foo")` is tainted.
|
||||||
*/
|
*/
|
||||||
predicate asyncWithStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
predicate asyncWithStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||||
exists(With with, Cfg::ControlFlowNode contextManager, Cfg::ControlFlowNode var |
|
exists(With with, ControlFlowNode contextManager, ControlFlowNode var |
|
||||||
var = any(SsaImpl::WithDefinition wd).getDefiningNode()
|
var = any(WithDefinition wd).getDefiningNode()
|
||||||
|
|
|
|
||||||
nodeFrom.(DataFlow::CfgNode).getNode() = contextManager and
|
nodeFrom.(DataFlow::CfgNode).getNode() = contextManager and
|
||||||
nodeTo.(DataFlow::CfgNode).getNode() = var and
|
nodeTo.(DataFlow::CfgNode).getNode() = var and
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user