diff --git a/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll b/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll index 1da4b1e51231..ee7c9b1136a5 100644 --- a/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll +++ b/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll @@ -664,6 +664,9 @@ module CfgImpl { /** Helper: blank identifier check */ private predicate notBlankIdent(Go::Expr e) { not e instanceof Go::BlankIdent } + /** Holds if `e` is invoked in a newly started goroutine. */ + private predicate isGoStmtCall(Ast::AstNode e) { e = any(Go::GoStmt s).getCall() } + /** Helper: implicit field selection for promoted selectors */ additional predicate implicitFieldSelection(Ast::AstNode e, int index, Go::Field implicitField) { exists(Go::StructType baseType, Go::PromotedField child, int implicitFieldDepth | @@ -704,6 +707,7 @@ module CfgImpl { Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c, boolean always ) { ast instanceof Go::CallExpr and + not isGoStmtCall(ast) and ( not exists(ast.(Go::CallExpr).getTarget()) or ast.(Go::CallExpr).getTarget().mayPanic() @@ -727,6 +731,7 @@ module CfgImpl { // exception completion so that the shared library's default In->After step // is suppressed. ast instanceof Go::CallExpr and + not isGoStmtCall(ast) and exists(Go::Function target | target = ast.(Go::CallExpr).getTarget() | target.mustPanic() or target.mustNotReturnNormally() ) and @@ -848,6 +853,7 @@ module CfgImpl { private predicate mayPanic(Ast::AstNode ast) { ast instanceof Go::CallExpr and not ast = any(Go::DeferStmt s).getCall() and + not isGoStmtCall(ast) and (not exists(ast.(Go::CallExpr).getTarget()) or ast.(Go::CallExpr).getTarget().mayPanic()) and not exists(Go::Function target | target = ast.(Go::CallExpr).getTarget() | target.mustNotReturnNormally() and not target.mustPanic() diff --git a/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected b/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected index 28c1fdb2735a..ae8d5d7e77c4 100644 --- a/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected +++ b/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected @@ -3127,7 +3127,6 @@ | stmts.go:135:3:135:14 | expression statement | stmts.go:135:3:135:14 | Before call to test5 | | stmts.go:135:9:135:13 | false | stmts.go:135:3:135:14 | call to test5 | | stmts.go:140:1:142:1 | Entry | stmts.go:140:13:140:13 | f | -| stmts.go:140:1:142:1 | Exceptional Exit | stmts.go:140:1:142:1 | Exit | | stmts.go:140:1:142:1 | Normal Exit | stmts.go:140:1:142:1 | Exit | | stmts.go:140:1:142:1 | function declaration | stmts.go:145:1:159:1 | function declaration | | stmts.go:140:13:140:13 | f | stmts.go:140:23:142:1 | block statement | @@ -3139,7 +3138,6 @@ | stmts.go:141:5:141:5 | f | stmts.go:141:5:141:7 | call to f | | stmts.go:141:5:141:7 | After call to f | stmts.go:141:2:141:7 | go statement | | stmts.go:141:5:141:7 | Before call to f | stmts.go:141:5:141:5 | f | -| stmts.go:141:5:141:7 | call to f | stmts.go:140:1:142:1 | Exceptional Exit | | stmts.go:141:5:141:7 | call to f | stmts.go:141:5:141:7 | After call to f | | stmts.go:145:1:159:1 | Entry | stmts.go:145:13:145:14 | xs | | stmts.go:145:1:159:1 | Exceptional Exit | stmts.go:145:1:159:1 | Exit | diff --git a/go/ql/test/query-tests/RedundantCode/UnreachableStatement/CONSISTENCY/CfgConsistency.expected b/go/ql/test/query-tests/RedundantCode/UnreachableStatement/CONSISTENCY/CfgConsistency.expected index 15227b6e59b4..e38f26b8c1ce 100644 --- a/go/ql/test/query-tests/RedundantCode/UnreachableStatement/CONSISTENCY/CfgConsistency.expected +++ b/go/ql/test/query-tests/RedundantCode/UnreachableStatement/CONSISTENCY/CfgConsistency.expected @@ -1,5 +1,5 @@ consistencyOverview -| deadEnd | 9 | +| deadEnd | 10 | deadEnd | main.go:17:2:17:10 | select statement | | main.go:109:2:109:10 | select statement | @@ -10,3 +10,4 @@ deadEnd | main.go:145:2:145:10 | select statement | | main.go:151:2:151:10 | select statement | | main.go:157:2:157:10 | select statement | +| main.go:164:2:164:10 | select statement | diff --git a/go/ql/test/query-tests/RedundantCode/UnreachableStatement/main.go b/go/ql/test/query-tests/RedundantCode/UnreachableStatement/main.go index cc26b717f605..85d5fc80a938 100644 --- a/go/ql/test/query-tests/RedundantCode/UnreachableStatement/main.go +++ b/go/ql/test/query-tests/RedundantCode/UnreachableStatement/main.go @@ -159,4 +159,9 @@ func test19() mystruct { return mystruct{test10(1), test10(2) == 2} // $ Alert } +func test20() { + go panic("panic in another goroutine") + select {} // OK: reachable after starting the goroutine +} + func main() {}