Skip to content

Commit 4e6f2ce

Browse files
committed
[StaticAnalyzer] Make it a noop when initializing a field of empty record.
Previously, Static Analyzer initializes empty type fields with zeroes. This can cause problems when those fields have no unique addresses. For example, #137252. rdar://146753089
1 parent c0a264e commit 4e6f2ce

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "clang/AST/ASTContext.h"
1314
#include "clang/AST/AttrIterator.h"
1415
#include "clang/AST/DeclCXX.h"
1516
#include "clang/AST/ParentMap.h"
@@ -700,6 +701,7 @@ void ExprEngine::handleConstructor(const Expr *E,
700701
if (CE) {
701702
// FIXME: Is it possible and/or useful to do this before PreStmt?
702703
StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx);
704+
ASTContext &Ctx = LCtx->getAnalysisDeclContext()->getASTContext();
703705
for (ExplodedNode *N : DstPreVisit) {
704706
ProgramStateRef State = N->getState();
705707
if (CE->requiresZeroInitialization()) {
@@ -715,7 +717,11 @@ void ExprEngine::handleConstructor(const Expr *E,
715717
// actually make things worse. Placement new makes this tricky as well,
716718
// since it's then possible to be initializing one part of a multi-
717719
// dimensional array.
718-
State = State->bindDefaultZero(Target, LCtx);
720+
const CXXRecordDecl *TargetHeldRecord =
721+
Target.getType(Ctx)->getPointeeCXXRecordDecl();
722+
723+
if (!TargetHeldRecord || !TargetHeldRecord->isEmpty())
724+
State = State->bindDefaultZero(Target, LCtx);
719725
}
720726

721727
Bldr.generateNode(CE, N, State, /*tag=*/nullptr,
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus -verify %s
2+
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus -verify %s -DEMPTY_CLASS
3+
4+
// expected-no-diagnostics
5+
6+
// This test reproduces the issue that previously the static analyzer
7+
// initialized an [[__no_unique_address__]] empty field to zero,
8+
// over-writing a non-empty field with the same offset.
9+
10+
namespace std {
11+
#ifdef EMPTY_CLASS
12+
13+
template <typename T>
14+
class default_delete {
15+
T dump();
16+
static T x;
17+
};
18+
template <class _Tp, class _Dp = default_delete<_Tp> >
19+
#else
20+
21+
struct default_delete {};
22+
template <class _Tp, class _Dp = default_delete >
23+
#endif
24+
class unique_ptr {
25+
[[__no_unique_address__]] _Tp * __ptr_;
26+
[[__no_unique_address__]] _Dp __deleter_;
27+
28+
public:
29+
explicit unique_ptr(_Tp* __p) noexcept
30+
: __ptr_(__p),
31+
__deleter_() {}
32+
33+
~unique_ptr() {
34+
delete __ptr_;
35+
}
36+
};
37+
}
38+
39+
struct X {};
40+
41+
int main()
42+
{
43+
std::unique_ptr<X> a(new X()); // previously leak falsely reported
44+
return 0;
45+
}

0 commit comments

Comments
 (0)