Author: Benedek Kaibas Date: 2026-09-25T15:06:54+02:00 New Revision: a509a4e98a50a2acc172a5f6eba77b8df020e3cd
URL: https://github.com/llvm/llvm-project/commit/a509a4e98a50a2acc172a5f6eba77b8df020e3cd DIFF: https://github.com/llvm/llvm-project/commit/a509a4e98a50a2acc172a5f6eba77b8df020e3cd.diff LOG: [LifetimeSafety] Enable C support by default under -Wlifetime-safety (#224028) This PR extends the lifetime safety analysis to C. When the analysis is enabled with `-Wlifetime-safety`, it now also runs on C code without the extra `-fexperimental-lifetime-safety-c` flag. I have renamed `-fexperimental-lifetime-safety-c` to `-flifetime-safety-c` since it is on by default from now on. The `-fno-lifetime-safety-c` flag disables the analysis for C. I have updated the documentation and the release notes and rewrote the RUN lines of the test cases that used the old flag. Added: clang/test/Driver/flifetime-safety-c.c Modified: clang/docs/LifetimeSafety.md clang/docs/ReleaseNotes.md clang/include/clang/Basic/LangOptions.def clang/include/clang/Options/Options.td clang/lib/Driver/ToolChains/Clang.cpp clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c clang/test/Sema/LifetimeSafety/safety-c.c Removed: ################################################################################ diff --git a/clang/docs/LifetimeSafety.md b/clang/docs/LifetimeSafety.md index dcf206547643d..dbf67cfb2ce77 100644 --- a/clang/docs/LifetimeSafety.md +++ b/clang/docs/LifetimeSafety.md @@ -3,7 +3,7 @@ ## Introduction -Clang Lifetime Safety Analysis is a C++ language extension which warns about +Clang Lifetime Safety Analysis is a C and C++ language extension which warns about potential dangling pointer defects in code. The analysis aims to detect when a pointer, reference or view type (such as `std::string_view`) refers to an object that is no longer alive, a condition that leads to use-after-free bugs and @@ -57,6 +57,24 @@ The analysis flags the assignment `v = s` as defective because `s` is destroyed while `v` is still alive and points to `s`, and adds a note to where `v` is used after `s` has been destroyed. +```c +#include <stdio.h> +void simple_dangle() { + int *ptr = NULL; + { + int i = 5; + ptr = &i; // warning: local variable 'i' does not live long enough + } // note: local variable 'i' is destroyed here + *ptr = 6; // note: later used here +} +``` + +This example demonstrates a simples use-after-scope bug in C. The `ptr` pointer +is set to `NULL` in the outer scope. In the inner scope ptr points to `i`, but +its lifetime ends at the end of the inner block which causes `ptr` to dangle +when it is set to 6. + + ### Running The Analysis To run the analysis, compile with the `-Wlifetime-safety-permissive` flag, e.g. @@ -66,7 +84,9 @@ clang -c -Wlifetime-safety-permissive example.cpp ``` This flag enables a core set of lifetime safety checks. For more fine-grained -control over warnings, see {ref}`warning_flags`. +control over warnings, see {ref}`warning_flags`. The analysis runs for both +C and C++ by default. Use `-fno-lifetime-safety-c` to disable the analysis +for C code. ## Lifetime Annotations diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 702ff4a17d5c0..48d9b05597868 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -382,6 +382,9 @@ features cannot lower the translation-unit ABI level; }; ``` +- Lifetime safety analysis is now enabled for C by default. The `-fexperimental-lifetime-safety-c` + flag is renamed to `-flifetime-safety-c`. Use `-fno-lifetime-safety-c` to disable it. + - Improved `-Wassign-enum` performance by caching enum enumerator values. (#GH176454) - Fixed a false negative in `-Warray-bounds` where the warning was suppressed diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index d7637f2dfd507..c4ae12cd44bed 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -525,7 +525,7 @@ LANGOPT(BoundsSafety, 1, 0, NotCompatible, "Bounds safety extension for C") LANGOPT(DebugRunLifetimeSafety, 1, 0, Benign, "Run lifetime safety analysis for C++. Does not enable warnings.") -LANGOPT(EnableLifetimeSafetyInC, 1, 0, Benign, "Lifetime safety analysis for C") +LANGOPT(EnableLifetimeSafetyInC, 1, 1, Benign, "Lifetime safety analysis for C") LANGOPT(LifetimeSafetyMaxCFGBlocks, 32, 0, Benign, "Skip LifetimeSafety analysis for functions with CFG block count exceeding this threshold. Specify 0 for no limit") diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 15b2196b68e76..1b1a00de20040 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -2121,12 +2121,11 @@ defm debug_run_lifetime_safety : BoolFOption< NegFlag<SetFalse, [], [CC1Option], "Disable">, BothFlags<[], [CC1Option], " lifetime safety analysis for C++. Warnings are still controlled by -Wlifetime-safety. Primarily used to surface crashes or compile-time regressions without showing analysis findings.">>; -defm experimental_lifetime_safety_c : BoolFOption< - "experimental-lifetime-safety-c", - LangOpts<"EnableLifetimeSafetyInC">, DefaultFalse, - PosFlag<SetTrue, [], [CC1Option], "Enable">, - NegFlag<SetFalse, [], [CC1Option], "Disable">, - BothFlags<[], [CC1Option], " experimental lifetime safety analysis for C">>; +defm lifetime_safety_c : BoolFOption< + "lifetime-safety-c", + LangOpts<"EnableLifetimeSafetyInC">, DefaultTrue, + NegFlag<SetFalse, [], [ClangOption, CC1Option]>, + PosFlag<SetTrue, [], [ClangOption], "Enable lifetime safety analysis for C">>; def lifetime_safety_max_cfg_blocks : Joined<["-"], "lifetime-safety-max-cfg-blocks=">, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 6636a5fd6e655..d42af0b16a1eb 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4554,6 +4554,9 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, Args.addOptInFlag(CmdArgs, options::OPT_fdiagnostics_show_hotness, options::OPT_fno_diagnostics_show_hotness); + Args.addOptOutFlag(CmdArgs, options::OPT_flifetime_safety_c, + options::OPT_fno_lifetime_safety_c); + if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { std::string Opt = diff --git a/clang/test/Driver/flifetime-safety-c.c b/clang/test/Driver/flifetime-safety-c.c new file mode 100644 index 0000000000000..28579add0f04d --- /dev/null +++ b/clang/test/Driver/flifetime-safety-c.c @@ -0,0 +1,7 @@ +/// -flifetime-safety-c is the default +// RUN: %clang -### -c %s 2>&1 | FileCheck --check-prefix=ENABLED %s +// ENABLED-NOT: "-fno-lifetime-safety-c" + +// RUN: %clang -### -c %s -flifetime-safety-c -fno-lifetime-safety-c 2>&1 | \ +// RUN: FileCheck --check-prefix=DISABLED %s +// DISABLED: "-fno-lifetime-safety-c" diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c index 0ad009fa0c559..58ffea304d7b9 100644 --- a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c +++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c @@ -1,18 +1,18 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \ +// RUN: %clang_cc1 -fsyntax-only -std=c17 \ // RUN: -Wlifetime-safety-suggestions -Wno-dangling \ // RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -// RUN: %clang_cc1 -fsyntax-only -std=c23 -fexperimental-lifetime-safety-c \ +// RUN: %clang_cc1 -fsyntax-only -std=c23 \ // RUN: -Wlifetime-safety-suggestions -Wno-dangling \ // RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s --check-prefix=CHECK-C23 -// RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \ +// RUN: %clang_cc1 -fsyntax-only -std=c17 \ // RUN: -Wlifetime-safety-suggestions -Wno-dangling \ // RUN: '-DLIFETIMEBOUND_MACRO=__attribute__((lifetimebound))' \ // RUN: -lifetime-safety-lifetimebound-macro=LIFETIMEBOUND_MACRO \ // RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s --check-prefix=CHECK-MACRO // RUN: cp %s %t.c -// RUN: %clang_cc1 -std=c17 -fexperimental-lifetime-safety-c \ +// RUN: %clang_cc1 -std=c17 \ // RUN: -Wlifetime-safety-suggestions -Wno-dangling -fixit %t.c -// RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \ +// RUN: %clang_cc1 -fsyntax-only -std=c17 \ // RUN: -Werror=lifetime-safety-suggestions -Wno-dangling %t.c int *return_pointer(int *p) { diff --git a/clang/test/Sema/LifetimeSafety/safety-c.c b/clang/test/Sema/LifetimeSafety/safety-c.c index 171ac15341efe..8e6ca521c1804 100644 --- a/clang/test/Sema/LifetimeSafety/safety-c.c +++ b/clang/test/Sema/LifetimeSafety/safety-c.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -Wno-varargs -Wno-non-pod-varargs -verify -fexperimental-lifetime-safety-c %s -// RUN: %clang_cc1 -fsyntax-only -Werror=lifetime-safety -Wno-dangling -Wno-varargs -Wno-non-pod-varargs %s +// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -Wno-varargs -Wno-non-pod-varargs -verify %s +// RUN: %clang_cc1 -fsyntax-only -Werror=lifetime-safety -Wno-dangling -Wno-varargs -Wno-non-pod-varargs -fno-lifetime-safety-c %s int *identity(int *p __attribute__((lifetimebound))) { return p; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
