@@ -82,9 +82,8 @@ module CfgImpl {
8282 or
8383 e .getParent * ( ) = any ( Go:: ArrayTypeExpr ate ) .getLength ( )
8484 or
85- // The body block of a switch (expression or type) is transparent: the
86- // shared switch model wires control flow directly from the switch to its
87- // case clauses (in control-flow order) and between cases, so the
85+ // The shared switch model wires control flow directly from the switch to
86+ // its case clauses (in control-flow order) and between cases, so the
8887 // enclosing block must not introduce its own nodes or default
8988 // left-to-right sequencing of the case clauses.
9089 e = any ( Go:: SwitchStmt sw ) .getBody ( )
@@ -217,12 +216,6 @@ module CfgImpl {
217216 }
218217
219218 class ForeachStmt extends LoopStmt instanceof Go:: RangeStmt {
220- // Go's `range` statement binds its key and value by destructuring the
221- // current element. The extractor synthesizes a single "range element"
222- // node grouping the key and value (see `Go::RangeElementExpr`), which we
223- // present here as the loop variable. The shared library routes control
224- // flow into and out of this node, and Go wires the destructuring through
225- // it (see `rangeStmtStep`).
226219 Expr getVariable ( ) { result = this .( Go:: RangeStmt ) .getPattern ( ) }
227220
228221 Expr getCollection ( ) { result = this .( Go:: RangeStmt ) .getDomain ( ) }
@@ -298,18 +291,11 @@ module CfgImpl {
298291 DefaultCase ( ) { not exists ( this .( Go:: CaseClause ) .getAnExpr ( ) ) }
299292 }
300293
301- /** Gets the initializer of `switch` statement `switch`, if any. */
302294 AstNode getSwitchInit ( Switch switch ) { result = switch .( Go:: SwitchStmt ) .getInit ( ) }
303295
304- /**
305- * Go has no implicit fall-through between case clauses; a case that runs to
306- * the end of its body breaks out of the switch. Fall-through only happens
307- * when the case body ends with an explicit `fallthrough` statement, in
308- * which case control transfers to the next case clause's body (in source
309- * order). The shared library models this by chaining the body of such a
310- * case to the body of the following case.
311- */
312296 predicate fallsThrough ( Case c ) {
297+ // Go has no implicit fall-through between case clauses; an explicit
298+ // `fallthrough` statement is required.
313299 c .( Go:: CaseClause ) .getStmt ( max ( int i | exists ( c .( Go:: CaseClause ) .getStmt ( i ) ) ) ) instanceof
314300 Go:: FallthroughStmt
315301 }
@@ -444,11 +430,11 @@ module CfgImpl {
444430
445431 predicate preOrderExpr ( Ast:: Expr e ) {
446432 // The call of a `defer` statement is not invoked at the statement
447- // itself; its callee and arguments are evaluated in place, but the call
448- // is only invoked later, at function exit (modelled by the `defer-invoke`
449- // node and `additionalSuccessor`). Marking it as pre-order means no in-order
450- // "invocation" node (and hence no inline exceptional-exit edge) is
451- // created at the `defer` statement.
433+ // itself; its callee expression and arguments are evaluated in place,
434+ // but the call is only invoked later, at function exit (modelled by the
435+ // `defer-invoke` node and `additionalSuccessor`). Marking it as
436+ // pre-order means no in-order "invocation" node (and hence no inline
437+ // exceptional-exit edge) is created at the `defer` statement.
452438 e = any ( Go:: DeferStmt s ) .getCall ( )
453439 or
454440 // Parenthesized expressions are value-transparent (via `propagatesValue`)
@@ -963,12 +949,12 @@ module CfgImpl {
963949 exists ( Go:: FuncDef fd | funcHasDefer ( fd ) |
964950 successorType instanceof DirectSuccessor and
965951 (
966- // (a) an exit predecessor with no active defer flows straight to the exit target
952+ // an exit predecessor with no active defer flows straight to the exit target
967953 normalExitPred ( n1 , fd ) and
968954 n1 = reachableBeforeNextDeferRegistration ( funcEntry ( fd ) ) and
969955 deferChainExitTarget ( fd , n2 )
970956 or
971- // (b) an exit predecessor flows to the invocation of the last-registered active defer
957+ // an exit predecessor flows to the invocation of the last-registered active defer
972958 exists ( Go:: DeferStmt d , PreControlFlowNode reg |
973959 deferRegistration ( reg , d ) and
974960 d .getEnclosingFunction ( ) = fd and
@@ -977,7 +963,7 @@ module CfgImpl {
977963 deferInvoke ( n2 , d )
978964 )
979965 or
980- // (c) deferred invocations chain in last-in-first-out order
966+ // deferred invocations chain in last-in-first-out order
981967 exists ( Go:: DeferStmt laterRegistered , Go:: DeferStmt earlierRegistered |
982968 laterRegistered .getEnclosingFunction ( ) = fd and
983969 nextRegisteredDefer ( laterRegistered , earlierRegistered ) and
@@ -986,7 +972,7 @@ module CfgImpl {
986972 deferInvoke ( n2 , earlierRegistered )
987973 )
988974 or
989- // (d) the invocation of the first-registered (last to run) defer flows to the exit target
975+ // the invocation of the first-registered (last to run) defer flows to the exit target
990976 exists ( Go:: DeferStmt firstD |
991977 firstRegisteredDefer ( firstD , fd ) and
992978 deferInvocationMayReturnNormally ( firstD ) and
@@ -995,7 +981,7 @@ module CfgImpl {
995981 )
996982 )
997983 or
998- // (e) a possible panic with active defers flows to the last-registered active defer
984+ // a possible panic with active defers flows to the last-registered active defer
999985 successorType instanceof ExceptionSuccessor and
1000986 exists ( Go:: DeferStmt d , PreControlFlowNode reg |
1001987 deferRegistration ( reg , d ) and
@@ -1113,7 +1099,6 @@ module CfgImpl {
11131099 |
11141100 epilogueStep ( assgn , n1 , n2 )
11151101 or
1116- // Last epilogue -> after the assignment
11171102 n1 .isAdditional ( assgn , getLastEpilogueTag ( assgn ) ) and
11181103 n2 .isAfter ( assgn )
11191104 )
@@ -1210,7 +1195,6 @@ module CfgImpl {
12101195 exists ( Go:: ReturnStmt ret |
12111196 epilogueStep ( ret , n1 , n2 )
12121197 or
1213- // Last return epilogue -> return node
12141198 n1 .isAdditional ( ret , getLastEpilogueTag ( ret ) ) and
12151199 n2 .isIn ( ret )
12161200 )
@@ -1236,10 +1220,8 @@ module CfgImpl {
12361220 |
12371221 epilogueStep ( call , n1 , n2 )
12381222 or
1239- // Last tuple-extraction node -> the call's invocation node
12401223 n1 .isAdditional ( call , getLastEpilogueTag ( call ) ) and n2 .isIn ( call )
12411224 or
1242- // Invocation node -> after the call (unless the call never returns normally)
12431225 n1 .isIn ( call ) and
12441226 n2 .isAfter ( call ) and
12451227 not beginAbruptCompletion ( call , n1 , _, true )
@@ -1308,7 +1290,6 @@ module CfgImpl {
13081290 exists ( Go:: SliceExpr se |
13091291 n1 .isBefore ( se ) and n2 .isBefore ( se .getBase ( ) )
13101292 or
1311- // After base -> implicit deref, or (if none) the first present bound / slice eval
13121293 n1 .isAfter ( se .getBase ( ) ) and
13131294 (
13141295 if implicitDerefCondition ( se .getBase ( ) )
@@ -1318,7 +1299,6 @@ module CfgImpl {
13181299 or
13191300 n1 .isAdditional ( se .getBase ( ) , "implicit-deref" ) and sliceNext ( se , - 1 , n2 )
13201301 or
1321- // After a present bound -> the next present bound / slice eval
13221302 n1 .isAfter ( se .getLow ( ) ) and sliceNext ( se , 0 , n2 )
13231303 or
13241304 n1 .isAfter ( se .getHigh ( ) ) and sliceNext ( se , 1 , n2 )
@@ -1344,7 +1324,6 @@ module CfgImpl {
13441324 (
13451325 n1 .isBefore ( sel ) and n2 .isBefore ( sel .getBase ( ) )
13461326 or
1347- // After base (no implicit-deref) -> first implicit-field or In(sel)
13481327 n1 .isAfter ( sel .getBase ( ) ) and
13491328 not implicitDerefCondition ( sel .getBase ( ) ) and
13501329 (
@@ -1358,23 +1337,22 @@ module CfgImpl {
13581337 not implicitFieldSelection ( sel , _, _) and n2 .isIn ( sel )
13591338 )
13601339 or
1361- // After base (has implicit-deref) -> implicit-deref node
13621340 n1 .isAfter ( sel .getBase ( ) ) and
13631341 implicitDerefCondition ( sel .getBase ( ) ) and
13641342 n2 .isAdditional ( sel .getBase ( ) , "implicit-deref" )
13651343 or
1366- // After implicit-deref -> first implicit-field or In(sel)
13671344 n1 .isAdditional ( sel .getBase ( ) , "implicit-deref" ) and
13681345 (
1346+ // Has implicit field reads: go to outermost (highest index)
13691347 exists ( int maxIdx |
13701348 maxIdx = max ( int i | implicitFieldSelection ( sel , i , _) ) and
13711349 n2 .isAdditional ( sel , "implicit-field:" + maxIdx .toString ( ) )
13721350 )
13731351 or
1352+ // No implicit field reads: go directly to In(sel)
13741353 not implicitFieldSelection ( sel , _, _) and n2 .isIn ( sel )
13751354 )
13761355 or
1377- // Between implicit field reads: descend from index i to i-1
13781356 exists ( int i |
13791357 i > 1 and
13801358 implicitFieldSelection ( sel , i , _) and
@@ -1383,7 +1361,6 @@ module CfgImpl {
13831361 n2 .isAdditional ( sel , "implicit-field:" + ( i - 1 ) .toString ( ) )
13841362 )
13851363 or
1386- // Last implicit field read (index 1) -> In(sel)
13871364 implicitFieldSelection ( sel , 1 , _) and
13881365 n1 .isAdditional ( sel , "implicit-field:1" ) and
13891366 n2 .isIn ( sel )
@@ -1400,18 +1377,15 @@ module CfgImpl {
14001377 */
14011378 private predicate compositeLitStep ( PreControlFlowNode n1 , PreControlFlowNode n2 ) {
14021379 exists ( Go:: CompositeLit lit |
1403- // Before -> In (the literal allocation)
14041380 n1 .isBefore ( lit ) and n2 .isIn ( lit )
14051381 or
1406- // In -> first element, or After if no elements
14071382 n1 .isIn ( lit ) and
14081383 (
14091384 n2 .isBefore ( lit .getElement ( 0 ) )
14101385 or
14111386 not exists ( lit .getElement ( _) ) and n2 .isAfter ( lit )
14121387 )
14131388 or
1414- // After element -> lit-init -> next element or After.
14151389 // Positional array/slice elements have an implicit index that is
14161390 // modelled on the `lit-init` instruction itself (see
14171391 // `IR::InitLiteralElementInstruction`) rather than as a separate node.
@@ -1607,17 +1581,6 @@ module CfgImpl {
16071581 )
16081582 }
16091583
1610- /**
1611- * Function definition prologue and epilogue:
1612- * - Prologue: parameters are modelled as native CFG nodes by the shared
1613- * library (Entry -> param -> ... -> Before(body)). The remaining
1614- * prologue on Before(body) zero-initializes any named result
1615- * variables: zero-init:0 -> zero-init:1 -> ... -> first statement.
1616- * - Epilogue: return -> result-read:0 -> result-read:1 -> ... -> result-read:last
1617- *
1618- * The last result-read node goes to `After(body)`, from which the shared
1619- * callable CFG continues to the normal exit.
1620- */
16211584 private predicate hasFuncDefPrologue ( Go:: FuncDef fd ) { exists ( fd .getResultVar ( _) ) }
16221585
16231586 private predicate funcDefBodyStart ( Go:: FuncDef fd , PreControlFlowNode n ) {
@@ -1627,47 +1590,41 @@ module CfgImpl {
16271590 n .isAdditional ( fd .getBody ( ) , "result-read:0" )
16281591 }
16291592
1593+ /**
1594+ * Function body flow for named result variables: `Before(body)` ->
1595+ * `zero-init:0` -> ... -> first statement -> ... -> `result-read:0` -> ...
1596+ * -> `After(body)`. Parameters precede `Before(body)` through the shared
1597+ * callable flow. Return and defer handling route into the result-read
1598+ * sequence separately; this predicate sequences its nodes and routes
1599+ * defer-free fall-through into it.
1600+ */
16301601 private predicate funcDefStep ( PreControlFlowNode n1 , PreControlFlowNode n2 ) {
16311602 exists ( Go:: FuncDef fd | exists ( fd .getBody ( ) ) |
1632- // Before(body) -> first result-var zero-init node. Parameters are
1633- // modelled as native CFG nodes by the shared library and route
1634- // Entry -> param -> ... -> Before(body) ahead of this point; the
1635- // no-result-variable case (Before(body) -> first statement) is handled
1636- // by the shared library's default control flow.
16371603 n1 .isBefore ( fd .getBody ( ) ) and
16381604 exists ( fd .getResultVar ( 0 ) ) and
16391605 n2 .isAdditional ( fd .getBody ( ) , "zero-init:0" )
16401606 or
1641- // zero-init:j -> next: zero-init:(j+1), or Before(body).
1642- // The zero-init node also writes the result variable (see
1643- // `IR::EvalImplicitInitInstruction`), so there is no separate result-init node.
16441607 exists ( int j | exists ( fd .getResultVar ( j ) ) |
16451608 n1 .isAdditional ( fd .getBody ( ) , "zero-init:" + j .toString ( ) ) and
16461609 (
1647- // Next result var exists
16481610 exists ( fd .getResultVar ( j + 1 ) ) and
16491611 n2 .isAdditional ( fd .getBody ( ) , "zero-init:" + ( j + 1 ) .toString ( ) )
16501612 or
1651- // No next result var: go to Before(body)
16521613 not exists ( fd .getResultVar ( j + 1 ) ) and
16531614 funcDefBodyStart ( fd , n2 )
16541615 )
16551616 )
16561617 or
1657- // result-read:j -> result-read:(j+1)
16581618 exists ( int j | exists ( fd .getResultVar ( j + 1 ) ) |
16591619 n1 .isAdditional ( fd .getBody ( ) , "result-read:" + j .toString ( ) ) and
16601620 n2 .isAdditional ( fd .getBody ( ) , "result-read:" + ( j + 1 ) .toString ( ) )
16611621 )
16621622 or
1663- // Normal fall-through enters the result-read epilogue when there are
1664- // named results but no deferred calls.
16651623 not funcHasDefer ( fd ) and
16661624 exists ( fd .getResultVar ( 0 ) ) and
16671625 n1 .isAfter ( getLastRankedChild ( fd .getBody ( ) ) ) and
16681626 n2 .isAdditional ( fd .getBody ( ) , "result-read:0" )
16691627 or
1670- // The completed result-read epilogue reaches `After(body)`.
16711628 exists ( int j |
16721629 exists ( fd .getResultVar ( j ) ) and
16731630 not exists ( fd .getResultVar ( j + 1 ) ) and
0 commit comments