Detect dangling field references when stack memory escapes to class
fields. This change extends lifetime safety analysis to detect a common
class of temporal memory safety bugs where local variables or parameters
are stored in class fields but outlive their scope.
- Added a new `FieldEscapeFact` class to represent when an origin
escapes via assignment to a field
- Refactored `OriginEscapesFact` into a base class with specialized
subclasses for different escape scenarios
- Added detection for stack memory escaping to fields in constructors
and member functions
- Implemented new diagnostic for dangling field references with
appropriate warning messages
Importantly,
- Added `AddParameterDtors` option to CFG to add parameter dtors and
lifetime ends behind an option. In principle, parameters ctors and dtors
do not belong in the function context but in the caller context. This
becomes incorrect to include in function's CFG when we have inlined CFGs
like some analyses in the analyzer (produces double dtors for
arguments). Therefore this provides a way to opt-in to know about
destructed params on function exits.
In C++20 range-based for loops, variables declared in the init-statement
were not correctly added to the CFG builder's local scope. Consequently,
implicit destructors for these variables were missing from the CFG.
This caused analyses relying on the CFG to incorrectly model the
lifetime of these variables. Specifically, Thread Safety Analysis
reported false positives for RAII locks declared in the init-statement.
Fix it by calling addLocalScopeForStmt for the init-statement in
CFGBuilder::VisitCXXForRangeStmt. This ensures destructors are correctly
inserted into the CFG.
Fixes: https://github.com/abseil/abseil-cpp/issues/1901
This PR adds performance instrumentation to `clang::CallGraph` and
`clang::CFG` to aid in benchmarking the overhead of call
graph construction and CFG rebuilding.
This aims to facilitate benchmarking on large codebases like LLVM to
ensure that the performance impact of new analysis-based warnings
remains within acceptable regressions.
This PR enhances the CFG builder to properly handle function parameters
in lifetime analysis:
1. Added code to include parameters in the initial scope during CFG
construction for both `FunctionDecl` and `BlockDecl` types
2. Added a special case to skip reference parameters, as they don't need
automatic destruction
3. Fixed several test cases that were previously marked as "FIXME" due
to missing parameter lifetime tracking
Previously, Clang's lifetime analysis was not properly tracking the
lifetime of function parameters, causing it to miss important
use-after-return bugs when parameter values were returned by reference
or address. This change ensures that parameters are properly tracked in
the CFG, allowing the analyzer to correctly identify when stack memory
associated with parameters is returned.
Fixes https://github.com/llvm/llvm-project/issues/169014
By default, the `default:` branch (or the successor if there is no
`default` and cases return) of a switch on fully covered enumerations is
considered as "Unreachable". It is a sane assumption in most cases, but
not always. That commit allows to change such behavior when needed.
## Problem
Currently, functions with `analyzer_noreturn` attribute aren't
recognized as `no-return` by `CFG`:
```cpp
void assertion_handler() __attribute__((analyzer_noreturn)) {
log(...);
}
void handle_error(const std::optional<int> opt) {
if (!opt) {
fatal_error(); // Static analyzer doesn't know this never returns
}
*opt = 1; // False-positive `unchecked-optional-access` warning as analyzer thinks this is reachable
}
```
## Solution
1. Extend the `FunctionDecl` class by adding an `isAnalyzerNoReturn()`
function
2. Update `CFGBuilder::VisitCallExpr` to check both `FD->isNoReturn()`
and `FD->isAnalyzerNoReturn()` properties
## Comments
This PR incorporates part of the work done in
https://github.com/llvm/llvm-project/pull/146355
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.
`checkIncorrectLogicOperator` checks if an expression, for example `x !=
0 || x != 1.0`, is always true or false by comparing the two literals
`0` and `1.0`. But in case `x` is a 16-bit float, the two literals have
distinct types---16-bit float and double, respectively. Directly
comparing `APValue`s extracted from the two literals results in an
assertion failure because of their distinct types.
This commit fixes the issue by doing a conversion from the "smaller" one
to the "bigger" one. The two literals must be compatible because both of
them are comparing with `x`.
rdar://152456316
These are identified by misc-include-cleaner. I've filtered out those
that break builds. Also, I'm staying away from llvm-config.h,
config.h, and Compiler.h, which likely cause platform- or
compiler-specific build failures.
Closes#57270.
This PR changes the `Stmt *` field in `SymbolConjured` with
`CFGBlock::ConstCFGElementRef`. The motivation is that, when conjuring a
symbol, there might not always be a statement available, causing
information to be lost for conjured symbols, whereas the CFGElementRef
can always be provided at the callsite.
Following the idea, this PR changes callsites of functions to create
conjured symbols, and replaces them with appropriate `CFGElementRef`s.
There is a caveat at loop widening, where the correct location is the
CFG terminator (which is not an element and does not have a ref). In
this case, the first element in the block is passed as a location.
Previous PR #128251, Reverted at #137304.
This PR attempts to improve the diagnostics flag
`-Wtautological-overlap-compare` (#13473). I have added code to warn
about float-point literals and character literals. I have also changed
the warning message for the non-overlapping case to provide a more
correct hint to the user.
Fixes#13473.
This PR changes the `Stmt *` field in `SymbolConjured` with
`CFGBlock::ConstCFGElementRef`. The motivation is that, when conjuring a
symbol, there might not always be a statement available, causing
information to be lost for conjured symbols, whereas the CFGElementRef
can always be provided at the callsite.
Following the idea, this PR changes callsites of functions to create
conjured symbols, and replaces them with appropriate `CFGElementRef`s.
Closes#57270
This is the second attempt to bring initial support for [[assume()]] in
the Clang Static Analyzer.
The first attempt (#116462) was reverted in
2b9abf0db2d106c7208b4372e662ef5df869e6f1 due to some weird failure in a
libcxx test involving `#pragma clang loop vectorize(enable)
interleave(enable)`.
The failure could be reduced into:
```c++
template <class ExecutionPolicy>
void transform(ExecutionPolicy) {
#pragma clang loop vectorize(enable) interleave(enable)
for (int i = 0; 0;) { // The DeclStmt of "i" would be added twice in the ThreadSafety analysis.
// empty
}
}
void entrypoint() {
transform(1);
}
```
As it turns out, the problem with the initial patch was this:
```c++
for (const auto *Attr : AS->getAttrs()) {
if (const auto *AssumeAttr = dyn_cast<CXXAssumeAttr>(Attr)) {
Expr *AssumeExpr = AssumeAttr->getAssumption();
if (!AssumeExpr->HasSideEffects(Ctx)) {
childrenBuf.push_back(AssumeExpr);
}
}
// Visit the actual children AST nodes.
// For CXXAssumeAttrs, this is always a NullStmt.
llvm::append_range(childrenBuf, AS->children()); // <--- This was not meant to be part of the "for" loop.
children = childrenBuf;
}
return;
```
The solution was simple. Just hoist it from the loop.
I also had a closer look at `CFGBuilder::VisitAttributedStmt`, where I also spotted another bug.
We would have added the CFG blocks twice if the AttributedStmt would have both the `[[fallthrough]]` and the `[[assume()]]` attributes. With my fix, it will only once add the blocks. Added a regression test for this.
Co-authored-by: Vinay Deshmukh <vinay_deshmukh AT outlook DOT com>
This PR reapply https://github.com/llvm/llvm-project/pull/117437.
The issue has been fixed by the 2nd commit, we need to ignore parens in
CXXDefaultArgExpr when build CFG, because CXXDefaultArgExpr::getExpr
stripped off the top level FullExpr and ConstantExpr, ParenExpr may
occurres in the top level.
---------
Signed-off-by: yronglin <yronglin777@gmail.com>
The C++ standard prohibits this implicit destructor call, leading to
incorrect reports from clang-analyzer. This causes projects that use
std::option (including llvm) to fail the cplusplus.NewDelete test
incorrectly when run through the analyzer.
Fixes#119415
This caused assertion failures:
clang/lib/Analysis/CFG.cpp:822:
void (anonymous namespace)::CFGBuilder::appendStmt(CFGBlock *, const Stmt *):
Assertion `!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S' failed.
See comment on the PR.
This reverts commit 44aa618ef67d302f5ab77cc591fb3434fe967a2e.
Resolves#100762
Gist of the change:
1. All the symbol analysis, constraint manager and expression parsing
logic was already present, but the previous code didn't "visit" the
expressions within `assume()` by parsing those expressions, all of the
code "just works" by evaluating the SVals, and hence leaning on the same
logic that makes the code with `__builtin_assume` work
2. "Ignore" an expression from adding in CFG if it has side-effects (
similar to CGStmt.cpp (todo add link))
3. Add additional test case for ternary operator handling and modify
CFG.cpp's VisitGuardedExpr code for `continue`-ing if the `ProgramPoint`
is a `StmtPoint`
---------
Co-authored-by: Balazs Benics <benicsbalazs@gmail.com>
* Don't call raw_string_ostream::flush(), which is essentially a no-op.
* Strip unneeded calls to raw_string_ostream::str(), to avoid extra indirection.
Depends on https://github.com/llvm/llvm-project/pull/92527
Clang now support the following:
- Extending lifetime of object bound to reference members of aggregates,
that are created from default member initializer.
- Rebuild `CXXDefaultArgExpr` and `CXXDefaultInitExpr` as needed where
called or constructed.
But CFG and ExprEngine need to be updated to address this change.
This PR add `CXXDefaultArgExpr` and `CXXDefaultInitExpr` into CFG, and
correct handle these expressions in ExprEngine
---------
Signed-off-by: yronglin <yronglin777@gmail.com>
In PR #79382, I need to add a new type that derives from
ConstantArrayType. This means that ConstantArrayType can no longer use
`llvm::TrailingObjects` to store the trailing optional Expr*.
This change refactors ConstantArrayType to store a 60-bit integer and
4-bits for the integer size in bytes. This replaces the APInt field
previously in the type but preserves enough information to recreate it
where needed.
To reduce the number of places where the APInt is re-constructed I've
also added some helper methods to the ConstantArrayType to allow some
common use cases that operate on either the stored small integer or the
APInt as appropriate.
Resolves#85124.
This patch introduces a new warning flag -Wtautological-negation-compare grouped in -Wtautological-compare that warns on the use of && or || operators against a variable and its negation.
e.g. x || !x and !x && x
This also makes the -Winfinite-recursion diagnose more cases.
Fixes https://github.com/llvm/llvm-project/issues/56035
Differential Revision: https://reviews.llvm.org/D152093
I actually visited each link and added relevant context directly to the code.
This is related to the effort to eliminate internal bug tracker links
(d618f1c, e0ac46e).
Test files still have a lot of rdar links and ids in them.
I haven't touched them yet.
Per [stmt.for] p1 (https://eel.is/c++draft/stmt.for#1) the following
`for` and `while` statements are equivalent
```
for (; A c = b; b.c) {
A d;
}
while (A c = b) {
A d;
b.c;
}
```
As a consequence, the variable declared for the condition expression
should be destroyed after the increment expression.
This fixed the handling of the object lifetime `continue`, and now
destructors, scope and lifetime elements are present for continue
path in following code:
```
for (; A c = b; b.c) {
if (cond)
continue;
A d;
}
```
Reviewed By: xazax.hun
Differential Revision: https://reviews.llvm.org/D155547
This patch reworks generation for the `CFGScopeBegin`, `CFGScopeEnd`,
and `CFGLiftimeEnd`, in a way that they are now compatible with each
other and `CFGAutomaticObjDtor`. All of the above elements are now
generated by a single code path, that conditionally inserts elements if
they are requested.
In addition, the handling of `goto` statements is improved.
The `goto` statement may leave multiple scopes (and trigger destruction
and lifetime end for the affected variables) and enter multiple scopes,
for example:
```lang=C++
{
int s1;
{
int s2;
goto label; // leaves s1, s2, and enters t1 t1
}
}
{
int t1;
{
int t2;
label:
}
}
```
This is performed by first determining the shared parent scope of the
source and destination. And then emitting elements for exiting each
scope between the source and the parent, and entering each scope
between the parent and destination. All such elements are appended
to the source block, as one label may be reached from multiple scopes.
Finally, the approach for handling backward jumps is changed. When
connecting a source block to a destination block that requires the
insertion of additional elements, we put this element into a new block,
which is then linked between the source and the destination block.
For example:
```lang=C++
{
int t;
label:
// Destination block referred to as 'DB'
}
{
// Source block referred to as 'SB'
Obj s;
goto label;
}
```
The jump between `SB` with terminator `T: goto` and `DB` should be
coupled with the following CFG elements:
```
CFGAutomaticObjDtor(s)
CFGLifetimeEnd(s)
CFGScopeEnd(s)
CFGScopeBegin(t)
```
To handle such situations, we create a new link (`LB`) that is linked as
the predecessor of `DB`, to which we transfer the terminator (`goto`
statement) of `SB`. Then `LB` is handled in the same manner as the
source block in the case of forward jumps.
This produces CFG that looks like this:
```
SB -> LB (T: goto) -> DB
```
Finally, the resulting block is linked as the successor of `SB`. Such an
approach uses existing handling of the `noreturn` destructors.
As a reminder, for each destructor of an automatic object that is
marked as `noreturn`, a new `noreturn` block (marked `NBn`) is
created, at the destructor is inserted at the end of it.
To illustrate, given two `noreturn` destructors, we will have:
```
SB -> NB1 (noreturn)
NB2 (noreturn)
LB (T:goto) -> DB
```
Reviewed By: ymandel, steakhal
Differential Revision: https://reviews.llvm.org/D153273