Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "clang/AST/ASTContext.h"
#include "clang/AST/AttrIterator.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ParentMap.h"
Expand Down Expand Up @@ -700,6 +701,7 @@ void ExprEngine::handleConstructor(const Expr *E,
if (CE) {
// FIXME: Is it possible and/or useful to do this before PreStmt?
StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx);
ASTContext &Ctx = LCtx->getAnalysisDeclContext()->getASTContext();
for (ExplodedNode *N : DstPreVisit) {
ProgramStateRef State = N->getState();
if (CE->requiresZeroInitialization()) {
Expand All @@ -715,7 +717,11 @@ void ExprEngine::handleConstructor(const Expr *E,
// actually make things worse. Placement new makes this tricky as well,
// since it's then possible to be initializing one part of a multi-
// dimensional array.
State = State->bindDefaultZero(Target, LCtx);
const CXXRecordDecl *TargetHeldRecord =
Target.getType(Ctx)->getPointeeCXXRecordDecl();

if (!TargetHeldRecord || !TargetHeldRecord->isEmpty())
State = State->bindDefaultZero(Target, LCtx);
}

Bldr.generateNode(CE, N, State, /*tag=*/nullptr,
Expand Down
45 changes: 45 additions & 0 deletions clang/test/Analysis/issue-137252.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus -verify %s -DEMPTY_CLASS

// expected-no-diagnostics

// This test reproduces the issue that previously the static analyzer
// initialized an [[__no_unique_address__]] empty field to zero,
// over-writing a non-empty field with the same offset.

namespace std {
#ifdef EMPTY_CLASS

template <typename T>
class default_delete {
T dump();
static T x;
};
template <class _Tp, class _Dp = default_delete<_Tp> >
#else

struct default_delete {};
template <class _Tp, class _Dp = default_delete >
#endif
class unique_ptr {
[[__no_unique_address__]] _Tp * __ptr_;
[[__no_unique_address__]] _Dp __deleter_;

public:
explicit unique_ptr(_Tp* __p) noexcept
: __ptr_(__p),
__deleter_() {}

~unique_ptr() {
delete __ptr_;
}
};
}

struct X {};

int main()
{
std::unique_ptr<X> a(new X()); // previously leak falsely reported
return 0;
}
Loading