Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit be35df1

Browse files
committed
[analyzer] Handle zeroing CXXConstructExprs.
Re-apply r184511, reverted in r184561, with the trivial default constructor fast path removed -- it turned out not to be necessary here. Certain expressions can cause a constructor invocation to zero-initialize its object even if the constructor itself does no initialization. The analyzer now handles that before evaluating the call to the constructor, using the same "default binding" mechanism that calloc() uses, rather than simply ignoring the zero-initialization flag. <rdar://problem/14212563> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184815 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 1fc9111 commit be35df1

File tree

2 files changed

+123
-1
lines changed

2 files changed

+123
-1
lines changed

Diff for: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp

+32-1
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
176176
}
177177

178178
// FIXME: This will eventually need to handle new-expressions as well.
179+
// Don't forget to update the pre-constructor initialization code below.
179180
}
180181

181182
// If we couldn't find an existing region to construct into, assume we're
@@ -233,8 +234,38 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
233234

234235
ExplodedNodeSet DstPreVisit;
235236
getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this);
237+
238+
ExplodedNodeSet PreInitialized;
239+
{
240+
StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx);
241+
if (CE->requiresZeroInitialization()) {
242+
// Type of the zero doesn't matter.
243+
SVal ZeroVal = svalBuilder.makeZeroVal(getContext().CharTy);
244+
245+
for (ExplodedNodeSet::iterator I = DstPreVisit.begin(),
246+
E = DstPreVisit.end();
247+
I != E; ++I) {
248+
ProgramStateRef State = (*I)->getState();
249+
// FIXME: Once we properly handle constructors in new-expressions, we'll
250+
// need to invalidate the region before setting a default value, to make
251+
// sure there aren't any lingering bindings around. This probably needs
252+
// to happen regardless of whether or not the object is zero-initialized
253+
// to handle random fields of a placement-initialized object picking up
254+
// old bindings. We might only want to do it when we need to, though.
255+
// FIXME: This isn't actually correct for arrays -- we need to zero-
256+
// initialize the entire array, not just the first element -- but our
257+
// handling of arrays everywhere else is weak as well, so this shouldn't
258+
// actually make things worse. Placement new makes this tricky as well,
259+
// since it's then possible to be initializing one part of a multi-
260+
// dimensional array.
261+
State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal);
262+
Bldr.generateNode(CE, *I, State, /*tag=*/0, ProgramPoint::PreStmtKind);
263+
}
264+
}
265+
}
266+
236267
ExplodedNodeSet DstPreCall;
237-
getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit,
268+
getCheckerManager().runCheckersForPreCall(DstPreCall, PreInitialized,
238269
*Call, *this);
239270

240271
ExplodedNodeSet DstEvaluated;

Diff for: test/Analysis/ctor-inlining.mm renamed to test/Analysis/ctor.mm

+91
Original file line numberDiff line numberDiff line change
@@ -534,3 +534,94 @@ void testVirtual() {
534534
clang_analyzer_eval(counter == 1); // expected-warning{{TRUE}}
535535
}
536536
}
537+
538+
namespace ZeroInitialization {
539+
struct raw_pair {
540+
int p1;
541+
int p2;
542+
};
543+
544+
void testVarDecl() {
545+
raw_pair p{};
546+
clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}}
547+
clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}}
548+
}
549+
550+
void testTemporary() {
551+
clang_analyzer_eval(raw_pair().p1 == 0); // expected-warning{{TRUE}}
552+
clang_analyzer_eval(raw_pair().p2 == 0); // expected-warning{{TRUE}}
553+
}
554+
555+
void testArray() {
556+
raw_pair p[2] = {};
557+
clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{TRUE}}
558+
clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{TRUE}}
559+
clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{TRUE}}
560+
clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{TRUE}}
561+
}
562+
563+
void testNew() {
564+
// FIXME: Pending proper implementation of constructors for 'new'.
565+
raw_pair *pp = new raw_pair();
566+
clang_analyzer_eval(pp->p1 == 0); // expected-warning{{UNKNOWN}}
567+
clang_analyzer_eval(pp->p2 == 0); // expected-warning{{UNKNOWN}}
568+
}
569+
570+
void testArrayNew() {
571+
// FIXME: Pending proper implementation of constructors for 'new[]'.
572+
raw_pair *p = new raw_pair[2]();
573+
clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{UNKNOWN}}
574+
clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{UNKNOWN}}
575+
clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{UNKNOWN}}
576+
clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{UNKNOWN}}
577+
}
578+
579+
struct initializing_pair {
580+
public:
581+
int x;
582+
raw_pair y;
583+
initializing_pair() : x(), y() {}
584+
};
585+
586+
void testFieldInitializers() {
587+
initializing_pair p;
588+
clang_analyzer_eval(p.x == 0); // expected-warning{{TRUE}}
589+
clang_analyzer_eval(p.y.p1 == 0); // expected-warning{{TRUE}}
590+
clang_analyzer_eval(p.y.p2 == 0); // expected-warning{{TRUE}}
591+
}
592+
593+
struct subclass : public raw_pair {
594+
subclass() = default;
595+
};
596+
597+
void testSubclass() {
598+
subclass p;
599+
clang_analyzer_eval(p.p1 == 0); // expected-warning{{garbage}}
600+
}
601+
602+
struct initializing_subclass : public raw_pair {
603+
initializing_subclass() : raw_pair() {}
604+
};
605+
606+
void testInitializingSubclass() {
607+
initializing_subclass p;
608+
clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}}
609+
clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}}
610+
}
611+
612+
struct pair_wrapper {
613+
pair_wrapper() : p() {}
614+
raw_pair p;
615+
};
616+
617+
struct virtual_subclass : public virtual pair_wrapper {
618+
virtual_subclass() {}
619+
};
620+
621+
struct double_virtual_subclass : public virtual_subclass {
622+
double_virtual_subclass() {
623+
// This previously caused a crash because the pair_wrapper subobject was
624+
// initialized twice.
625+
}
626+
};
627+
}

0 commit comments

Comments
 (0)