https://github.com/ilovepi updated https://github.com/llvm/llvm-project/pull/174894
>From fa99d157049ec7abc7c8fdac734d9cd4d730bcc7 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Wed, 7 Jan 2026 14:30:55 -0800 Subject: [PATCH 1/3] [clang][driver] Expose a frontend option for trap-unreachable We have several issues that list surprising behavior around UB. In many cases, this causes undesirable control flow, such as execution falling through to the next function (or whatever is in memory) instead of remaining within the bounds of the procedure. #174844, #48943, #146791, and #137741 all discuss a host of related issues. In #174844, it was mentioned that we have backend support for this for Rust, and at least one big class of these issues could be addressed by exposing the option to clang. This patch adds a new driver option that does just that. For now, we're leaving this option off by default, though we expect only small differences in code size or performance as a result if it were to be enabled. There will be an RFC in the future when we have more confidence this should be the default configuration. Fixes #174844 --- clang/docs/ReleaseNotes.rst | 2 ++ clang/include/clang/Basic/CodeGenOptions.def | 3 +++ clang/include/clang/Options/Options.td | 7 +++++++ clang/lib/CodeGen/BackendUtil.cpp | 1 + clang/lib/Driver/ToolChains/Clang.cpp | 3 +++ clang/test/CodeGen/X86/unreachable-trap.c | 18 ++++++++++++++++++ clang/test/Driver/clang_f_opts.c | 5 +++++ 7 files changed, 39 insertions(+) create mode 100644 clang/test/CodeGen/X86/unreachable-trap.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c56d2015f7a3f..cf81164671ee3 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -363,6 +363,8 @@ New Compiler Flags - New options for enabling allocation token instrumentation: ``-fsanitize=alloc-token``, ``-falloc-token-max=``, ``-fsanitize-alloc-token-fast-abi``, ``-fsanitize-alloc-token-extended``. - The ``-resource-dir`` option is now displayed in the list of options shown by ``--help``. - New option ``-fmatrix-memory-layout`` added to control the memory layout of Clang matrix types. (e.g. ``-fmatrix-memory-layout=column-major`` or ``-fmatrix-memory-layout=row-major``). +- New option ``-ftrap-unreachable`` added to enable the existing backend option: TrapUnreachable. + This behavior is off by default (e.g. no change in the compiler's behavior) for now. Lanai Support ^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index baf8b093c10e6..3bf91c56c4cf1 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -430,6 +430,9 @@ CODEGENOPT(DirectAccessExternalData, 1, 0, Benign) /// paths that reach the end of a function without executing a required return. CODEGENOPT(StrictReturn, 1, 1, Benign) +/// Whether we should use make unreachable trap or not. +CODEGENOPT(TrapUnreachable, 1, 0, Benign) + /// Whether emit pseudo probes for sample pgo profile collection. CODEGENOPT(PseudoProbeForProfiling, 1, 0, Benign) diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index d48ca15864060..d68160c518516 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -4685,6 +4685,13 @@ defm strict_return : BoolFOption<"strict-return", " of a non-void function as unreachable">, PosFlag<SetTrue>>; +defm trap_unreachable + : BoolFOption<"trap-unreachable", CodeGenOpts<"TrapUnreachable">, + DefaultFalse, + PosFlag<SetTrue, [], [ClangOption, CC1Option], + "Treat unreachable instructions as traps">, + NegFlag<SetFalse>>; + let Flags = [TargetSpecific] in { defm ptrauth_intrinsics : OptInCC1FFlag<"ptrauth-intrinsics", "Enable pointer authentication intrinsics">; defm ptrauth_calls : OptInCC1FFlag<"ptrauth-calls", "Enable signing and authentication of all indirect calls">; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index d411ef1bf8763..acb262f584328 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -468,6 +468,7 @@ static bool initTargetOptions(const CompilerInstance &CI, Options.XCOFFReadOnlyPointers = CodeGenOpts.XCOFFReadOnlyPointers; Options.VecLib = convertDriverVectorLibraryToVectorLibrary(CodeGenOpts.getVecLib()); + Options.TrapUnreachable = CodeGenOpts.TrapUnreachable; switch (CodeGenOpts.getSwiftAsyncFramePointer()) { case CodeGenOptions::SwiftAsyncFramePointerKind::Auto: diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 4ca98600d6e93..e76319a3ac563 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5848,6 +5848,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptInFlag(CmdArgs, options::OPT_fsplit_stack, options::OPT_fno_split_stack); + Args.addOptInFlag(CmdArgs, options::OPT_ftrap_unreachable, + options::OPT_ftrap_unreachable); + // -fprotect-parens=0 is default. if (Args.hasFlag(options::OPT_fprotect_parens, options::OPT_fno_protect_parens, false)) diff --git a/clang/test/CodeGen/X86/unreachable-trap.c b/clang/test/CodeGen/X86/unreachable-trap.c new file mode 100644 index 0000000000000..bea34e80dd873 --- /dev/null +++ b/clang/test/CodeGen/X86/unreachable-trap.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu -ftrap-unreachable -S -o - 2>&1 | FileCheck %s --check-prefix=TRAP +// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu -S -o - 2>&1 | FileCheck %s --check-prefix=NOTRAP + +// TRAP: ud2 +// NOTRAP-NOT: ud2 + +[[noreturn]] +void exit(int); + +#define NULL 0 + +static void test(void) { + int *ptr = NULL; + *ptr = 0; + exit(0); +} + +void foo() { test(); } diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index 5871f1580d6b7..aedbef393abcc 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -651,3 +651,8 @@ // RUN: %clang -### --target=x86_64-pc-windows-msvc -fno-strict-aliasing %s 2>&1 | FileCheck -check-prefix=CHECK-NO-STRICT-ALIASING %s // CHECK-STRICT-ALIASING-NOT: -relaxed-aliasing // CHECK-NO-STRICT-ALIASING: -relaxed-aliasing + +// RUN: %clang -### -ftrap-unreachable %s 2>&1 | FileCheck %s -check-prefix=UNREACHABLE-TRAP +// RUN: %clang -### -fno-trap-unreachable %s 2>&1 | FileCheck %s -check-prefix=NO-UNREACHABLE-TRAP +// UNREACHABLE-TRAP: "-ftrap-unreachable" +// NO-UNREACHABLE-TRAP-NOT: "-ftrap-unreachable" >From 815adb8d1daf6058016bc4bc7dc909ffa82e5c00 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Mon, 12 Jan 2026 11:53:59 -0800 Subject: [PATCH 2/3] Also support NoTrapAfterNoreturn --- clang/include/clang/Basic/CodeGenOptions.def | 6 ++--- clang/include/clang/Basic/CodeGenOptions.h | 6 +++++ clang/include/clang/Options/Options.td | 13 ++++++----- clang/lib/CodeGen/BackendUtil.cpp | 12 +++++++++- clang/lib/Driver/ToolChains/Clang.cpp | 5 ++--- clang/test/CodeGen/X86/unreachable-trap.c | 23 +++++++++++++++----- clang/test/Driver/clang_f_opts.c | 12 ++++++---- 7 files changed, 55 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 3bf91c56c4cf1..90303062779b8 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -413,6 +413,9 @@ VALUE_CODEGENOPT(TLSSize, 8, 0, Benign) /// The types of variables that we will extend the live ranges of. ENUM_CODEGENOPT(ExtendVariableLiveness, ExtendVariableLivenessKind, 2, ExtendVariableLivenessKind::None, Benign) +/// Whether we should use make unreachable trap or not. +ENUM_CODEGENOPT(TrapUnreachable, TrapUnreachableKind, 2, TrapUnreachableKind::None, Benign) + /// The default stack protector guard offset to use. VALUE_CODEGENOPT(StackProtectorGuardOffset, 32, INT_MAX, Benign) @@ -430,9 +433,6 @@ CODEGENOPT(DirectAccessExternalData, 1, 0, Benign) /// paths that reach the end of a function without executing a required return. CODEGENOPT(StrictReturn, 1, 1, Benign) -/// Whether we should use make unreachable trap or not. -CODEGENOPT(TrapUnreachable, 1, 0, Benign) - /// Whether emit pseudo probes for sample pgo profile collection. CODEGENOPT(PseudoProbeForProfiling, 1, 0, Benign) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index c60ca507ff917..6265272f9507f 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -126,6 +126,12 @@ class CodeGenOptions : public CodeGenOptionsBase { All, }; + enum class TrapUnreachableKind { + None, + ExceptNoreturn, + All, + }; + enum InlineAsmDialectKind { IAD_ATT, IAD_Intel, diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index d68160c518516..8d0cb76db2664 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -4685,12 +4685,13 @@ defm strict_return : BoolFOption<"strict-return", " of a non-void function as unreachable">, PosFlag<SetTrue>>; -defm trap_unreachable - : BoolFOption<"trap-unreachable", CodeGenOpts<"TrapUnreachable">, - DefaultFalse, - PosFlag<SetTrue, [], [ClangOption, CC1Option], - "Treat unreachable instructions as traps">, - NegFlag<SetFalse>>; +def ftrap_unreachable : Joined<["-"], "ftrap-unreachable=">, + Group<f_Group>, Visibility<[ClangOption, CC1Option]>, + HelpText<"Treat unreachable instruction as traps.">, + Values<"all,except-noreturn,none">, + NormalizedValues<["All", "ExceptNoreturn", "None"]>, + NormalizedValuesScope<"CodeGenOptions::TrapUnreachableKind">, + MarshallingInfoEnum<CodeGenOpts<"TrapUnreachable">, "None">; let Flags = [TargetSpecific] in { defm ptrauth_intrinsics : OptInCC1FFlag<"ptrauth-intrinsics", "Enable pointer authentication intrinsics">; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index acb262f584328..cacce9f30b48d 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -468,7 +468,17 @@ static bool initTargetOptions(const CompilerInstance &CI, Options.XCOFFReadOnlyPointers = CodeGenOpts.XCOFFReadOnlyPointers; Options.VecLib = convertDriverVectorLibraryToVectorLibrary(CodeGenOpts.getVecLib()); - Options.TrapUnreachable = CodeGenOpts.TrapUnreachable; + + switch(CodeGenOpts.getTrapUnreachable()){ + case clang::CodeGenOptions::TrapUnreachableKind::ExceptNoreturn: + Options.NoTrapAfterNoreturn = true; + LLVM_FALLTHROUGH; + case clang::CodeGenOptions::TrapUnreachableKind::All: + Options.TrapUnreachable = true; + break; + case clang::CodeGenOptions::TrapUnreachableKind::None: + break; + }; switch (CodeGenOpts.getSwiftAsyncFramePointer()) { case CodeGenOptions::SwiftAsyncFramePointerKind::Auto: diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index e76319a3ac563..4c3d04a0bbd7f 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5848,9 +5848,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptInFlag(CmdArgs, options::OPT_fsplit_stack, options::OPT_fno_split_stack); - Args.addOptInFlag(CmdArgs, options::OPT_ftrap_unreachable, - options::OPT_ftrap_unreachable); - // -fprotect-parens=0 is default. if (Args.hasFlag(options::OPT_fprotect_parens, options::OPT_fno_protect_parens, false)) @@ -5865,6 +5862,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.addOptInFlag(CmdArgs, options::OPT_fatomic_ignore_denormal_mode, options::OPT_fno_atomic_ignore_denormal_mode); + Args.addLastArg(CmdArgs, options::OPT_ftrap_unreachable); + if (Arg *A = Args.getLastArg(options::OPT_fextend_args_EQ)) { const llvm::Triple::ArchType Arch = TC.getArch(); if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { diff --git a/clang/test/CodeGen/X86/unreachable-trap.c b/clang/test/CodeGen/X86/unreachable-trap.c index bea34e80dd873..e7f2adc3f9f9b 100644 --- a/clang/test/CodeGen/X86/unreachable-trap.c +++ b/clang/test/CodeGen/X86/unreachable-trap.c @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu -ftrap-unreachable -S -o - 2>&1 | FileCheck %s --check-prefix=TRAP -// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu -S -o - 2>&1 | FileCheck %s --check-prefix=NOTRAP +// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu -ftrap-unreachable=all -S -o - 2>&1 | FileCheck %s --check-prefixes=TRAP,COMMON +// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu -ftrap-unreachable=except-noreturn -S -o - 2>&1 | FileCheck %s --check-prefixes=NORETURN,COMMON +// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu -ftrap-unreachable=none -S -o - 2>&1 | FileCheck %s --check-prefixes=NOTRAP,COMMON -// TRAP: ud2 // NOTRAP-NOT: ud2 [[noreturn]] @@ -9,10 +9,23 @@ void exit(int); #define NULL 0 -static void test(void) { +[[gnu::noinline]] +[[noreturn]] +void a() { +// COMMON-LABEL: a: +// TRAP: ud2 +// NORETURN: ud2 int *ptr = NULL; *ptr = 0; exit(0); } -void foo() { test(); } +[[gnu::noinline]] +[[noreturn]] + void b() { +// COMMON-LABEL: b: +// COMMON: call{{.*}} exit +// TRAP: ud2 +// NORETURN-NOT: ud2 + exit(0); +} diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index aedbef393abcc..68db27a2f63d2 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -652,7 +652,11 @@ // CHECK-STRICT-ALIASING-NOT: -relaxed-aliasing // CHECK-NO-STRICT-ALIASING: -relaxed-aliasing -// RUN: %clang -### -ftrap-unreachable %s 2>&1 | FileCheck %s -check-prefix=UNREACHABLE-TRAP -// RUN: %clang -### -fno-trap-unreachable %s 2>&1 | FileCheck %s -check-prefix=NO-UNREACHABLE-TRAP -// UNREACHABLE-TRAP: "-ftrap-unreachable" -// NO-UNREACHABLE-TRAP-NOT: "-ftrap-unreachable" +// RUN: %clang -### -ftrap-unreachable=all %s 2>&1 | FileCheck %s -check-prefix=UNREACHABLE-TRAP-ALL +// RUN: %clang -### -ftrap-unreachable=none %s 2>&1 | FileCheck %s -check-prefix=UNREACHABLE-TRAP-NONE +// RUN: %clang -### -ftrap-unreachable=except-noreturn %s 2>&1 | FileCheck %s -check-prefix=UNREACHABLE-TRAP-EXCEPT-NORETURN +// RUN: %clang -### %s 2>&1 | FileCheck %s -check-prefix=UNREACHABLE-TRAP-EMPTY +// UNREACHABLE-TRAP-ALL: "-ftrap-unreachable=all" +// UNREACHABLE-TRAP-EXCEPT-NORETURN: "-ftrap-unreachable=except-noreturn" +// UNREACHABLE-TRAP-NONE: "-ftrap-unreachable=none" +// UNREACHABLE-TRAP-EMPTY-NOT: -ftrap-unreachable >From 1f698eb5d01ecfb33477463c7f1576e39c391057 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Mon, 12 Jan 2026 13:08:51 -0800 Subject: [PATCH 3/3] Fix formatting --- clang/include/clang/Options/Options.td | 16 +++++++++------- clang/lib/CodeGen/BackendUtil.cpp | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 8d0cb76db2664..3ff2177477de4 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -4685,13 +4685,15 @@ defm strict_return : BoolFOption<"strict-return", " of a non-void function as unreachable">, PosFlag<SetTrue>>; -def ftrap_unreachable : Joined<["-"], "ftrap-unreachable=">, - Group<f_Group>, Visibility<[ClangOption, CC1Option]>, - HelpText<"Treat unreachable instruction as traps.">, - Values<"all,except-noreturn,none">, - NormalizedValues<["All", "ExceptNoreturn", "None"]>, - NormalizedValuesScope<"CodeGenOptions::TrapUnreachableKind">, - MarshallingInfoEnum<CodeGenOpts<"TrapUnreachable">, "None">; +def ftrap_unreachable + : Joined<["-"], "ftrap-unreachable=">, + Group<f_Group>, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Treat unreachable instruction as traps.">, + Values<"all,except-noreturn,none">, + NormalizedValues<["All", "ExceptNoreturn", "None"]>, + NormalizedValuesScope<"CodeGenOptions::TrapUnreachableKind">, + MarshallingInfoEnum<CodeGenOpts<"TrapUnreachable">, "None">; let Flags = [TargetSpecific] in { defm ptrauth_intrinsics : OptInCC1FFlag<"ptrauth-intrinsics", "Enable pointer authentication intrinsics">; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index cacce9f30b48d..3f5f68e444edd 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -469,7 +469,7 @@ static bool initTargetOptions(const CompilerInstance &CI, Options.VecLib = convertDriverVectorLibraryToVectorLibrary(CodeGenOpts.getVecLib()); - switch(CodeGenOpts.getTrapUnreachable()){ + switch (CodeGenOpts.getTrapUnreachable()) { case clang::CodeGenOptions::TrapUnreachableKind::ExceptNoreturn: Options.NoTrapAfterNoreturn = true; LLVM_FALLTHROUGH; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
