Skip to content

Commit b90c105

Browse files
committed
Checkpoint from VS Code for cloud agent session
1 parent dc20666 commit b90c105

File tree

8 files changed

+3587
-721
lines changed

8 files changed

+3587
-721
lines changed

go/ql/lib/semmle/go/controlflow/BasicBlocks.qll

Lines changed: 10 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,66 +5,27 @@ overlay[local]
55
module;
66

77
import go
8-
private import ControlFlowGraphImpl
9-
private import codeql.controlflow.BasicBlock as BB
10-
private import codeql.controlflow.SuccessorType
8+
private import ControlFlowGraphShared
119

12-
private module Input implements BB::InputSig<Location> {
13-
/** A delineated part of the AST with its own CFG. */
14-
class CfgScope = ControlFlow::Root;
10+
/** A basic block in the control-flow graph. */
11+
class BasicBlock = GoCfg::Cfg::BasicBlock;
1512

16-
/** The class of control flow nodes. */
17-
class Node = ControlFlowNode;
18-
19-
/** Gets the CFG scope in which this node occurs. */
20-
CfgScope nodeGetCfgScope(Node node) { node.getRoot() = result }
21-
22-
/** Gets an immediate successor of this node. */
23-
Node nodeGetASuccessor(Node node, SuccessorType t) {
24-
result = node.getASuccessor() and
25-
(
26-
not result instanceof ControlFlow::ConditionGuardNode and t instanceof DirectSuccessor
27-
or
28-
t.(BooleanSuccessor).getValue() = result.(ControlFlow::ConditionGuardNode).getOutcome()
29-
)
30-
}
31-
32-
/**
33-
* Holds if `node` represents an entry node to be used when calculating
34-
* dominance.
35-
*/
36-
predicate nodeIsDominanceEntry(Node node) { node instanceof EntryNode }
37-
38-
/**
39-
* Holds if `node` represents an exit node to be used when calculating
40-
* post dominance.
41-
*/
42-
predicate nodeIsPostDominanceExit(Node node) { node instanceof ExitNode }
43-
}
44-
45-
private module BbImpl = BB::Make<Location, Input>;
46-
47-
class BasicBlock = BbImpl::BasicBlock;
48-
49-
class EntryBasicBlock = BbImpl::EntryBasicBlock;
50-
51-
cached
52-
private predicate reachableBB(BasicBlock bb) {
53-
bb instanceof EntryBasicBlock
54-
or
55-
exists(BasicBlock predBB | predBB.getASuccessor(_) = bb | reachableBB(predBB))
56-
}
13+
/** An entry basic block. */
14+
class EntryBasicBlock = GoCfg::Cfg::EntryBasicBlock;
5715

5816
/**
5917
* A basic block that is reachable from an entry basic block.
18+
*
19+
* Since the shared CFG library only creates nodes for reachable code,
20+
* all basic blocks are reachable by construction.
6021
*/
6122
class ReachableBasicBlock extends BasicBlock {
62-
ReachableBasicBlock() { reachableBB(this) }
23+
ReachableBasicBlock() { any() }
6324
}
6425

6526
/**
6627
* A reachable basic block with more than one predecessor.
6728
*/
6829
class ReachableJoinBlock extends ReachableBasicBlock {
69-
ReachableJoinBlock() { this.getFirstNode().isJoin() }
30+
ReachableJoinBlock() { this.getFirstNode().(ControlFlow::Node).isJoin() }
7031
}

go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll

Lines changed: 51 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -5,70 +5,59 @@ overlay[local]
55
module;
66

77
import go
8-
private import ControlFlowGraphImpl
98
private import ControlFlowGraphShared
109

11-
/** Provides helper predicates for mapping btween CFG nodes and the AST. */
10+
/** Provides helper predicates for mapping between CFG nodes and the AST. */
1211
module ControlFlow {
13-
/** A file or function with which a CFG is associated. */
12+
/** A function with which a CFG is associated. */
1413
class Root extends AstNode {
15-
Root() { exists(this.(File).getADecl()) or exists(this.(FuncDef).getBody()) }
14+
Root() { exists(this.(FuncDef).getBody()) }
1615

17-
/** Holds if `nd` belongs to this file or function. */
18-
predicate isRootOf(AstNode nd) {
19-
this = nd.getEnclosingFunction()
20-
or
21-
not exists(nd.getEnclosingFunction()) and
22-
this = nd.getFile()
23-
}
16+
/** Holds if `nd` belongs to this function. */
17+
predicate isRootOf(AstNode nd) { this = nd.getEnclosingFunction() }
2418

25-
/** Gets the synthetic entry node of the CFG for this file or function. */
19+
/** Gets the synthetic entry node of the CFG for this function. */
2620
EntryNode getEntryNode() { result = ControlFlow::entryNode(this) }
2721

28-
/** Gets the synthetic exit node of the CFG for this file or function. */
22+
/** Gets the synthetic exit node of the CFG for this function. */
2923
ExitNode getExitNode() { result = ControlFlow::exitNode(this) }
3024
}
3125

3226
/**
33-
* A node in the intra-procedural control-flow graph of a Go function or file.
27+
* A node in the intra-procedural control-flow graph of a Go function.
3428
*
3529
* Nodes correspond to expressions and statements that compute a value or perform
3630
* an operation (as opposed to providing syntactic structure or type information).
3731
*
38-
* There are also synthetic entry and exit nodes for each Go function and file
32+
* There are also synthetic entry and exit nodes for each Go function
3933
* that mark the beginning and the end, respectively, of the execution of the
40-
* function and the loading of the file.
34+
* function.
4135
*/
42-
class Node extends TControlFlowNode {
43-
/** Gets a node that directly follows this one in the control-flow graph. */
44-
Node getASuccessor() { result = CFG::succ(this) }
45-
46-
/** Gets a node that directly precedes this one in the control-flow graph. */
47-
Node getAPredecessor() { this = result.getASuccessor() }
48-
36+
class Node extends GoCfg::ControlFlowNode {
4937
/** Holds if this is a node with more than one successor. */
5038
predicate isBranch() { strictcount(this.getASuccessor()) > 1 }
5139

5240
/** Holds if this is a node with more than one predecessor. */
5341
predicate isJoin() { strictcount(this.getAPredecessor()) > 1 }
5442

5543
/** Holds if this is the first control-flow node in `subtree`. */
56-
predicate isFirstNodeOf(AstNode subtree) { CFG::firstNode(subtree, this) }
57-
58-
/** Holds if this node is the (unique) entry node of a function or file. */
59-
predicate isEntryNode() { this instanceof MkEntryNode }
44+
predicate isFirstNodeOf(AstNode subtree) {
45+
this.isBefore(subtree)
46+
or
47+
this.injects(subtree)
48+
}
6049

61-
/** Holds if this node is the (unique) exit node of a function or file. */
62-
predicate isExitNode() { this instanceof MkExitNode }
50+
/** Holds if this node is the (unique) entry node of a function. */
51+
predicate isEntryNode() { this instanceof GoCfg::ControlFlow::EntryNode }
6352

64-
/** Gets the basic block to which this node belongs. */
65-
BasicBlock getBasicBlock() { result.getANode() = this }
53+
/** Holds if this node is the (unique) exit node of a function. */
54+
predicate isExitNode() { this instanceof GoCfg::ControlFlow::ExitNode }
6655

6756
/** Holds if this node dominates `dominee` in the control-flow graph. */
6857
overlay[caller?]
6958
pragma[inline]
7059
predicate dominatesNode(ControlFlow::Node dominee) {
71-
exists(ReachableBasicBlock thisbb, ReachableBasicBlock dbb, int i, int j |
60+
exists(GoCfg::Cfg::BasicBlock thisbb, GoCfg::Cfg::BasicBlock dbb, int i, int j |
7261
this = thisbb.getNode(i) and dominee = dbb.getNode(j)
7362
|
7463
thisbb.strictlyDominates(dbb)
@@ -77,20 +66,12 @@ module ControlFlow {
7766
)
7867
}
7968

80-
/** Gets the innermost function or file to which this node belongs. */
81-
Root getRoot() { none() }
69+
/** Gets the innermost function to which this node belongs. */
70+
Root getRoot() { result = this.getEnclosingCallable() }
8271

8372
/** Gets the file to which this node belongs. */
8473
File getFile() { result = this.getLocation().getFile() }
8574

86-
/**
87-
* Gets a textual representation of this control flow node.
88-
*/
89-
string toString() { result = "control-flow node" }
90-
91-
/** Gets the source location for this element. */
92-
Location getLocation() { none() }
93-
9475
/**
9576
* DEPRECATED: Use `getLocation()` instead.
9677
*
@@ -114,6 +95,12 @@ module ControlFlow {
11495
}
11596
}
11697

98+
/** A synthetic entry node for a function. */
99+
class EntryNode extends Node instanceof GoCfg::ControlFlow::EntryNode { }
100+
101+
/** A synthetic exit node for a function. */
102+
class ExitNode extends Node instanceof GoCfg::ControlFlow::ExitNode { }
103+
117104
/**
118105
* A control-flow node that initializes or updates the value of a constant, a variable,
119106
* a field, or an (array, slice, or map) element.
@@ -173,7 +160,7 @@ module ControlFlow {
173160
exists(IR::FieldTarget trg | trg = super.getLhs() |
174161
(
175162
trg.getBase() = base or
176-
trg.getBase() = MkImplicitDeref(base.(IR::EvalInstruction).getExpr())
163+
trg.getBase() = IR::implicitDerefInstruction(base.(IR::EvalInstruction).getExpr())
177164
) and
178165
trg.getField() = f and
179166
super.getRhs() = rhs
@@ -221,7 +208,7 @@ module ControlFlow {
221208
exists(IR::ElementTarget trg | trg = super.getLhs() |
222209
(
223210
trg.getBase() = base or
224-
trg.getBase() = MkImplicitDeref(base.(IR::EvalInstruction).getExpr())
211+
trg.getBase() = IR::implicitDerefInstruction(base.(IR::EvalInstruction).getExpr())
225212
) and
226213
trg.getIndex() = index and
227214
super.getRhs() = rhs
@@ -251,11 +238,15 @@ module ControlFlow {
251238
* A control-flow node recording the fact that a certain expression has a known
252239
* Boolean value at this point in the program.
253240
*/
254-
class ConditionGuardNode extends IR::Instruction, MkConditionGuardNode {
241+
class ConditionGuardNode extends Node {
255242
Expr cond;
256243
boolean outcome;
257244

258-
ConditionGuardNode() { this = MkConditionGuardNode(cond, outcome) }
245+
ConditionGuardNode() {
246+
this.isAfterTrue(cond) and outcome = true
247+
or
248+
this.isAfterFalse(cond) and outcome = false
249+
}
259250

260251
private predicate ensuresAux(Expr expr, boolean b) {
261252
expr = cond and b = outcome
@@ -321,29 +312,27 @@ module ControlFlow {
321312
boolean getOutcome() { result = outcome }
322313

323314
override Root getRoot() { result.isRootOf(cond) }
324-
325-
override string toString() { result = cond + " is " + outcome }
326-
327-
override Location getLocation() { result = cond.getLocation() }
328315
}
329316

330317
/**
331-
* Gets the entry node of function or file `root`.
318+
* Gets the entry node of function `root`.
332319
*/
333-
Node entryNode(Root root) { result = MkEntryNode(root) }
320+
EntryNode entryNode(Root root) { result.getEnclosingCallable() = root }
334321

335322
/**
336-
* Gets the exit node of function or file `root`.
323+
* Gets the exit node of function `root`.
337324
*/
338-
Node exitNode(Root root) { result = MkExitNode(root) }
325+
ExitNode exitNode(Root root) { result.getEnclosingCallable() = root }
339326

340327
/**
341328
* Holds if the function `f` may return without panicking, exiting the process, or looping forever.
342329
*
343330
* This is defined conservatively, and so may also hold of a function that in fact
344331
* cannot return normally, but never fails to hold of a function that can return normally.
345332
*/
346-
predicate mayReturnNormally(FuncDecl f) { CFG::mayReturnNormally(f.getBody()) }
333+
predicate mayReturnNormally(FuncDecl f) {
334+
exists(GoCfg::ControlFlow::NormalExitNode exit | exit.getEnclosingCallable() = f)
335+
}
347336

348337
/**
349338
* Holds if `pred` is the node for the case `testExpr` in an expression
@@ -353,20 +342,16 @@ module ControlFlow {
353342
predicate isSwitchCaseTestPassingEdge(
354343
ControlFlow::Node pred, ControlFlow::Node succ, Expr switchExpr, Expr testExpr
355344
) {
356-
CFG::isSwitchCaseTestPassingEdge(pred, succ, switchExpr, testExpr)
345+
exists(ExpressionSwitchStmt ess, CaseClause cc, int i |
346+
ess.getExpr() = switchExpr and
347+
cc = ess.getACase() and
348+
testExpr = cc.getExpr(i) and
349+
pred.isAfter(testExpr) and
350+
succ.isFirstNodeOf(cc.getStmt(0))
351+
)
357352
}
358353
}
359354

360355
class ControlFlowNode = ControlFlow::Node;
361356

362357
class Write = ControlFlow::WriteNode;
363-
364-
/**
365-
* Provides the shared CFG library types for Go.
366-
*
367-
* These types are generated by the shared `codeql.controlflow.ControlFlowGraph`
368-
* library and coexist with the existing Go CFG types during the transition.
369-
* Use `SharedCfg::ControlFlowNode` to access the shared library's node type,
370-
* `SharedCfg::ControlFlow::EntryNode` for entry nodes, etc.
371-
*/
372-
module SharedCfg = GoCfg;

go/ql/lib/semmle/go/controlflow/ControlFlowGraphShared.qll

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ module GoCfg {
2525
private import Cfg2
2626
import Public
2727

28+
/** Holds if `e` has an implicit field selection at `index` for `implicitField`. */
29+
predicate implicitFieldSelection(Go::AstNode e, int index, Go::Field implicitField) {
30+
Input::implicitFieldSelection(e, index, implicitField)
31+
}
32+
2833
/** Provides an implementation of the AST signature for Go. */
2934
private module Ast implements CfgLib::AstSig<Go::Location> {
3035
class AstNode = Go::AstNode;
@@ -63,7 +68,11 @@ module GoCfg {
6368

6469
AstNode callableGetBody(Callable c) { result = c.(Go::FuncDef).getBody() }
6570

66-
Callable getEnclosingCallable(AstNode node) { result = node.getEnclosingFunction() }
71+
Callable getEnclosingCallable(AstNode node) {
72+
result = node and node instanceof Callable
73+
or
74+
not node instanceof Callable and result = node.getEnclosingFunction()
75+
}
6776

6877
class Stmt = Go::Stmt;
6978

@@ -515,7 +524,7 @@ module GoCfg {
515524
private predicate notBlankIdent(Go::Expr e) { not e instanceof Go::BlankIdent }
516525

517526
/** Helper: implicit field selection for promoted selectors */
518-
private predicate implicitFieldSelection(Ast::AstNode e, int index, Go::Field implicitField) {
527+
predicate implicitFieldSelection(Ast::AstNode e, int index, Go::Field implicitField) {
519528
exists(Go::StructType baseType, Go::PromotedField child, int implicitFieldDepth |
520529
baseType = e.(Go::PromotedSelector).getSelectedStructType() and
521530
(

0 commit comments

Comments
 (0)