@@ -162,6 +162,7 @@ module CfgImpl {
162162
163163 class BlockStmt extends Go:: BlockStmt {
164164 BlockStmt ( ) {
165+ not this = any ( Go:: FuncDef fd ) .getBody ( ) and
165166 not this = any ( Go:: SwitchStmt sw ) .getBody ( ) and
166167 not this = any ( Go:: SelectStmt sel ) .getBody ( )
167168 }
@@ -453,7 +454,7 @@ module CfgImpl {
453454 // The call of a `defer` statement is not invoked at the statement
454455 // itself; its callee and arguments are evaluated in place, but the call
455456 // is only invoked later, at function exit (modelled by the `defer-invoke`
456- // node and `deferExitStep `). Marking it as pre-order means no in-order
457+ // node and `additionalSuccessor `). Marking it as pre-order means no in-order
457458 // "invocation" node (and hence no inline exceptional-exit edge) is
458459 // created at the `defer` statement.
459460 e = any ( Go:: DeferStmt s ) .getCall ( )
@@ -603,7 +604,7 @@ module CfgImpl {
603604 tag = "implicit-field:" + i .toString ( )
604605 )
605606 or
606- // Deferred-call invocation node, placed at function exit by `deferExitStep `
607+ // Deferred-call invocation node, placed at function exit by `additionalSuccessor `
607608 n = any ( Go:: DeferStmt s ) .getCall ( ) and tag = "defer-invoke"
608609 )
609610 }
@@ -800,40 +801,31 @@ module CfgImpl {
800801 exists ( fd .getResultVar ( 0 ) ) and
801802 n .isAdditional ( fd .getBody ( ) , "result-read:0" )
802803 )
803- }
804-
805- additional predicate overridesCallableEndAbruptCompletion (
806- Ast:: Callable c , AbruptCompletion completion
807- ) {
808- // For functions with result variables, the library's default routing of a
809- // `return` straight to the normal exit node is suppressed so that the
810- // return is instead caught by `endAbruptCompletion` above and routed
811- // through the result-read epilogue.
812- //
813- // For functions containing `defer` statements, the default routing is
814- // likewise suppressed so that returns are routed through the deferred-call
815- // epilogue (see `deferExitStep`) instead.
816- ( exists ( c .( Go:: FuncDef ) .getResultVar ( 0 ) ) or funcHasDefer ( c .( Go:: FuncDef ) ) ) and
817- completion .getSuccessorType ( ) instanceof ReturnSuccessor
804+ or
805+ // Function bodies are excluded from `Ast::BlockStmt`, so handle goto
806+ // targets among their top-level statements here.
807+ exists ( Go:: FuncDef fd , Go:: Stmt target , Label l |
808+ ast = fd .getBody ( ) and
809+ target = fd .getBody ( ) .getAStmt ( ) and
810+ not target instanceof Go:: GotoStmt and
811+ hasLabel ( target , l ) and
812+ n .isBefore ( target ) and
813+ c .getSuccessorType ( ) instanceof GotoSuccessor and
814+ c .hasLabel ( l )
815+ )
818816 }
819817
820818 additional predicate overridesAbruptCompletionEdge (
821819 PreControlFlowNode source , PreControlFlowNode target , AbruptCompletion completion
822820 ) {
821+ completion .getSuccessorType ( ) instanceof ReturnSuccessor and
822+ target instanceof NormalExitNodeImpl and
823+ exists ( PreControlFlowNode replacement | additionalSuccessor ( source , replacement , _) )
824+ or
823825 completion .getSuccessorType ( ) instanceof ExceptionSuccessor and
824826 target instanceof ExceptionalExitNodeImpl and
825827 exists ( PreControlFlowNode nextDefer |
826- deferExitStep ( source , nextDefer , _) and deferInvoke ( nextDefer , _)
827- )
828- }
829-
830- additional predicate callableExitStep ( PreControlFlowNode n , Ast:: Callable c , boolean normal ) {
831- // The last result-read node of the epilogue steps to the normal exit node.
832- exists ( Go:: FuncDef fd , int j | fd = c |
833- normal = true and
834- exists ( fd .getResultVar ( j ) ) and
835- not exists ( fd .getResultVar ( j + 1 ) ) and
836- n .isAdditional ( fd .getBody ( ) , "result-read:" + j .toString ( ) )
828+ additionalSuccessor ( source , nextDefer , _) and deferInvoke ( nextDefer , _)
837829 )
838830 }
839831
@@ -937,12 +929,12 @@ module CfgImpl {
937929
938930 /**
939931 * Holds if `n` is a normal-exit predecessor of `fd`: a `return` statement
940- * node, or the fall-through node after the body.
932+ * node, or the normal fall-through from the body's last statement .
941933 */
942934 private predicate normalExitPred ( PreControlFlowNode n , Go:: FuncDef fd ) {
943935 exists ( Go:: ReturnStmt ret | ret .getEnclosingFunction ( ) = fd and n .isIn ( ret ) )
944936 or
945- n .isAfter ( fd .getBody ( ) )
937+ n .isAfter ( getLastRankedChild ( fd .getBody ( ) ) )
946938 }
947939
948940 /**
@@ -968,17 +960,16 @@ module CfgImpl {
968960 /**
969961 * Holds if, after running its deferred calls, `fd` should continue at
970962 * `target` on a normal exit. For functions with result variables this is
971- * the start of the result-read epilogue; otherwise it is the normal exit
972- * node directly .
963+ * the start of the result-read epilogue; otherwise it is the function
964+ * body's `After` node .
973965 */
974966 private predicate deferChainExitTarget ( Go:: FuncDef fd , PreControlFlowNode target ) {
975967 exists ( fd .getResultVar ( 0 ) ) and target .isAdditional ( fd .getBody ( ) , "result-read:0" )
976968 or
977- not exists ( fd .getResultVar ( _) ) and
978- target .( NormalExitNodeImpl ) .getEnclosingCallable ( ) = fd
969+ not exists ( fd .getResultVar ( _) ) and target .isAfter ( fd .getBody ( ) )
979970 }
980971
981- additional predicate deferExitStep (
972+ additional predicate additionalSuccessor (
982973 PreControlFlowNode n1 , PreControlFlowNode n2 , SuccessorType successorType
983974 ) {
984975 exists ( Go:: FuncDef fd | funcHasDefer ( fd ) |
@@ -1028,10 +1019,6 @@ module CfgImpl {
10281019 )
10291020 }
10301021
1031- additional predicate overridesCallableBodyExit ( Ast:: Callable c ) {
1032- funcHasDefer ( c .( Go:: FuncDef ) )
1033- }
1034-
10351022 additional predicate overridesDefaultControlFlow ( Ast:: AstNode ast ) {
10361023 exists ( Go:: SelectStmt sel , Go:: RecvStmt recv |
10371024 recv = sel .getACommClause ( ) .getComm ( ) and
@@ -1054,6 +1041,10 @@ module CfgImpl {
10541041 ) {
10551042 ast = any ( Go:: FuncDef fd | hasFuncDefPrologue ( fd ) ) .getBody ( ) and source .isBefore ( ast )
10561043 or
1044+ ast = any ( Go:: FuncDef fd | funcHasDefer ( fd ) ) .getBody ( ) and
1045+ source .isAfter ( getLastRankedChild ( ast ) ) and
1046+ target .isAfter ( ast )
1047+ or
10571048 exists ( getFirstEpilogueTag ( ast ) ) and
10581049 (
10591050 source .isAfter ( getLastRankedChild ( ast ) )
@@ -1693,21 +1684,16 @@ module CfgImpl {
16931684 * variables: zero-init:0 → zero-init:1 → ... → first statement.
16941685 * - Epilogue: return → result-read:0 → result-read:1 → ... → result-read:last
16951686 *
1696- * The last result-read node goes to `NormalExit(fd)` via the shared
1697- * library's `callableExitStep` hook .
1687+ * The last result-read node goes to `After(body)`, from which the shared
1688+ * callable CFG continues to the normal exit .
16981689 */
16991690 private predicate hasFuncDefPrologue ( Go:: FuncDef fd ) { exists ( fd .getResultVar ( _) ) }
17001691
17011692 private predicate funcDefBodyStart ( Go:: FuncDef fd , PreControlFlowNode n ) {
17021693 n .isBefore ( getRankedChild ( fd .getBody ( ) , 1 ) )
17031694 or
17041695 not exists ( getRankedChild ( fd .getBody ( ) , _) ) and
1705- n .isAfter ( fd .getBody ( ) ) and
1706- // When Before(body) and After(body) are the same node (the shared library's
1707- // "simple leaf node" optimization merges them for empty bodies without
1708- // additional nodes), don't generate Before→After as it would be a self-loop.
1709- // The callable exit mechanism already routes After(body) → NormalExit.
1710- not n .isBefore ( fd .getBody ( ) )
1696+ n .isAdditional ( fd .getBody ( ) , "result-read:0" )
17111697 }
17121698
17131699 private predicate funcDefStep ( PreControlFlowNode n1 , PreControlFlowNode n2 ) {
@@ -1737,12 +1723,26 @@ module CfgImpl {
17371723 )
17381724 )
17391725 or
1740- // result-read:j → result-read:(j+1); the last result-read node steps to
1741- // the normal exit node via the `callableExitStep` hook.
1726+ // result-read:j → result-read:(j+1)
17421727 exists ( int j | exists ( fd .getResultVar ( j + 1 ) ) |
17431728 n1 .isAdditional ( fd .getBody ( ) , "result-read:" + j .toString ( ) ) and
17441729 n2 .isAdditional ( fd .getBody ( ) , "result-read:" + ( j + 1 ) .toString ( ) )
17451730 )
1731+ or
1732+ // Normal fall-through enters the result-read epilogue when there are
1733+ // named results but no deferred calls.
1734+ not funcHasDefer ( fd ) and
1735+ exists ( fd .getResultVar ( 0 ) ) and
1736+ n1 .isAfter ( getLastRankedChild ( fd .getBody ( ) ) ) and
1737+ n2 .isAdditional ( fd .getBody ( ) , "result-read:0" )
1738+ or
1739+ // The completed result-read epilogue reaches `After(body)`.
1740+ exists ( int j |
1741+ exists ( fd .getResultVar ( j ) ) and
1742+ not exists ( fd .getResultVar ( j + 1 ) ) and
1743+ n1 .isAdditional ( fd .getBody ( ) , "result-read:" + j .toString ( ) ) and
1744+ n2 .isAfter ( fd .getBody ( ) )
1745+ )
17461746 )
17471747 }
17481748 }
@@ -1766,15 +1766,6 @@ module CfgImpl {
17661766 )
17671767 }
17681768
1769- predicate overridesCallableEndAbruptCompletion ( Ast:: Callable c , AbruptCompletion completion ) {
1770- exists ( c .( Go:: FuncDef ) .getResultVar ( 0 ) ) and
1771- completion .getSuccessorType ( ) instanceof ReturnSuccessor
1772- }
1773-
1774- predicate callableExitStep ( PreControlFlowNode n , Ast:: Callable c , boolean normal ) {
1775- Input1:: callableExitStep ( n , c , normal )
1776- }
1777-
17781769 predicate overridesDefaultControlFlow ( Ast:: AstNode ast ) {
17791770 Input1:: overridesDefaultControlFlow ( ast )
17801771 }
@@ -1804,28 +1795,18 @@ module CfgImpl {
18041795 Input1:: endAbruptCompletion ( ast , n , c )
18051796 }
18061797
1807- predicate overridesCallableEndAbruptCompletion ( Ast:: Callable c , AbruptCompletion completion ) {
1808- Input1:: overridesCallableEndAbruptCompletion ( c , completion )
1809- }
1810-
18111798 predicate overridesAbruptCompletionEdge (
18121799 PreControlFlowNode source , PreControlFlowNode target , AbruptCompletion completion
18131800 ) {
18141801 Input1:: overridesAbruptCompletionEdge ( source , target , completion )
18151802 }
18161803
1817- predicate callableExitStep ( PreControlFlowNode n , Ast:: Callable c , boolean normal ) {
1818- Input1:: callableExitStep ( n , c , normal )
1819- }
1820-
1821- predicate deferExitStep (
1804+ predicate additionalSuccessor (
18221805 PreControlFlowNode n1 , PreControlFlowNode n2 , SuccessorType successorType
18231806 ) {
1824- Input1:: deferExitStep ( n1 , n2 , successorType )
1807+ Input1:: additionalSuccessor ( n1 , n2 , successorType )
18251808 }
18261809
1827- predicate overridesCallableBodyExit ( Ast:: Callable c ) { Input1:: overridesCallableBodyExit ( c ) }
1828-
18291810 predicate overridesDefaultControlFlow ( Ast:: AstNode ast ) {
18301811 Input1:: overridesDefaultControlFlow ( ast )
18311812 }
0 commit comments