baloghadamsoftware updated this revision to Diff 243796.
baloghadamsoftware added a comment.
First real checker `IteratorRange` now marks container as interesting to
benefit from container note tags. The other two iterator checkers will be
updated after a second phase of container note tags which also cares for
reassignment (upon move) and invalidation of iterators.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D73720/new/
https://reviews.llvm.org/D73720
Files:
clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
clang/test/Analysis/container-modeling.cpp
clang/test/Analysis/iterator-range.cpp
Index: clang/test/Analysis/iterator-range.cpp
===================================================================
--- clang/test/Analysis/iterator-range.cpp
+++ clang/test/Analysis/iterator-range.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -analyzer-output=text %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -analyzer-output=text %s -verify
#include "Inputs/system-header-simulator-cxx.h"
@@ -32,6 +32,7 @@
void deref_end(const std::vector<int> &V) {
auto i = V.end();
*i; // expected-warning{{Past-the-end iterator dereferenced}}
+ // expected-note@-1{{Past-the-end iterator dereferenced}}
}
// Prefix increment - operator++()
@@ -59,6 +60,7 @@
void incr_end(const std::vector<int> &V) {
auto i = V.end();
++i; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
+ // expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
}
// Postfix increment - operator++(int)
@@ -86,6 +88,7 @@
void end_incr(const std::vector<int> &V) {
auto i = V.end();
i++; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
+ // expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
}
// Prefix decrement - operator--()
@@ -93,6 +96,7 @@
void decr_begin(const std::vector<int> &V) {
auto i = V.begin();
--i; // expected-warning{{Iterator decremented ahead of its valid range}}
+ // expected-note@-1{{Iterator decremented ahead of its valid range}}
}
void decr_behind_begin(const std::vector<int> &V) {
@@ -120,6 +124,7 @@
void begin_decr(const std::vector<int> &V) {
auto i = V.begin();
i--; // expected-warning{{Iterator decremented ahead of its valid range}}
+ // expected-note@-1{{Iterator decremented ahead of its valid range}}
}
void behind_begin_decr(const std::vector<int> &V) {
@@ -168,11 +173,13 @@
void incr_by_2_ahead_of_end(const std::vector<int> &V) {
auto i = --V.end();
i += 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
+ // expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
}
void incr_by_2_end(const std::vector<int> &V) {
auto i = V.end();
i += 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
+ // expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
}
// Addition - operator+(int)
@@ -201,11 +208,13 @@
void incr_by_2_copy_ahead_of_end(const std::vector<int> &V) {
auto i = --V.end();
auto j = i + 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
+ // expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
}
void incr_by_2_copy_end(const std::vector<int> &V) {
auto i = V.end();
auto j = i + 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}}
+ // expected-note@-1{{Iterator incremented behind the past-the-end iterator}}
}
// Subtraction assignment - operator-=(int)
@@ -213,11 +222,13 @@
void decr_by_2_begin(const std::vector<int> &V) {
auto i = V.begin();
i -= 2; // expected-warning{{Iterator decremented ahead of its valid range}}
+ // expected-note@-1{{Iterator decremented ahead of its valid range}}
}
void decr_by_2_behind_begin(const std::vector<int> &V) {
auto i = ++V.begin();
i -= 2; // expected-warning{{Iterator decremented ahead of its valid range}}
+ // expected-note@-1{{Iterator decremented ahead of its valid range}}
}
void decr_by_2_behind_begin_by_2(const std::vector<int> &V) {
@@ -246,11 +257,13 @@
void decr_by_2_copy_begin(const std::vector<int> &V) {
auto i = V.begin();
auto j = i - 2; // expected-warning{{Iterator decremented ahead of its valid range}}
+ // expected-note@-1{{Iterator decremented ahead of its valid range}}
}
void decr_by_2_copy_behind_begin(const std::vector<int> &V) {
auto i = ++V.begin();
auto j = i - 2; // expected-warning{{Iterator decremented ahead of its valid range}}
+ // expected-note@-1{{Iterator decremented ahead of its valid range}}
}
void decr_by_2_copy_behind_begin_by_2(const std::vector<int> &V) {
@@ -303,6 +316,7 @@
void subscript_zero_end(const std::vector<int> &V) {
auto i = V.end();
auto j = i[0]; // expected-warning{{Past-the-end iterator dereferenced}}
+ // expected-note@-1{{Past-the-end iterator dereferenced}}
}
// By negative number
@@ -329,7 +343,8 @@
void subscript_negative_end(const std::vector<int> &V) {
auto i = V.end();
- auto j = i[-1]; // // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect no warning
+ auto j = i[-1]; // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect no warning
+ // expected-note@-1{{Past-the-end iterator dereferenced}}
}
// By positive number
@@ -357,6 +372,7 @@
void subscript_positive_end(const std::vector<int> &V) {
auto i = V.end();
auto j = i[1]; // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect warning Iterator incremented behind the past-the-end iterator
+ // expected-note@-1{{Past-the-end iterator dereferenced}} FIXME: expect note@-1 Iterator incremented behind the past-the-end iterator
}
//
@@ -376,5 +392,17 @@
void arrow_deref_end(const std::vector<S> &V) {
auto i = V.end();
- int n = i->n; // expected-warning{{Past-the-end iterator dereferenced}}
+ int n = i->n; // expected-warning{{Past-the-end iterator dereferenced}}
+ // expected-note@-1{{Past-the-end iterator dereferenced}}
+}
+
+// Container modification - test path notes
+
+void deref_end_after_pop_back(std::vector<int> &V) {
+ const auto i = --V.end();
+
+ V.pop_back(); // expected-note{{Container 'V' shrinked from the right by 1 position}}
+
+ *i; // expected-warning{{Past-the-end iterator dereferenced}}
+ // expected-note@-1{{Past-the-end iterator dereferenced}}
}
Index: clang/test/Analysis/container-modeling.cpp
===================================================================
--- clang/test/Analysis/container-modeling.cpp
+++ clang/test/Analysis/container-modeling.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -analyzer-output=text -verify
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -analyzer-output=text -verify
// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true %s 2>&1 | FileCheck %s
@@ -20,14 +20,16 @@
V.begin();
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
- clang_analyzer_express(clang_analyzer_container_begin(V)); //expected-warning{{$V.begin()}}
+ clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}}
+ // expected-note@-1{{$V.begin()}}
}
void end(const std::vector<int> &V) {
V.end();
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
- clang_analyzer_express(clang_analyzer_container_end(V)); //expected-warning{{$V.end()}}
+ clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end()}}
+ // expected-note@-1{{$V.end()}}
}
////////////////////////////////////////////////////////////////////////////////
@@ -48,8 +50,10 @@
long B2 = clang_analyzer_container_begin(V2);
long E2 = clang_analyzer_container_end(V2);
V1 = std::move(V2);
- clang_analyzer_eval(clang_analyzer_container_begin(V1) == B2); //expected-warning{{TRUE}}
- clang_analyzer_eval(clang_analyzer_container_end(V2) == E2); //expected-warning{{TRUE}}
+ clang_analyzer_eval(clang_analyzer_container_begin(V1) == B2); // expected-warning{{TRUE}}
+ // expected-note@-1{{TRUE}}
+ clang_analyzer_eval(clang_analyzer_container_end(V2) == E2); // expected-warning{{TRUE}}
+ // expected-note@-1{{TRUE}}
}
////////////////////////////////////////////////////////////////////////////////
@@ -63,6 +67,8 @@
/// Design decision: extends containers to the ->RIGHT-> (i.e. the
/// past-the-end position of the container is incremented).
+void clang_analyzer_dump(void*);
+
void push_back(std::vector<int> &V, int n) {
V.cbegin();
V.cend();
@@ -70,10 +76,13 @@
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
- V.push_back(n);
+ V.push_back(n); // expected-note{{Container 'V' extended to the right by 1 position}}
+ // expected-note@-1{{Container 'V' extended to the right by 1 position}}
clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}}
+ // expected-note@-1{{$V.begin()}}
clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}}
+ // expected-note@-1{{$V.end() + 1}}
}
/// emplace_back()
@@ -88,10 +97,14 @@
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
- V.emplace_back(n);
+ V.emplace_back(n); // expected-note{{Container 'V' extended to the right by 1 position}}
+ // expected-note@-1{{Container 'V' extended to the right by 1 position}}
+
clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}}
+ // expected-note@-1{{$V.begin()}}
clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}}
+ // expected-note@-1{{$V.end() + 1}}
}
/// pop_back()
@@ -106,10 +119,14 @@
clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()");
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
- V.pop_back();
+ V.pop_back(); // expected-note{{Container 'V' shrinked from the right by 1 position}}
+ // expected-note@-1{{Container 'V' shrinked from the right by 1 position}}
+
clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}}
+ // expected-note@-1{{$V.begin()}}
clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() - 1}}
+ // expected-note@-1{{$V.end() - 1}}
}
/// push_front()
@@ -117,17 +134,20 @@
/// Design decision: extends containers to the <-LEFT<- (i.e. the first
/// position of the container is decremented).
-void push_front(std::deque<int> &D, int n) {
- D.cbegin();
- D.cend();
+void push_front(std::list<int> &L, int n) {
+ L.cbegin();
+ L.cend();
- clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()");
- clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()");
+ clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()");
+ clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()");
- D.push_front(n);
+ L.push_front(n); // expected-note{{Container 'L' extended to the left by 1 position}}
+ // expected-note@-1{{Container 'L' extended to the left by 1 position}}
- clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() - 1 (to correctly track the container's size)
- clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}}
+ clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}}
+ // expected-note@-1{{$L.begin() - 1}}
+ clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}}
+ // expected-note@-1{{$L.end()}}
}
/// emplace_front()
@@ -135,17 +155,20 @@
/// Design decision: extends containers to the <-LEFT<- (i.e. the first
/// position of the container is decremented).
-void deque_emplace_front(std::deque<int> &D, int n) {
- D.cbegin();
- D.cend();
+void emplace_front(std::list<int> &L, int n) {
+ L.cbegin();
+ L.cend();
- clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()");
- clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()");
+ clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()");
+ clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()");
- D.emplace_front(n);
+ L.emplace_front(n); // expected-note{{Container 'L' extended to the left by 1 position}}
+ // expected-note@-1{{Container 'L' extended to the left by 1 position}}
- clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin - 1 (to correctly track the container's size)
- clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}}
+ clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}}
+ // expected-note@-1{{$L.begin() - 1}}
+ clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}}
+ // expected-note@-1{{$L.end()}}
}
/// pop_front()
@@ -153,19 +176,49 @@
/// Design decision: shrinks containers to the ->RIGHT-> (i.e. the first
/// position of the container is incremented).
-void deque_pop_front(std::deque<int> &D, int n) {
- D.cbegin();
- D.cend();
+void pop_front(std::list<int> &L, int n) {
+ L.cbegin();
+ L.cend();
+
+ clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()");
+ clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()");
+
+ L.pop_front(); // expected-note{{Container 'L' shrinked from the left by 1 position}}
+ // expected-note@-1{{Container 'L' shrinked from the left by 1 position}}
+
+ clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() + 1}}
+ // expected-note@-1{{$L.begin() + 1}}
+ clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}}
+ // expected-note@-1{{$L.end()}}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// O T H E R T E S T S
+///
+////////////////////////////////////////////////////////////////////////////////
+
+/// Track the right container only
+
+void push_back(std::vector<int> &V1, std::vector<int> &V2, int n) {
+ V1.cbegin();
+ V1.cend();
+ V2.cbegin();
+ V2.cend();
- clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()");
- clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()");
+ clang_analyzer_denote(clang_analyzer_container_begin(V1), "$V1.begin()");
+ clang_analyzer_denote(clang_analyzer_container_end(V1), "$V1.end()");
- D.pop_front();
+ V2.push_back(n); // no note expected
- clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin() + 1}}
- clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}}
+ clang_analyzer_express(clang_analyzer_container_begin(V1)); // expected-warning{{$V1.begin()}}
+ // expected-note@-1{{$V1.begin()}}
+ clang_analyzer_express(clang_analyzer_container_end(V1)); // expected-warning{{$V1.end()}}
+ // expected-note@-1{{$V1.end()}}
}
+/// Print Container Data as Part of the Program State
+
void clang_analyzer_printState();
void print_state(std::vector<int> &V) {
Index: clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
@@ -185,7 +185,12 @@
ExplodedNode *ErrNode) const {
auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
ErrNode);
+
+ const auto *Pos = getIteratorPosition(C.getState(), Val);
+ assert(Pos && "Iterator without known position cannot be out-of-range.");
+
R->markInteresting(Val);
+ R->markInteresting(Pos->getContainer());
C.emitReport(std::move(R));
}
Index: clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
@@ -92,7 +92,15 @@
if (Field) {
State = State->BindExpr(CE, C.getLocationContext(),
nonloc::SymbolVal(Field));
- C.addTransition(State);
+ const NoteTag *InterestingTag =
+ C.getNoteTag([Cont](BugReport &BR) -> std::string {
+ auto *PSBR = dyn_cast<PathSensitiveBugReport>(&BR);
+ if (PSBR) {
+ PSBR->markInteresting(Cont);
+ }
+ return "";
+ });
+ C.addTransition(State, InterestingTag);
return;
}
}
Index: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -31,47 +31,43 @@
class ContainerModeling
: public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> {
- void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal,
- const SVal &Cont) const;
- void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal,
- const SVal &Cont) const;
- void handleAssignment(CheckerContext &C, const SVal &Cont,
- const Expr *CE = nullptr,
- const SVal &OldCont = UndefinedVal()) const;
- void handleAssign(CheckerContext &C, const SVal &Cont) const;
- void handleClear(CheckerContext &C, const SVal &Cont) const;
- void handlePushBack(CheckerContext &C, const SVal &Cont) const;
- void handlePopBack(CheckerContext &C, const SVal &Cont) const;
- void handlePushFront(CheckerContext &C, const SVal &Cont) const;
- void handlePopFront(CheckerContext &C, const SVal &Cont) const;
- void handleInsert(CheckerContext &C, const SVal &Cont,
- const SVal &Iter) const;
- void handleErase(CheckerContext &C, const SVal &Cont, const SVal &Iter) const;
- void handleErase(CheckerContext &C, const SVal &Cont, const SVal &Iter1,
- const SVal &Iter2) const;
- void handleEraseAfter(CheckerContext &C, const SVal &Cont,
- const SVal &Iter) const;
- void handleEraseAfter(CheckerContext &C, const SVal &Cont, const SVal &Iter1,
- const SVal &Iter2) const;
+ void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal,
+ SVal Cont) const;
+ void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal,
+ SVal Cont) const;
+ void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr,
+ SVal OldCont = UndefinedVal()) const;
+ void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const;
+ void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const;
+ void handlePushBack(CheckerContext &C, SVal Cont, const Expr *ContE) const;
+ void handlePopBack(CheckerContext &C, SVal Cont, const Expr *ContE) const;
+ void handlePushFront(CheckerContext &C, SVal Cont, const Expr *ContE) const;
+ void handlePopFront(CheckerContext &C, SVal Cont, const Expr *ContE) const;
+ void handleInsert(CheckerContext &C, SVal Cont, SVal Iter) const;
+ void handleErase(CheckerContext &C, SVal Cont, SVal Iter) const;
+ void handleErase(CheckerContext &C, SVal Cont, SVal Iter1, SVal Iter2) const;
+ void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter) const;
+ void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter1,
+ SVal Iter2) const;
+ const NoteTag *getChangeTag(CheckerContext &C, StringRef Text,
+ const MemRegion *ContReg,
+ const Expr *ContE) const;
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
const char *Sep) const override;
public:
- ContainerModeling() {}
+ ContainerModeling() = default;
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
- typedef void (ContainerModeling::*NoItParamFn)(CheckerContext &,
- const SVal &) const;
- typedef void (ContainerModeling::*OneItParamFn)(CheckerContext &,
- const SVal &,
- const SVal &) const;
- typedef void (ContainerModeling::*TwoItParamFn)(CheckerContext &,
- const SVal &,
- const SVal &,
- const SVal &) const;
+ using NoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
+ const Expr *) const;
+ using OneItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
+ SVal) const;
+ using TwoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, SVal,
+ SVal) const;
CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
{{0, "clear", 0},
@@ -184,7 +180,8 @@
if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call);
if (Handler0) {
- (this->**Handler0)(C, InstCall->getCXXThisVal());
+ (this->**Handler0)(C, InstCall->getCXXThisVal(),
+ InstCall->getCXXThisExpr());
return;
}
@@ -259,7 +256,7 @@
}
void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
- const SVal &RetVal, const SVal &Cont) const {
+ SVal RetVal, SVal Cont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -281,7 +278,7 @@
}
void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
- const SVal &RetVal, const SVal &Cont) const {
+ SVal RetVal, SVal Cont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -302,9 +299,8 @@
C.addTransition(State);
}
-void ContainerModeling::handleAssignment(CheckerContext &C, const SVal &Cont,
- const Expr *CE,
- const SVal &OldCont) const {
+void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont,
+ const Expr *CE, SVal OldCont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -379,8 +375,8 @@
C.addTransition(State);
}
-void ContainerModeling::handleAssign(CheckerContext &C,
- const SVal &Cont) const {
+void ContainerModeling::handleAssign(CheckerContext &C, SVal Cont,
+ const Expr *ContE) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -393,7 +389,8 @@
C.addTransition(State);
}
-void ContainerModeling::handleClear(CheckerContext &C, const SVal &Cont) const {
+void ContainerModeling::handleClear(CheckerContext &C, SVal Cont,
+ const Expr *ContE) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -415,12 +412,14 @@
}
}
}
+ const NoteTag *ChangeTag =
+ getChangeTag(C, "became empty", ContReg, ContE);
State = invalidateAllIteratorPositions(State, ContReg);
- C.addTransition(State);
+ C.addTransition(State, ChangeTag);
}
-void ContainerModeling::handlePushBack(CheckerContext &C,
- const SVal &Cont) const {
+void ContainerModeling::handlePushBack(CheckerContext &C, SVal Cont,
+ const Expr *ContE) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -452,13 +451,15 @@
nonloc::SymbolVal(EndSym),
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
SymMgr.getType(EndSym)).getAsSymbol();
+ const NoteTag *ChangeTag =
+ getChangeTag(C, "extended to the right by 1 position", ContReg, ContE);
State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
+ C.addTransition(State, ChangeTag);
}
- C.addTransition(State);
}
-void ContainerModeling::handlePopBack(CheckerContext &C,
- const SVal &Cont) const {
+void ContainerModeling::handlePopBack(CheckerContext &C, SVal Cont,
+ const Expr *ContE) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -479,6 +480,8 @@
nonloc::SymbolVal(EndSym),
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
SymMgr.getType(EndSym)).getAsSymbol();
+ const NoteTag *ChangeTag =
+ getChangeTag(C, "shrinked from the right by 1 position", ContReg, ContE);
// For vector-like and deque-like containers invalidate the last and the
// past-end iterator positions. For list-like containers only invalidate
// the last position
@@ -491,12 +494,12 @@
}
auto newEndSym = BackSym;
State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
- C.addTransition(State);
+ C.addTransition(State, ChangeTag);
}
}
-void ContainerModeling::handlePushFront(CheckerContext &C,
- const SVal &Cont) const {
+void ContainerModeling::handlePushFront(CheckerContext &C, SVal Cont,
+ const Expr *ContE) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -522,14 +525,16 @@
nonloc::SymbolVal(BeginSym),
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
SymMgr.getType(BeginSym)).getAsSymbol();
+ const NoteTag *ChangeTag =
+ getChangeTag(C, "extended to the left by 1 position", ContReg, ContE);
State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
- C.addTransition(State);
+ C.addTransition(State, ChangeTag);
}
}
}
-void ContainerModeling::handlePopFront(CheckerContext &C,
- const SVal &Cont) const {
+void ContainerModeling::handlePopFront(CheckerContext &C, SVal Cont,
+ const Expr *ContE) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -557,13 +562,15 @@
nonloc::SymbolVal(BeginSym),
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
SymMgr.getType(BeginSym)).getAsSymbol();
+ const NoteTag *ChangeTag =
+ getChangeTag(C, "shrinked from the left by 1 position", ContReg, ContE);
State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
- C.addTransition(State);
+ C.addTransition(State, ChangeTag);
}
}
-void ContainerModeling::handleInsert(CheckerContext &C, const SVal &Cont,
- const SVal &Iter) const {
+void ContainerModeling::handleInsert(CheckerContext &C, SVal Cont,
+ SVal Iter) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -593,8 +600,8 @@
}
}
-void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont,
- const SVal &Iter) const {
+void ContainerModeling::handleErase(CheckerContext &C, SVal Cont,
+ SVal Iter) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -627,9 +634,8 @@
C.addTransition(State);
}
-void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont,
- const SVal &Iter1,
- const SVal &Iter2) const {
+void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, SVal Iter1,
+ SVal Iter2) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -664,8 +670,8 @@
C.addTransition(State);
}
-void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont,
- const SVal &Iter) const {
+void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
+ SVal Iter) const {
auto State = C.getState();
const auto *Pos = getIteratorPosition(State, Iter);
if (!Pos)
@@ -685,9 +691,8 @@
C.addTransition(State);
}
-void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont,
- const SVal &Iter1,
- const SVal &Iter2) const {
+void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
+ SVal Iter1, SVal Iter2) const {
auto State = C.getState();
const auto *Pos1 = getIteratorPosition(State, Iter1);
const auto *Pos2 = getIteratorPosition(State, Iter2);
@@ -700,6 +705,31 @@
C.addTransition(State);
}
+const NoteTag *ContainerModeling::getChangeTag(CheckerContext &C,
+ StringRef Text,
+ const MemRegion *ContReg,
+ const Expr *ContE) const {
+ StringRef Name;
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(ContE)) {
+ Name = DRE->getDecl()->getName();
+ }
+
+ return C.getNoteTag([Text, Name, ContReg](BugReport &BR) -> std::string {
+ const auto *PSBR = dyn_cast<PathSensitiveBugReport>(&BR);
+ if (!PSBR)
+ return "";
+
+ if (!PSBR->isInteresting(ContReg))
+ return "";
+
+ SmallString<256> Msg;
+ llvm::raw_svector_ostream Out(Msg);
+ Out << "Container " << (!Name.empty() ? ("'" + Name.str() + "' ") : "" )
+ << Text;
+ return std::string(Out.str());
+ });
+}
+
void ContainerModeling::printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const {
auto ContMap = State->get<ContainerMap>();
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits