Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -659,8 +659,10 @@ /// Store the region returned by operator new() so that the constructor /// that follows it knew what location to initialize. The value should be /// cleared once the respective CXXNewExpr CFGStmt element is processed. + /// \p T is the type of the newly allocated object, which is not necessarily + /// obvious from \p V because the return type of operator new is void *. ProgramStateRef pushCXXNewAllocatorValue(ProgramStateRef State, - SVal V); + SVal V, QualType T); /// Retrieve the location returned by the current operator new(). SVal peekCXXNewAllocatorValue(ProgramStateRef State); Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -314,7 +314,12 @@ } ProgramStateRef ExprEngine::pushCXXNewAllocatorValue(ProgramStateRef State, - SVal V) { + SVal V, QualType T) { + // Because operator new returns void *, we need to perform the cast here, + // which is implied by the semantics of operator new. + V = svalBuilder.evalCast(V, T, + getContext().getPointerType(getContext().VoidTy)); + return State->add(V); } Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -463,7 +463,8 @@ for (auto I : DstPostCall) { ProgramStateRef State = I->getState(); ValueBldr.generateNode( - CNE, I, pushCXXNewAllocatorValue(State, State->getSVal(CNE, LCtx))); + CNE, I, pushCXXNewAllocatorValue(State, State->getSVal(CNE, LCtx), + CNE->getType())); } getCheckerManager().runCheckersForPostCall(Dst, DstPostValue, Index: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -277,11 +277,12 @@ state = state->BindExpr(CCE, callerCtx, ThisV); } - if (isa(CE)) { + if (const auto *CNE = dyn_cast(CE)) { // We are currently evaluating a CXXNewAllocator CFGElement. It takes a // while to reach the actual CXXNewExpr element from here, so keep the // region for later use. - state = pushCXXNewAllocatorValue(state, state->getSVal(CE, callerCtx)); + state = pushCXXNewAllocatorValue(state, state->getSVal(CE, callerCtx), + CNE->getType()); } } Index: test/Analysis/new-ctor-conservative.cpp =================================================================== --- test/Analysis/new-ctor-conservative.cpp +++ test/Analysis/new-ctor-conservative.cpp @@ -12,3 +12,12 @@ S *s = new S; clang_analyzer_eval(s->x == 1); // expected-warning{{TRUE}} } + +void checkNewPOD() { + int *i = new int; + clang_analyzer_eval(*i == 0); // expected-warning{{UNKNOWN}} + int *j = new int(); + clang_analyzer_eval(*j == 0); // expected-warning{{TRUE}} + int *k = new int(5); + clang_analyzer_eval(*k == 5); // expected-warning{{TRUE}} +} Index: test/Analysis/new-ctor-inlined.cpp =================================================================== --- test/Analysis/new-ctor-inlined.cpp +++ test/Analysis/new-ctor-inlined.cpp @@ -27,3 +27,18 @@ // Check that bindings are correct (and also not dying). clang_analyzer_eval(s->x == 1); // expected-warning{{TRUE}} } + +void checkNewPOD() { + int *i = new int; + clang_analyzer_eval(*i == 0); // expected-warning{{UNKNOWN}} + int *j = new int(); + clang_analyzer_eval(*j == 0); // expected-warning{{TRUE}} + int *k = new int(5); + clang_analyzer_eval(*k == 5); // expected-warning{{TRUE}} +} + +void checkTrivialCopy() { + S s; + S *t = new S(s); // no-crash + clang_analyzer_eval(t->x == 1); // expected-warning{{TRUE}} +}