mirror of
https://github.com/github/codeql.git
synced 2026-05-14 11:19:27 +02:00
Checkpoint from VS Code for cloud agent session
This commit is contained in:
@@ -5,66 +5,27 @@ overlay[local]
|
||||
module;
|
||||
|
||||
import go
|
||||
private import ControlFlowGraphImpl
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
private import codeql.controlflow.SuccessorType
|
||||
private import ControlFlowGraphShared
|
||||
|
||||
private module Input implements BB::InputSig<Location> {
|
||||
/** A delineated part of the AST with its own CFG. */
|
||||
class CfgScope = ControlFlow::Root;
|
||||
/** A basic block in the control-flow graph. */
|
||||
class BasicBlock = GoCfg::Cfg::BasicBlock;
|
||||
|
||||
/** The class of control flow nodes. */
|
||||
class Node = ControlFlowNode;
|
||||
|
||||
/** 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 }
|
||||
}
|
||||
|
||||
private module BbImpl = BB::Make<Location, Input>;
|
||||
|
||||
class BasicBlock = BbImpl::BasicBlock;
|
||||
|
||||
class EntryBasicBlock = BbImpl::EntryBasicBlock;
|
||||
|
||||
cached
|
||||
private predicate reachableBB(BasicBlock bb) {
|
||||
bb instanceof EntryBasicBlock
|
||||
or
|
||||
exists(BasicBlock predBB | predBB.getASuccessor(_) = bb | reachableBB(predBB))
|
||||
}
|
||||
/** An entry basic block. */
|
||||
class EntryBasicBlock = GoCfg::Cfg::EntryBasicBlock;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ReachableBasicBlock() { reachableBB(this) }
|
||||
ReachableBasicBlock() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A reachable basic block with more than one predecessor.
|
||||
*/
|
||||
class ReachableJoinBlock extends ReachableBasicBlock {
|
||||
ReachableJoinBlock() { this.getFirstNode().isJoin() }
|
||||
ReachableJoinBlock() { this.getFirstNode().(ControlFlow::Node).isJoin() }
|
||||
}
|
||||
|
||||
@@ -5,47 +5,35 @@ overlay[local]
|
||||
module;
|
||||
|
||||
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 {
|
||||
/** A file or function with which a CFG is associated. */
|
||||
/** A function with which a CFG is associated. */
|
||||
class Root extends AstNode {
|
||||
Root() { exists(this.(File).getADecl()) or exists(this.(FuncDef).getBody()) }
|
||||
Root() { exists(this.(FuncDef).getBody()) }
|
||||
|
||||
/** Holds if `nd` belongs to this file or function. */
|
||||
predicate isRootOf(AstNode nd) {
|
||||
this = nd.getEnclosingFunction()
|
||||
or
|
||||
not exists(nd.getEnclosingFunction()) and
|
||||
this = nd.getFile()
|
||||
}
|
||||
/** Holds if `nd` belongs to this function. */
|
||||
predicate isRootOf(AstNode nd) { this = nd.getEnclosingFunction() }
|
||||
|
||||
/** Gets the synthetic entry node of the CFG for this file or function. */
|
||||
/** Gets the synthetic entry node of the CFG for this function. */
|
||||
EntryNode getEntryNode() { result = ControlFlow::entryNode(this) }
|
||||
|
||||
/** Gets the synthetic exit node of the CFG for this file or function. */
|
||||
/** Gets the synthetic exit node of the CFG for this function. */
|
||||
ExitNode getExitNode() { result = ControlFlow::exitNode(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* function and the loading of the file.
|
||||
* function.
|
||||
*/
|
||||
class Node extends TControlFlowNode {
|
||||
/** 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() }
|
||||
|
||||
class Node extends GoCfg::ControlFlowNode {
|
||||
/** Holds if this is a node with more than one successor. */
|
||||
predicate isBranch() { strictcount(this.getASuccessor()) > 1 }
|
||||
|
||||
@@ -53,22 +41,23 @@ module ControlFlow {
|
||||
predicate isJoin() { strictcount(this.getAPredecessor()) > 1 }
|
||||
|
||||
/** 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. */
|
||||
predicate isEntryNode() { this instanceof MkEntryNode }
|
||||
/** Holds if this node is the (unique) entry node of a function. */
|
||||
predicate isEntryNode() { this instanceof GoCfg::ControlFlow::EntryNode }
|
||||
|
||||
/** Holds if this node is the (unique) exit node of a function or file. */
|
||||
predicate isExitNode() { this instanceof MkExitNode }
|
||||
|
||||
/** Gets the basic block to which this node belongs. */
|
||||
BasicBlock getBasicBlock() { result.getANode() = this }
|
||||
/** Holds if this node is the (unique) exit node of a function. */
|
||||
predicate isExitNode() { this instanceof GoCfg::ControlFlow::ExitNode }
|
||||
|
||||
/** Holds if this node dominates `dominee` in the control-flow graph. */
|
||||
overlay[caller?]
|
||||
pragma[inline]
|
||||
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)
|
||||
|
|
||||
thisbb.strictlyDominates(dbb)
|
||||
@@ -77,20 +66,12 @@ module ControlFlow {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the innermost function or file to which this node belongs. */
|
||||
Root getRoot() { none() }
|
||||
/** Gets the innermost function to which this node belongs. */
|
||||
Root getRoot() { result = this.getEnclosingCallable() }
|
||||
|
||||
/** Gets the file to which this node belongs. */
|
||||
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.
|
||||
*
|
||||
@@ -114,6 +95,12 @@ 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 { }
|
||||
|
||||
/**
|
||||
* A control-flow node that initializes or updates the value of a constant, a variable,
|
||||
* a field, or an (array, slice, or map) element.
|
||||
@@ -173,7 +160,7 @@ module ControlFlow {
|
||||
exists(IR::FieldTarget trg | trg = super.getLhs() |
|
||||
(
|
||||
trg.getBase() = base or
|
||||
trg.getBase() = MkImplicitDeref(base.(IR::EvalInstruction).getExpr())
|
||||
trg.getBase() = IR::implicitDerefInstruction(base.(IR::EvalInstruction).getExpr())
|
||||
) and
|
||||
trg.getField() = f and
|
||||
super.getRhs() = rhs
|
||||
@@ -221,7 +208,7 @@ module ControlFlow {
|
||||
exists(IR::ElementTarget trg | trg = super.getLhs() |
|
||||
(
|
||||
trg.getBase() = base or
|
||||
trg.getBase() = MkImplicitDeref(base.(IR::EvalInstruction).getExpr())
|
||||
trg.getBase() = IR::implicitDerefInstruction(base.(IR::EvalInstruction).getExpr())
|
||||
) and
|
||||
trg.getIndex() = index and
|
||||
super.getRhs() = rhs
|
||||
@@ -251,11 +238,15 @@ module ControlFlow {
|
||||
* A control-flow node recording the fact that a certain expression has a known
|
||||
* Boolean value at this point in the program.
|
||||
*/
|
||||
class ConditionGuardNode extends IR::Instruction, MkConditionGuardNode {
|
||||
class ConditionGuardNode extends Node {
|
||||
Expr cond;
|
||||
boolean outcome;
|
||||
|
||||
ConditionGuardNode() { this = MkConditionGuardNode(cond, outcome) }
|
||||
ConditionGuardNode() {
|
||||
this.isAfterTrue(cond) and outcome = true
|
||||
or
|
||||
this.isAfterFalse(cond) and outcome = false
|
||||
}
|
||||
|
||||
private predicate ensuresAux(Expr expr, boolean b) {
|
||||
expr = cond and b = outcome
|
||||
@@ -321,21 +312,17 @@ module ControlFlow {
|
||||
boolean getOutcome() { result = outcome }
|
||||
|
||||
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.
|
||||
@@ -343,7 +330,9 @@ module ControlFlow {
|
||||
* 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.
|
||||
*/
|
||||
predicate mayReturnNormally(FuncDecl f) { CFG::mayReturnNormally(f.getBody()) }
|
||||
predicate mayReturnNormally(FuncDecl f) {
|
||||
exists(GoCfg::ControlFlow::NormalExitNode exit | exit.getEnclosingCallable() = f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `pred` is the node for the case `testExpr` in an expression
|
||||
@@ -353,20 +342,16 @@ module ControlFlow {
|
||||
predicate isSwitchCaseTestPassingEdge(
|
||||
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 Write = ControlFlow::WriteNode;
|
||||
|
||||
/**
|
||||
* Provides the shared CFG library types for Go.
|
||||
*
|
||||
* These types are generated by the shared `codeql.controlflow.ControlFlowGraph`
|
||||
* library and coexist with the existing Go CFG types during the transition.
|
||||
* Use `SharedCfg::ControlFlowNode` to access the shared library's node type,
|
||||
* `SharedCfg::ControlFlow::EntryNode` for entry nodes, etc.
|
||||
*/
|
||||
module SharedCfg = GoCfg;
|
||||
|
||||
@@ -25,6 +25,11 @@ module GoCfg {
|
||||
private import Cfg2
|
||||
import Public
|
||||
|
||||
/** Holds if `e` has an implicit field selection at `index` for `implicitField`. */
|
||||
predicate implicitFieldSelection(Go::AstNode e, int index, Go::Field implicitField) {
|
||||
Input::implicitFieldSelection(e, index, implicitField)
|
||||
}
|
||||
|
||||
/** Provides an implementation of the AST signature for Go. */
|
||||
private module Ast implements CfgLib::AstSig<Go::Location> {
|
||||
class AstNode = Go::AstNode;
|
||||
@@ -63,7 +68,11 @@ module GoCfg {
|
||||
|
||||
AstNode callableGetBody(Callable c) { result = c.(Go::FuncDef).getBody() }
|
||||
|
||||
Callable getEnclosingCallable(AstNode node) { result = node.getEnclosingFunction() }
|
||||
Callable getEnclosingCallable(AstNode node) {
|
||||
result = node and node instanceof Callable
|
||||
or
|
||||
not node instanceof Callable and result = node.getEnclosingFunction()
|
||||
}
|
||||
|
||||
class Stmt = Go::Stmt;
|
||||
|
||||
@@ -515,7 +524,7 @@ module GoCfg {
|
||||
private predicate notBlankIdent(Go::Expr e) { not e instanceof Go::BlankIdent }
|
||||
|
||||
/** Helper: implicit field selection for promoted selectors */
|
||||
private predicate implicitFieldSelection(Ast::AstNode e, int index, Go::Field implicitField) {
|
||||
predicate implicitFieldSelection(Ast::AstNode e, int index, Go::Field implicitField) {
|
||||
exists(Go::StructType baseType, Go::PromotedField child, int implicitFieldDepth |
|
||||
baseType = e.(Go::PromotedSelector).getSelectedStructType() and
|
||||
(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1580
go/ql/lib/semmle/go/controlflow/IR.qll.bak
Normal file
1580
go/ql/lib/semmle/go/controlflow/IR.qll.bak
Normal file
File diff suppressed because it is too large
Load Diff
1580
go/ql/lib/semmle/go/controlflow/IR.qll.bak2
Normal file
1580
go/ql/lib/semmle/go/controlflow/IR.qll.bak2
Normal file
File diff suppressed because it is too large
Load Diff
@@ -89,7 +89,7 @@ private module Internal {
|
||||
/** Holds if the `i`th node of `bb` in function `f` is an entry node. */
|
||||
private predicate entryNode(FuncDef f, ReachableBasicBlock bb, int i) {
|
||||
f = bb.getScope() and
|
||||
bb.getNode(i).isEntryNode()
|
||||
bb.getNode(i).(ControlFlow::Node).isEntryNode()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -154,7 +154,7 @@ module Revel {
|
||||
|
||||
private IR::EvalInstruction skipImplicitFieldReads(IR::Instruction insn) {
|
||||
result = insn or
|
||||
result = skipImplicitFieldReads(insn.(IR::ImplicitFieldReadInstruction).getBase())
|
||||
result = skipImplicitFieldReads(insn.(IR::ImplicitFieldReadInstruction).getBaseInstruction())
|
||||
}
|
||||
|
||||
/** A call to `Controller.Render`. */
|
||||
|
||||
Reference in New Issue
Block a user