Skip to content

Commit 199140a

Browse files
vtjnashgiordano
authored andcommitted
[analyzer] Do not destruct fields of unions (llvm#122330)
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 llvm#119415 (cherry picked from commit 9b8297b)
1 parent f54f5f7 commit 199140a

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

clang/lib/Analysis/CFG.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2034,6 +2034,8 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
20342034
}
20352035

20362036
// First destroy member objects.
2037+
if (RD->isUnion())
2038+
return;
20372039
for (auto *FI : RD->fields()) {
20382040
// Check for constant size array. Set type to array element type.
20392041
QualType QT = FI->getType();

clang/test/Analysis/NewDelete-checker-test.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,3 +458,31 @@ void testLeakBecauseNTTPIsNotDeallocation() {
458458
void* p = ::operator new(10);
459459
deallocate_via_nttp<not_free>(p);
460460
} // leak-warning{{Potential leak of memory pointed to by 'p'}}
461+
462+
namespace optional_union {
463+
template <typename T>
464+
class unique_ptr {
465+
T *q;
466+
public:
467+
unique_ptr() : q(new T) {}
468+
~unique_ptr() {
469+
delete q;
470+
}
471+
};
472+
473+
union custom_union_t {
474+
unique_ptr<int> present;
475+
char notpresent;
476+
custom_union_t() : present(unique_ptr<int>()) {}
477+
~custom_union_t() {}
478+
};
479+
480+
void testUnionCorrect() {
481+
custom_union_t a;
482+
a.present.~unique_ptr<int>();
483+
}
484+
485+
void testUnionLeak() {
486+
custom_union_t a;
487+
} // leak-warning{{Potential leak of memory pointed to by 'a.present.q'}}
488+
}

clang/test/Analysis/dtor-union.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=destructors -verify -std=c++11 %s
2+
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=destructors -verify -std=c++17 %s
3+
4+
void clang_analyzer_eval(bool);
5+
6+
struct InlineDtor {
7+
static int cnt;
8+
static int dtorCalled;
9+
~InlineDtor() {
10+
++dtorCalled;
11+
}
12+
};
13+
14+
int InlineDtor::cnt = 0;
15+
int InlineDtor::dtorCalled = 0;
16+
17+
void testUnionDtor() {
18+
static int unionDtorCalled;
19+
InlineDtor::cnt = 0;
20+
InlineDtor::dtorCalled = 0;
21+
unionDtorCalled = 0;
22+
{
23+
union UnionDtor {
24+
InlineDtor kind1;
25+
char kind2;
26+
~UnionDtor() { unionDtorCalled++; }
27+
};
28+
UnionDtor u1{.kind1{}};
29+
UnionDtor u2{.kind2{}};
30+
auto u3 = new UnionDtor{.kind1{}};
31+
auto u4 = new UnionDtor{.kind2{}};
32+
delete u3;
33+
delete u4;
34+
}
35+
36+
clang_analyzer_eval(unionDtorCalled == 4); // expected-warning {{TRUE}}
37+
clang_analyzer_eval(InlineDtor::dtorCalled == 0); // expected-warning {{TRUE}}
38+
}

0 commit comments

Comments
 (0)