Add a parameter to `shouldTrackImplicitObjectArg` to differentiate
between lifetime safety analysis and statement-local analysis.
The statement-local analysis was experiencing false positives when
tracking dereference operators for GSL pointers, so this change allows
for more aggressive tracking in the full analysis while being more
conservative in the statement-local analysis.
- Added a `RunningUnderLifetimeSafety` boolean parameter to
`shouldTrackImplicitObjectArg` function to distinguish between lifetime
safety analysis and Sema's statement-local analysis
- Enhanced tracking of dereference operators for GSL pointers in STL:
- Now tracks both `operator*` and `operator->` when running under
lifetime safety analysis
- Avoids tracking these operators in statement-local analysis to prevent
false positives
Corrected various spelling mistakes such as 'occurred', 'receiver',
'initialized', 'length', and others in comments, variable names,
function names, and documentation throughout the project. These
changes improve code readability and maintain consistency in naming
and documentation.
Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
Add support for tracking STL container methods and free functions in the
lifetime safety analysis.
- Added `VisitExprWithCleanups` to the `FactsGenerator` to properly
handle expressions with cleanup code
- Moved `shouldTrackImplicitObjectArg` and `shouldTrackFirstArgument`
from `CheckExprLifetime.cpp` to `LifetimeAnnotations.h/cpp` to make them
available to the lifetime safety analysis
- Enhanced the lifetime analysis to track STL container methods that
return pointers or references dependent on the container's lifetime
(e.g., `begin()`, `data()`, `c_str()`)
- Added support for tracking free functions like `std::begin`,
`std::data`, and `std::any_cast` that return pointers or references
dependent on their arguments
Fixes https://github.com/llvm/llvm-project/issues/162622
fixes#159434
In HLSL matrices are matrix_type in all respects except that they
support a constructor style syntax for initializing matrices.
This change adds a translation of vector constructor arguments into
initializer lists.
This supports the following HLSL syntax:
(1) HLSL matrices support constructor syntax
(2) HLSL matrices are expanded to constituate components in constructor
using the same initalizer list behavior defined in transformInitList
allows us to support struct element initalization via
HLSLElementwiseCast
Switch to the `.Cases({S0, S1, ...}, Value)` overload instead, and the
manually-enumerated overloads with 6+ arguments are getting deprecated
in https://github.com/llvm/llvm-project/pull/163405.
This pre-commits API updates ahead of the deprecation to make potential
reverts cleaner. This was already reviewed in #163405.
Restructure the C++ Lifetime Safety Analysis into modular components
with clear separation of concerns.
This PR reorganizes the C++ Lifetime Safety Analysis code by:
1. Breaking up the monolithic `LifetimeSafety.cpp` (1500+ lines) into
multiple smaller, focused files
2. Creating a dedicated `LifetimeSafety` directory with a clean
component structure
3. Introducing header files for each component with proper documentation
4. Moving existing code into the appropriate component files:
- `Checker.h/cpp`: Core lifetime checking logic
- `Dataflow.h`: Generic dataflow analysis framework
- `Facts.h`: Lifetime-relevant events and fact management
- `FactsGenerator.h/cpp`: AST traversal for fact generation
- `LiveOrigins.h/cpp`: Backward dataflow analysis for origin liveness
- `LoanPropagation.h/cpp`: Forward dataflow analysis for loan tracking
- `Loans.h`: Loan and access path definitions
- `Origins.h`: Origin management
- `Reporter.h`: Interface for reporting lifetime violations
- `Utils.h`: Common utilities for the analysis
The code functionality remains the same, but is now better organized
with clearer interfaces between components.
Add support for `lifetimebound` attributes in the lifetime safety
analysis to track loans from function parameters to return values.
Implemented support for `lifetimebound` attributes on function
parameters
This change replaces the single `AssignOriginFact` with two separate
operations: `OriginFlowFact` and `KillOriginFact`. The key difference is
in semantics:
* Old `AssignOriginFact`: Replaced the destination origin's loans
entirely with the source origin's loans.
* New `OriginFlowFact`: Can now optionally merge the source origin's
loans to the destination's existing loans.
* New `KillOriginFact`: Clears all loans from an origin.
For function calls with `lifetimebound` parameters, we kill the the
return value' origin first then use `OriginFlowFact` to accumulate loans
from multiple parameters into the return value's origin - enabling
tracking multiple lifetimebound arguments.
- Added a new `LifetimeAnnotations.h/cpp` to provide helper functions
for inspecting and inferring lifetime annotations
- Moved several functions from `CheckExprLifetime.cpp` to the new file
to make them reusable
The `lifetimebound` attribute is a key mechanism for expressing lifetime
dependencies between function parameters and return values. This change
enables the lifetime safety analysis to properly track these
dependencies, allowing it to detect more potential dangling reference
issues.
This reintroduces `Type.h`, having earlier been renamed to `TypeBase.h`,
as a redirection to `TypeBase.h`, and redirects most users to include
the former instead.
This is a preparatory patch for being able to provide inline definitions
for `Type` methods which would otherwise cause a circular dependency
with `Decl{,CXX}.h`.
Doing these operations into their own NFC patch helps the git rename
detection logic work, preserving the history.
This patch makes clang just a little slower to build (~0.17%), just
because it makes more code indirectly include `DeclCXX.h`.
This is a preparatory patch, to be able to provide inline definitions
for `Type` functions which depend on `Decl{,CXX}.h`. As the latter also
depends on `Type.h`, this would not be possible without some
reorganizing.
Splitting this rename into its own patch allows git to track this as a
rename, and preserve all git history, and not force any code
reformatting.
A later NFC patch will reintroduce `Type.h` as redirection to
`TypeBase.h`, rewriting most places back to directly including `Type.h`
instead of `TypeBase.h`, leaving only a handful of places where this is
necessary.
Then yet a later patch will exploit this by making more stuff inline.
C++23 mandates that temporaries used in range-based for loops are
lifetime-extended
to cover the full loop. This patch adds a check for loop variables and
compiler-
generated `__range` bindings to apply the correct extension.
Includes test cases based on examples from CWG900/P2644R1.
Fixes https://github.com/llvm/llvm-project/issues/109793
Microsoft helpfully defines `THIS` to `void` in two different platform
SDK headers, at least one of which is reachable via <Windows.h>. We have
a user who ran into a build because of `THIS` unfortunate macro name
collision.
Rename the members to better match our naming conventions.
Fixes#142186
This fixes a false positive caused by #114044.
For `GSLPointer*` types, it's less clear whether the lifetime issue is
about the GSLPointer object itself or the owner it points to. To avoid
false positives, we take a conservative approach in our heuristic.
Fixes#127195
(This will be backported to release 20).
We currently have ad-hoc filtering logic for temporary object member
access in `VisitGSLPointerArg`. This logic filters out more cases than
it should, leading to false negatives. Furthermore, this location lacks
sufficient context to implement a more accurate solution.
This patch refines the filtering logic by moving it to the central
filtering location, `analyzePathForGSLPointer`, consolidating the logic
and avoiding scattered filtering across multiple places. As a result,
the special handling for conditional operators (#120233) is no longer
necessary.
This change also resolves#120543.
This partially fixes#62072 by making sure that re-declarations of a
function do not have the effect of removing lifetimebound from the
canonical declaration.
It doesn't handle the implicit 'this' parameter, but that can be
addressed in a separate fix.
When a vector is instantiated with a pointer type (`T` being `const
Foo*`), the inferred annotation becomes `push_back(const Foo*& value
[[clang::lifetime_capture_by(this)]])`.
For reference parameters, the `lifetime_capture_by` attribute treats the
lifetime as referring to the referenced object -- in this case, the
**pointer** itself, not the pointee object. In the `push_back`, we copy
the pointer's value, which does not establish a reference to the
pointer. This behavior is safe and does not capture the pointer's
lifetime.
The annotation should not be inferred for cases where `T` is a pointer
type, as the intended semantics do not align with the annotation.
Fixes#121391
When analyzing a dangling gsl pointer, we currently filter out all field
access `MemberExpr` to avoid common false positives (`string_view sv =
Temp().sv`), However, this filter only applies to direct MemberExpr
instances, leaving the conditional operator as an escaping example
(`GSLPointer pointer(Cond ? Owner().ptr : GSLPointer());`).
This patch extends the MemberExpr logic to handle the conditional
operator. The heuristic is intentionally simple, which may result in
some false negatives. However, it effectively covers common cases like
`std::string_view sv = cond ? "123" : std::string();`, which is a
reasonable trade-off.
Fixes https://github.com/llvm/llvm-project/issues/120206
The lifetime analyzer processes GSL pointers:
- when encountering a constructor for a `gsl::pointer`, the analyzer
continues traversing the constructor argument, regardless of whether the
parameter has a `lifetimebound` annotation. This aims to catch cases
where a GSL pointer is constructed from a GSL owner, either directly
(e.g., `FooPointer(FooOwner)`) or through a chain of GSL pointers (e.g.,
`FooPointer(FooPointer(FooOwner))`);
- When a temporary object is reported in the callback, the analyzer has
heuristics to exclude non-owner types, aiming to avoid false positives
(like `FooPointer(FooPointer())`).
In the problematic case (discovered in
https://github.com/llvm/llvm-project/pull/112751#issuecomment-2441055471)
of `return foo.get();`:
- When the analyzer reports the local object `foo`, the `Path` is
`[GslPointerInit, Lifetimebound]`.
- The `Path` goes through
[`pathOnlyHandlesGslPointer`](https://github.com/llvm/llvm-project/blob/main/clang/lib/Sema/CheckExprLifetime.cpp#L1136)
and isn’t filtered out by the [[heuristics]](because `foo` is an owner
type), the analyzer treats it as the `FooPointer(FooOwner())` scenario,
thus triggering a diagnostic.
Filtering out base on the object 'foo' is wrong, because the GSLPointer
is constructed from the return result of the `foo.get()`. The patch
fixes this by teaching the heuristic to use the return result (only
`const GSLOwner&` is considered) of the lifetimebound annotated
function.
A specialization declaration can have an attribute even if the primary
template does not, particularly when the specialization is instantiated
from an annotated using-alias declaration.
Fix#118064
Unlike brace initialization, the parenthesized aggregate initialization
in C++20 does not extend the lifetime of a temporary object bound to a
reference in an aggreate. This can lead to dangling references:
```
struct A { const int& r; };
A a1(1); // well-formed, but results in a dangling reference.
```
With this patch, clang will diagnose this common dangling issues.
Fixes#101957
With this change, the lifetime_capture_by code path will not handle the
constructor decl to avoid bogus diagnostics (see the testcase).
Instead, we reuse the lifetimebound code as the
lifetime_capture_by(this) has the same semantic as lifetimebound in
constructor. The downside is that the lifetimebound diagnostic is reused
for the capture case (I think it is not a big issue).
Fixes#117680
This patch correctes the handling of non-member functions in the
`isNormalAssignmentOperator` function within `CheckExprLifetime.cpp`.
The previous implementation incorrectly assumed that `FunctionDecl` is
always a `CXXMethodDecl`, leading to potential null pointer
dereferencing.
Change: - Correctly handle the case where `FD` is not a `CXXMethodDecl`
by using `FD->getParamDecl(0)->getType()`.
This fix ensures that the function correctly handles non-member
assignment operators, such as:
`struct S {}; void operator|=(S, S) {}`
This change improves the robustness of the `isNormalAssignmentOperator`
function by correctly identifying and handling different types of
function declarations.
This PR uses the existing lifetime analysis for the `capture_by`
attribute.
The analysis is behind `-Wdangling-capture` warning and is disabled by
default for now. Once it is found to be stable, it will be default
enabled.
Planned followup:
- add implicit inference of this attribute on STL container methods like
`std::vector::push_back`.
- (consider) warning if capturing `X` cannot capture anything. It should
be a reference, pointer or a view type.
- refactoring temporary visitors and other related handlers.
- start discussing `__global` vs `global` in the annotation in a
separate PR.
---------
Co-authored-by: Boaz Brickner <brickner@google.com>
This patch extends the filtering heuristic to apply for the
Lifetimebound code path.
This will suppress a common false positive:
```
namespace std {
template<typename T>
struct unique_ptr {
T &operator*();
T *get() const [[clang::lifetimebound]];
};
} // namespace std
struct X {
X(std::unique_ptr<int> up) :
pointer(up.get()), owner(std::move(up)) {}
int *pointer;
std::unique_ptr<int> owner;
};
```
See #114201.
This is a follow-up to https://github.com/llvm/llvm-project/pull/108344.
The original bailout check was overly strict, causing it to miss cases
like the vector(initializer_list, allocator) constructor. This patch
relaxes the check to address that issue.
Fix#111680
The lifetimes of local variables and function parameters must end before
the call to a [[clang::musttail]] function, instead of before the
return, because we will not have a stack frame to hold them when doing
the call.
This documents this limitation, and adds diagnostics to warn about some
code which is invalid because of it.
In the GSL analysis, we don't track the `this` object if the conversion
is not from gsl::owner to gsl pointer, we want to be conservative here
to avoid triggering false positives.
Fixes#108272
The PR reapply https://github.com/llvm/llvm-project/pull/97308.
- Implement [CWG1815](https://wg21.link/CWG1815): Support lifetime
extension of temporary created by aggregate initialization using a
default member initializer.
- Fix crash that introduced in
https://github.com/llvm/llvm-project/pull/97308. In
`InitListChecker::FillInEmptyInitForField`, when we enter
rebuild-default-init context, we copy all the contents of the parent
context to the current context, which will cause the `MaybeODRUseExprs`
to be lost. But we don't need to copy the entire context, only the
`DelayedDefaultInitializationContext` was required, which is used to
build `SourceLocExpr`, etc.
---------
Signed-off-by: yronglin <yronglin777@gmail.com>
This pull request enhances the GSL lifetime analysis to detect
situations where a dangling `Container<GSLPointer>` object is
constructed:
```cpp
std::vector<std::string_view> bad = {std::string()}; // dangling
```
The assignment case is not yet supported, but they will be addressed in
a follow-up.
Fixes#100526 (excluding the `push_back` case).
This reverts commit 45c8766973bb3bb73dd8d996231e114dcf45df9f
and 049512e39d96995cb373a76cf2d009a86eaf3aab.
This change triggers failed asserts on inputs like this:
struct a {
} constexpr b;
class c {
public:
c(a);
};
class B {
public:
using d = int;
struct e {
enum { f } g;
int h;
c i;
d j{};
};
};
B::e k{B::e::f, int(), b};
Compiled like this:
clang -target x86_64-linux-gnu -c repro.cpp
clang: ../../clang/lib/CodeGen/CGExpr.cpp:3105: clang::CodeGen::LValue
clang::CodeGen::CodeGenFunction::EmitDeclRefLValue(const clang::DeclRefExpr*):
Assertion `(ND->isUsed(false) || !isa<VarDecl>(ND) || E->isNonOdrUse() ||
!E->getLocation().isValid()) && "Should not use decl without marking it used!"' failed.
The warning is not emitted for the case `string_view c =
std::vector<std::string>({""}).at(0);` because we bail out during the
visit of the LHS at [this
point](5d2c324fea/clang/lib/Sema/CheckExprLifetime.cpp (L341-L343))
in the code.
This bailout was introduced in [this
commit](bcd0798c47)
to address a false positive with
`vector<vector::iterator>({""}).at(0);`. This PR refines that fix by
ensuring that, for initialization involving a gsl-pointer, we only
consider constructor calls that take the gsl-owner object.
Fixes#100384.
This allows clang to detect more use-after-free bugs (shown in the
#100549).
This relands the remaining change (removing the EnableLifetimeWarnings
flag) in https://github.com/llvm/llvm-project/pull/104906, with a proper
fix for the regression.
Fixes#100549