https://github.com/ianayl created https://github.com/llvm/llvm-project/pull/220462
This PR fixes codegen for statements that branch out of SEH handlers causing compiler crashes in LLVM, i.e. see current behavior as of 23.1.0: https://godbolt.org/z/ns3o3h84e ```c int main() { __try { } __finally { goto illegal_jmp; } illegal_jmp: return 0; } ``` Instead, this PR tries to adhere to [MSVC C4532](https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4532) and emits `unreachable` when a statement leads to a `br` out of the immediate SEH handler statement / outlined function. As visible in aforementioned Godbolt link, Sema already contains code emitting warnings on these jumps out of SEH handlers, it's moreso a matter of preventing the compiler crash and adhereing to what's specified in C4532. >From 3a3863ff81cd51223bf8526c219ae37243db7314 Mon Sep 17 00:00:00 2001 From: "Li, Ian" <[email protected]> Date: Tue, 1 Sep 2026 18:59:02 -0700 Subject: [PATCH] MSVC C4532: Generate "unreachable" if outlined SEH helper has gotos jumping out of the function --- clang/lib/CodeGen/CGException.cpp | 7 ++++--- clang/lib/CodeGen/CGStmt.cpp | 28 +++++++++++++++++++++++++++- clang/lib/CodeGen/CodeGenFunction.h | 13 ++++++++++--- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index b0fb3b4d85d15..109a02c3b48fe 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -1739,8 +1739,8 @@ struct PerformSEHFinally final : EHScopeStack::Cleanup { // Compute the two argument values. QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy}; llvm::Value *FP = nullptr; - // If CFG.IsOutlinedSEHHelper is true, then we are within a finally block. - if (CGF.IsOutlinedSEHHelper) { + // If CFG.IsOutlinedSEHHelper() is true, then we are within a finally block. + if (CGF.IsOutlinedSEHHelper()) { FP = &CGF.CurFn->arg_begin()[1]; } else { llvm::Function *LocalAddrFn = @@ -2083,7 +2083,8 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, llvm::Function *Fn = llvm::Function::Create( FnTy, llvm::GlobalValue::InternalLinkage, Name.str(), &CGM.getModule()); - IsOutlinedSEHHelper = true; + // Indicate the current function is an outlined SEH helper. + OutlinedSEHStmt = OutlinedStmt; StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args, OutlinedStmt->getBeginLoc(), OutlinedStmt->getBeginLoc()); diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index bf6e6eb50f555..f979786126c6c 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -848,6 +848,23 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) { EmitStmt(S.getSubStmt(), S.getAttrs()); } +static bool StmtContainsLabelDecl(const Stmt *S, const LabelDecl *Target) { + if (!S) + return false; + if (const auto *LS = dyn_cast<LabelStmt>(S)) + if (LS->getDecl() == Target) + return true; + for (const Stmt *Child : S->children()) + if (StmtContainsLabelDecl(Child, Target)) + return true; + return false; +} + +bool CodeGenFunction::IsLabelWithinSEHHelper(const LabelDecl *Label) const { + assert(IsOutlinedSEHHelper() && "Not in an outlined SEH helper"); + return StmtContainsLabelDecl(OutlinedSEHStmt, Label); +} + void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { // If this code is reachable then emit a stop point (if generating // debug info). We have to do this ourselves because we are on the @@ -855,6 +872,15 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { if (HaveInsertPoint()) EmitStopPoint(&S); + // MSVC C4532: jumping out of an outlined SEH helper is UB, but jumping + // internally should be fine. Sema has a warn for this already. + // `br` should not jump out of the current function anyway, so a jump out of + // the outlined SEH helper will cause a compiler crash. + if (IsOutlinedSEHHelper() && !IsLabelWithinSEHHelper(S.getLabel())) { + Builder.CreateUnreachable(); + Builder.ClearInsertionPoint(); + } + ApplyAtomGroup Grp(getDebugInfo()); EmitBranchThroughCleanup(getJumpDestForLabel(S.getLabel())); } @@ -1627,7 +1653,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { } // Returning from an outlined SEH helper is UB, and we already warn on it. - if (IsOutlinedSEHHelper) { + if (IsOutlinedSEHHelper()) { Builder.CreateUnreachable(); Builder.ClearInsertionPoint(); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index dfb6f2ff65a7d..9ff301bf4cd60 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -605,9 +605,16 @@ class CodeGenFunction : public CodeGenTypeCache { GlobalDecl CurSEHParent; - /// True if the current function is an outlined SEH helper. This can be a - /// finally block or filter expression. - bool IsOutlinedSEHHelper = false; + /// Pointer to the outlined SEH helper statement if current function is an + /// outlined SEH helper, nullptr otherwise. This can be a finally block or + /// a filter expression. + const Stmt *OutlinedSEHStmt = nullptr; + + /// True if the current function is an outlined SEH helper. + bool IsOutlinedSEHHelper() const { return OutlinedSEHStmt != nullptr; } + + /// True if Label is found within OutlinedSEHStmt. + bool IsLabelWithinSEHHelper(const LabelDecl *Label) const; /// True if CodeGen currently emits code inside presereved access index /// region. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
