NoQ updated this revision to Diff 105897.
NoQ edited the summary of this revision.
NoQ added a comment.
Herald added a subscriber: mgorny.
This other diff implements approach (1) through a draft of a checker (that
doesn't model much yet). I had to additionally make sure we already have a
region to construct metadata for, in spirit of https://reviews.llvm.org/D27202.
For easier comparison, i thought it'd be better to stick it to the same
differential revision.
https://reviews.llvm.org/D35216
Files:
include/clang/StaticAnalyzer/Checkers/Checkers.td
lib/StaticAnalyzer/Checkers/CMakeLists.txt
lib/StaticAnalyzer/Checkers/StdInitializerListChecker.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
lib/StaticAnalyzer/Core/ProgramState.cpp
test/Analysis/initializer.cpp
test/Analysis/temporaries-callback-order.cpp
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
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<int *> list);
+};
+void foo() {
+ int *x = new int;
+ C c{x}; // no-warning
+}
+}
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: 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<CXXStdInitializerListExpr>(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/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<check::PostStmt<CXXStdInitializerListExpr>> {
+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<nonloc::LazyCompoundVal>();
+ 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<StdInitializerListChecker>();
+}
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: 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 {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits