Index: include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- include/clang/StaticAnalyzer/Checkers/Checkers.td +++ include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -272,6 +272,10 @@ HelpText<"Checks C++ copy and move assignment operators for self assignment">, DescFile<"CXXSelfAssignmentChecker.cpp">; +def StdInitializerListChecker : Checker<"StdInitializerList">, + HelpText<"Models std::initializer_list API.">, + DescFile<"StdInitializerListChecker.cpp">; + } // end: "cplusplus" let ParentPackage = CplusplusOptIn in { Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt =================================================================== --- lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -76,6 +76,7 @@ SimpleStreamChecker.cpp StackAddrEscapeChecker.cpp StdLibraryFunctionsChecker.cpp + StdInitializerListChecker.cpp StreamChecker.cpp TaintTesterChecker.cpp TestAfterDivZeroChecker.cpp Index: lib/StaticAnalyzer/Checkers/StdInitializerListChecker.cpp =================================================================== --- /dev/null +++ lib/StaticAnalyzer/Checkers/StdInitializerListChecker.cpp @@ -0,0 +1,53 @@ +//===-- StdInitializerListChecker.cpp -----------------------------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines a checker that models the API of C++11 std::initializer_list class. +// It doesn't emit warnings, at least for now. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/AST/ExprCXX.h" + +using namespace clang; +using namespace ento; + +namespace { +class StdInitializerListChecker + : public Checker> { +public: + void checkPostStmt(const CXXStdInitializerListExpr *S, + CheckerContext &C) const; +}; +} // end anonymous namespace + +void StdInitializerListChecker::checkPostStmt( + const CXXStdInitializerListExpr *S, CheckerContext &C) const { + QualType ElementType = + QualType(S->getSubExpr()->getType()->getArrayElementTypeNoTypeQual(), 0); + + nonloc::LazyCompoundVal V = C.getSVal(S).castAs(); + const MemRegion *R = V.getRegion(); + + const LocationContext *LCtx = C.getLocationContext(); + SymbolRef Sym = C.getSymbolManager().getMetadataSymbol( + R, S, ElementType, LCtx, C.blockCount(), this); + Loc MetaLoc = loc::MemRegionVal( + C.getSValBuilder().getRegionManager().getSymbolicRegion(Sym)); + + SVal ListData = C.getSVal(S->getSubExpr()); + C.addTransition(C.getState()->bindLoc(MetaLoc, ListData, LCtx, true)); +} + +void ento::registerStdInitializerListChecker(CheckerManager &mgr) { + mgr.registerChecker(); +} Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1074,12 +1074,19 @@ for (ExplodedNodeSet::iterator it = preVisit.begin(), et = preVisit.end(); it != et; ++it) { ExplodedNode *N = *it; + ProgramStateRef State = N->getState(); const LocationContext *LCtx = N->getLocationContext(); - SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, - resultType, - currBldrCtx->blockCount()); - ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result); - Bldr2.generateNode(S, N, state); + SVal Result; + if (isa(Ex)) { + const MemRegion *InitListRegion = + svalBuilder.getRegionManager().getCXXStaticTempObjectRegion(Ex); + Result = State->getSVal(InitListRegion); + } else { + Result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, resultType, + currBldrCtx->blockCount()); + } + State = State->BindExpr(Ex, LCtx, Result); + Bldr2.generateNode(S, N, State); } getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); @@ -2232,7 +2239,7 @@ // same state. SVal StoredVal = State->getSVal(regionLoc->getRegion()); if (StoredVal != Val) - escapes = (State == (State->bindLoc(*regionLoc, Val, LCtx))); + escapes = (State == (State->bindLoc(*regionLoc, Val, LCtx, false))); } } Index: lib/StaticAnalyzer/Core/ProgramState.cpp =================================================================== --- lib/StaticAnalyzer/Core/ProgramState.cpp +++ lib/StaticAnalyzer/Core/ProgramState.cpp @@ -116,13 +116,18 @@ const LocationContext *LCtx, bool notifyChanges) const { ProgramStateManager &Mgr = getStateManager(); - ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(), - LV, V)); + ProgramStateRef NewState = + makeWithStore(Mgr.StoreMgr->Bind(getStore(), LV, V)); const MemRegion *MR = LV.getAsRegion(); - if (MR && Mgr.getOwningEngine() && notifyChanges) - return Mgr.getOwningEngine()->processRegionChange(newState, MR, LCtx); + if (MR && Mgr.getOwningEngine() && notifyChanges) { + NewState = Mgr.getOwningEngine()->processRegionChange(NewState, MR, LCtx); + if (!NewState) + return nullptr; + return Mgr.getOwningEngine()->processPointerEscapedOnBind(NewState, LV, V, + LCtx); + } - return newState; + return NewState; } ProgramStateRef ProgramState::bindDefault(SVal loc, Index: test/Analysis/initializer.cpp =================================================================== --- test/Analysis/initializer.cpp +++ test/Analysis/initializer.cpp @@ -1,7 +1,9 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDeleteLeaks,cplusplus.StdInitializerList,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s void clang_analyzer_eval(bool); +#include "Inputs/system-header-simulator-cxx.h" + class A { int x; public: @@ -204,3 +206,13 @@ const char(&f)[2]; }; } + +namespace CXX_initializer_lists { +struct C { + C(std::initializer_list list); +}; +void foo() { + int *x = new int; + C c{x}; // no-warning +} +} Index: test/Analysis/temporaries-callback-order.cpp =================================================================== --- test/Analysis/temporaries-callback-order.cpp +++ test/Analysis/temporaries-callback-order.cpp @@ -18,14 +18,12 @@ void seeIfCheckBindWorks() { // This should trigger checkBind. The rest of the code shouldn't. - // This also triggers checkRegionChanges after that. // Note that this function is analyzed first, so the messages would be on top. int x = 1; } // seeIfCheckBindWorks(): // CHECK: Bind -// CHECK-NEXT: RegionChanges // testTemporaries(): // CHECK-NEXT: RegionChanges