Index: clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -111,7 +111,8 @@ OverloadedOperatorKind Op, const SVal &RetVal, const SVal &Iterator, const SVal &Amount) const; void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator, - OverloadedOperatorKind OK, SVal Offset) const; + OverloadedOperatorKind OK, SVal Offset, + Optional OperandLValue) const; void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, SVal Amount) const; void handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, @@ -121,6 +122,7 @@ void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal, const MemRegion *Cont) const; bool noChangeInAdvance(CheckerContext &C, SVal Iter, const Expr *CE) const; + Optional getOperandLValue(CheckerContext &C, Expr *Operand) const; void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override; @@ -254,10 +256,23 @@ if (!isIncrementOperator(OK) && !isDecrementOperator(OK)) return; + // Since binding happens before this checker hook, the iterator position + // is removed from the lvalue operand of this operation. We have to find that + // lvalue to allow `handlePtrIncrOrDecr()` to assign the new iterator + // position to it. For the prefix version it is the same as the result of + // the expression. + Optional OperandLValue = None; + if (OK == UO_PreInc || OK == UO_PreDec) { + ProgramStateRef State = C.getState(); + OperandLValue = State->getSVal(UO, C.getLocationContext()); + } else { + OperandLValue = getOperandLValue(C, UO->getSubExpr()); + } + auto &SVB = C.getSValBuilder(); handlePtrIncrOrDecr(C, UO->getSubExpr(), isIncrementOperator(OK) ? OO_Plus : OO_Minus, - SVB.makeArrayIndex(1)); + SVB.makeArrayIndex(1), OperandLValue); } void IteratorModeling::checkPostStmt(const BinaryOperator *BO, @@ -284,8 +299,17 @@ if (!AmountExpr->getType()->isIntegralOrEnumerationType()) return; const SVal &AmountVal = IsIterOnLHS ? RVal : LVal; + + // Since binding happens before this checker hook, the iterator position + // is removed from the lvalue operand of this operation (assignments only). + // We have to find that lvalue to allow `handlePtrIncrOrDecr()` to assign + // the new iterator position to it. + Optional OperandLValue = None; + if (BinaryOperator::isAssignmentOp(OK)) { + OperandLValue = State->getSVal(BO, C.getLocationContext()); + } handlePtrIncrOrDecr(C, IterExpr, BinaryOperator::getOverloadedOperator(OK), - AmountVal); + AmountVal, OperandLValue); } } @@ -629,7 +653,8 @@ void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator, OverloadedOperatorKind OK, - SVal Offset) const { + SVal Offset, + Optional OperandLValue) const { if (!Offset.getAs()) return; @@ -639,7 +664,7 @@ QualType ElementType = PtrType->getPointeeType(); ProgramStateRef State = C.getState(); - SVal OldVal = State->getSVal(Iterator, C.getLocationContext()); + SVal OldVal = State->getSValAsScalarOrLoc(Iterator, C.getLocationContext()); const IteratorPosition *OldPos = getIteratorPosition(State, OldVal); if (!OldPos) @@ -664,6 +689,9 @@ "Iterator should have position after successful advancement"); ProgramStateRef NewState = setIteratorPosition(State, NewVal, *NewPos); + if (OperandLValue.hasValue()) { + NewState = setIteratorPosition(NewState, *OperandLValue, *NewPos); + } C.addTransition(NewState); } else { assignToContainer(C, Iterator, NewVal, OldPos->getContainer()); @@ -728,6 +756,20 @@ return PosBefore->getOffset() == PosAfter->getOffset(); } +Optional +IteratorModeling::getOperandLValue(CheckerContext &C, Expr *Operand) const { + ProgramStateRef State = C.getState(); + auto *LCtx = C.getLocationContext(); + + if (const auto *DRE = dyn_cast(Operand->IgnoreParenImpCasts())) { + if (const auto *VD = dyn_cast(DRE->getDecl())) { + return State->getLValue(VD, LCtx); + } + } + + return None; +} + void IteratorModeling::printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const { auto SymbolMap = State->get(); Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h =================================================================== --- clang/test/Analysis/Inputs/system-header-simulator-cxx.h +++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h @@ -32,6 +32,14 @@ typedef typename Iterator::reference reference; typedef typename Iterator::iterator_category iterator_category; }; + + template struct iterator_traits { + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef random_access_iterator_tag iterator_category; + }; } template struct __vector_iterator { @@ -280,8 +288,13 @@ public: typedef T value_type; typedef size_t size_type; + #ifdef STD_VECTOR_ITERATOR_PTR + typedef T* iterator; + typedef const T* const_iterator; + #else typedef __vector_iterator iterator; typedef __vector_iterator const_iterator; + #endif vector() : _start(0), _finish(0), _end_of_storage(0) {} template @@ -795,7 +808,8 @@ void advance(InputIterator& it, Distance n) #if !defined(STD_ADVANCE_INLINE_LEVEL) || STD_ADVANCE_INLINE_LEVEL > 1 { - __advance(it, n, typename InputIterator::iterator_category()); + __advance(it, n, + typename iterator_traits::iterator_category()); } #else ; Index: clang/test/Analysis/diagnostics/explicit-suppression.cpp =================================================================== --- clang/test/Analysis/diagnostics/explicit-suppression.cpp +++ clang/test/Analysis/diagnostics/explicit-suppression.cpp @@ -19,6 +19,6 @@ void testCopyNull(C *I, C *E) { std::copy(I, E, (C *)0); #ifndef SUPPRESSED - // expected-warning@../Inputs/system-header-simulator-cxx.h:709 {{Called C++ object pointer is null}} + // expected-warning@../Inputs/system-header-simulator-cxx.h:722 {{Called C++ object pointer is null}} #endif } Index: clang/test/Analysis/invalidated-iterator.cpp =================================================================== --- clang/test/Analysis/invalidated-iterator.cpp +++ clang/test/Analysis/invalidated-iterator.cpp @@ -1,5 +1,7 @@ // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.InvalidatedIterator -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.InvalidatedIterator -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.InvalidatedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -DSTD_VECTOR_ITERATOR_PTR %s -verify +// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.InvalidatedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -DSTD_VECTOR_ITERATOR_PTR %s -verify #include "Inputs/system-header-simulator-cxx.h" @@ -7,13 +9,13 @@ void normal_dereference(std::vector &V) { auto i = V.cbegin(); - *i; // no-warning + int n = *i; // no-warning } void invalidated_dereference(std::vector &V) { auto i = V.cbegin(); V.erase(i); - *i; // expected-warning{{Invalidated iterator accessed}} + int n = *i; // expected-warning{{Invalidated iterator accessed}} } void normal_prefix_increment(std::vector &V) { @@ -28,12 +30,12 @@ } void normal_prefix_decrement(std::vector &V) { - auto i = ++V.cbegin(); + auto i = std::next(V.cbegin()); --i; // no-warning } void invalidated_prefix_decrement(std::vector &V) { - auto i = ++V.cbegin(); + auto i = std::next(V.cbegin()); V.erase(i); --i; // expected-warning{{Invalidated iterator accessed}} } @@ -50,12 +52,12 @@ } void normal_postfix_decrement(std::vector &V) { - auto i = ++V.cbegin(); + auto i = std::next(V.cbegin()); i--; // no-warning } void invalidated_postfix_decrement(std::vector &V) { - auto i = ++V.cbegin(); + auto i = std::next(V.cbegin()); V.erase(i); i--; // expected-warning{{Invalidated iterator accessed}} } @@ -106,13 +108,13 @@ void normal_subscript(std::vector &V) { auto i = V.cbegin(); - i[1]; // no-warning + int n = i[1]; // no-warning } void invalidated_subscript(std::vector &V) { auto i = V.cbegin(); V.erase(i); - i[1]; // expected-warning{{Invalidated iterator accessed}} + int n = i[1]; // expected-warning{{Invalidated iterator accessed}} } void assignment(std::vector &V) { Index: clang/test/Analysis/iterator-modeling.cpp =================================================================== --- clang/test/Analysis/iterator-modeling.cpp +++ clang/test/Analysis/iterator-modeling.cpp @@ -8,6 +8,10 @@ // 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 -DSTD_ADVANCE_INLINE_LEVEL=2 %s -verify -analyzer-config display-checker-name=false +// 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 -DSTD_VECTOR_ITERATOR_PTR %s -verify -analyzer-config display-checker-name=false + +// 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 -DSTD_VECTOR_ITERATOR_PTR %s -verify -analyzer-config display-checker-name=false + // 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 #include "Inputs/system-header-simulator-cxx.h" @@ -60,7 +64,10 @@ auto j = ++i; + clang_analyzer_eval(clang_analyzer_iterator_container(i) == &v); // expected-warning{{TRUE}} clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning-re {{$v.begin() + 1{{$}}}} + + clang_analyzer_eval(clang_analyzer_iterator_container(j) == &v); // expected-warning{{TRUE}} clang_analyzer_express(clang_analyzer_iterator_position(j)); // expected-warning-re {{$v.begin() + 1{{$}}}} } @@ -390,7 +397,8 @@ } void vector_move_assignment(std::vector &V1, std::vector &V2) { - auto i0 = V1.cbegin(), i1 = V2.cbegin(), i2 = --V2.cend(), i3 = V2.cend(); + auto i0 = V1.cbegin(), i1 = V2.cbegin(), i2 = std::prev(V2.cend()), + i3 = V2.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V2), "$V2.begin()"); @@ -544,7 +552,7 @@ /// std::vector-like containers: The past-the-end iterator is invalidated. void vector_push_back(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -604,7 +612,7 @@ /// std::vector-like containers: The past-the-end iterator is invalidated. void vector_emplace_back(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -664,7 +672,7 @@ /// past-the-end iterator, are invalidated. void vector_pop_back(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -996,7 +1004,7 @@ } void vector_insert_behind_begin(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::next(V.cbegin()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -1029,7 +1037,7 @@ } void vector_insert_ahead_of_end(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -1045,7 +1053,7 @@ } void vector_insert_end(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -1323,7 +1331,7 @@ } void vector_emplace_behind_begin(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::next(V.cbegin()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -1356,7 +1364,7 @@ } void vector_emplace_ahead_of_end(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -1372,7 +1380,7 @@ } void vector_emplace_end(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -1614,7 +1622,7 @@ /// the erase, including the past-the-end iterator. void vector_erase_begin(std::vector &V) { - auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::next(V.cbegin()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -1629,7 +1637,7 @@ } void vector_erase_behind_begin(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::next(V.cbegin()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -1662,7 +1670,7 @@ } void vector_erase_ahead_of_end(std::vector &V) { - auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + auto i0 = V.cbegin(), i1 = std::prev(V.cend()), i2 = V.cend(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); @@ -1889,141 +1897,49 @@ } } -template -struct cont_with_ptr_iterator { - typedef T* iterator; - T* begin() const; - T* end() const; +struct iter_wrapper { + std::vector::iterator i; }; -void begin_ptr_iterator(const cont_with_ptr_iterator &c) { - auto i = c.begin(); - - clang_analyzer_eval(clang_analyzer_iterator_container(i) == &c); // expected-warning{{TRUE}} - clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()"); - clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin()}} - - if (i != c.begin()) { - clang_analyzer_warnIfReached(); - } - } - -void prefix_increment_ptr_iterator(const cont_with_ptr_iterator &c) { - auto i = c.begin(); - - clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()"); - - auto j = ++i; - - clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin() + 1}} - clang_analyzer_express(clang_analyzer_iterator_position(j)); // expected-warning{{$c.begin() + 1}} -} - -void prefix_decrement_ptr_iterator(const cont_with_ptr_iterator &c) { - auto i = c.end(); - - clang_analyzer_denote(clang_analyzer_container_end(c), "$c.end()"); - - auto j = --i; - - clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.end() - 1}} - clang_analyzer_express(clang_analyzer_iterator_position(j)); // expected-warning{{$c.end() - 1}} -} - -void postfix_increment_ptr_iterator(const cont_with_ptr_iterator &c) { - auto i = c.begin(); - - clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()"); - - auto j = i++; - - clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin() + 1}} - clang_analyzer_express(clang_analyzer_iterator_position(j)); // expected-warning{{$c.begin()}} -} - -void postfix_decrement_ptr_iterator(const cont_with_ptr_iterator &c) { - auto i = c.end(); - - clang_analyzer_denote(clang_analyzer_container_end(c), "$c.end()"); - - auto j = i--; - - clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.end() - 1}} - clang_analyzer_express(clang_analyzer_iterator_position(j)); // expected-warning{{$c.end()}} -} - -void plus_equal_ptr_iterator(const cont_with_ptr_iterator &c) { - auto i = c.begin(); - - clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()"); - - i += 2; - - clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin() + 2}} -} - -void minus_equal_ptr_iterator(const cont_with_ptr_iterator &c) { - auto i = c.end(); - - clang_analyzer_denote(clang_analyzer_container_end(c), "$c.end()"); - - i -= 2; - - clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.end() - 2}} -} - -void minus_equal_ptr_iterator_variable(const cont_with_ptr_iterator &c, - int n) { - auto i = c.end(); +void member_iterator_incr(std::vector V) { + iter_wrapper iw; + iw.i = V.begin(); - i -= n; // no-crash -} - -void plus_lhs_ptr_iterator(const cont_with_ptr_iterator &c) { - auto i1 = c.begin(); - - clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()"); + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); - auto i2 = i1 + 2; + iw.i++; - clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &c); // expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$c.begin()}} - clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$c.begin() + 2}} + clang_analyzer_express(clang_analyzer_iterator_position(iw.i)); // expected-warning-re {{$V.begin() + 1{{$}}}} } -void plus_rhs_ptr_iterator(const cont_with_ptr_iterator &c) { - auto i1 = c.begin(); - - clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()"); - - auto i2 = 2 + i1; - - clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &c); // expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$c.begin()}} - clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$c.begin() + 2}} -} +struct iter_wrapper_wrapper { + iter_wrapper iw; +}; -void minus_ptr_iterator(const cont_with_ptr_iterator &c) { - auto i1 = c.end(); +void member_member_iterator_incr(std::vector V) { + iter_wrapper_wrapper iww; + iww.iw.i = V.begin(); - clang_analyzer_denote(clang_analyzer_container_end(c), "$c.end()"); + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); - auto i2 = i1 - 2; + iww.iw.i++; - clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &c); // expected-warning{{TRUE}} - clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$c.end()}} - clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$c.end() - 2}} + clang_analyzer_express(clang_analyzer_iterator_position(iww.iw.i)); // expected-warning-re {{$V.begin() + 1{{$}}}} } -void ptr_iter_diff(cont_with_ptr_iterator &c) { - auto i0 = c.begin(), i1 = c.end(); - ptrdiff_t len = i1 - i0; // no-crash -} +template +struct ContainerAdapter { + Cont C; + ContainerAdapter(Cont c) : C(c) {} + typename Cont::iterator begin() { return C.begin(); } +}; -void ptr_iter_cmp_nullptr(cont_with_ptr_iterator &c) { - auto i0 = c.begin(); - if (i0 != nullptr) // no-crash - ++i0; +void adapter_test(std::vector V) { + ContainerAdapter> A(V); + auto i = A.begin(); + auto j = V.begin(); + clang_analyzer_eval(clang_analyzer_iterator_container(i) == &A); // expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_container(j) == &V); // expected-warning{{TRUE}} } void clang_analyzer_printState(); @@ -2038,7 +1954,7 @@ // CHECK-NEXT: "i0 : Valid ; Container == SymRegion{reg_$[[#]] & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}" // CHECK-NEXT: ]} - *i0; + int n = *i0; const auto i1 = V.cend(); clang_analyzer_printState(); @@ -2048,5 +1964,5 @@ // CHECK-NEXT: "i1 : Valid ; Container == SymRegion{reg_$[[#]] & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}" // CHECK-NEXT: ]} - *i1; + n = *i1; } Index: clang/test/Analysis/iterator-range.cpp =================================================================== --- clang/test/Analysis/iterator-range.cpp +++ clang/test/Analysis/iterator-range.cpp @@ -1,5 +1,7 @@ // 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 +// 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 -DSTD_VECTOR_ITERATOR_PTR -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 -DSTD_VECTOR_ITERATOR_PTR -analyzer-output=text %s -verify #include "Inputs/system-header-simulator-cxx.h" @@ -9,30 +11,30 @@ void deref_begin(const std::vector &V) { auto i = V.begin(); - *i; // no-warning + int n = *i; // no-warning } void deref_begind_begin(const std::vector &V) { - auto i = ++V.begin(); - *i; // no-warning + auto i = std::next(V.begin()); + int n = *i; // no-warning } template Iter return_any_iterator(const Iter &It); void deref_unknown(const std::vector &V) { auto i = return_any_iterator(V.begin()); - *i; // no-warning + int n = *i; // no-warning } void deref_ahead_of_end(const std::vector &V) { - auto i = --V.end(); - *i; // no-warning + auto i = std::prev(V.end()); + int n = *i; // no-warning } void deref_end(const std::vector &V) { auto i = V.end(); - *i; // expected-warning{{Past-the-end iterator dereferenced}} - // expected-note@-1{{Past-the-end iterator dereferenced}} + int n = *i; // expected-warning{{Past-the-end iterator dereferenced}} + // expected-note@-1{{Past-the-end iterator dereferenced}} } // Prefix increment - operator++() @@ -43,7 +45,7 @@ } void incr_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); ++i; // no-warning } @@ -53,7 +55,7 @@ } void incr_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); ++i; // no-warning } @@ -71,7 +73,7 @@ } void behind_begin_incr(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); i++; // no-warning } @@ -81,7 +83,7 @@ } void ahead_of_end_incr(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); i++; // no-warning } @@ -100,7 +102,7 @@ } void decr_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); --i; // no-warning } @@ -110,7 +112,7 @@ } void decr_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); --i; // no-warning } @@ -128,7 +130,7 @@ } void behind_begin_decr(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); i--; // no-warning } @@ -138,7 +140,7 @@ } void ahead_of_end_decr(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); i--; // no-warning } @@ -155,7 +157,7 @@ } void incr_by_2_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); i += 2; // no-warning } @@ -165,13 +167,13 @@ } void incr_by_2_ahead_by_2_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); --i; i += 2; // no-warning } void incr_by_2_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(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}} } @@ -190,7 +192,7 @@ } void incr_by_2_copy_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = i + 2; // no-warning } @@ -200,13 +202,13 @@ } void incr_by_2_copy_ahead_by_2_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); --i; auto j = i + 2; // no-warning } void incr_by_2_copy_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(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}} } @@ -226,13 +228,13 @@ } void decr_by_2_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(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 &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); ++i; i -= 2; // no-warning } @@ -243,7 +245,7 @@ } void decr_by_2_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); i -= 2; // no-warning } @@ -261,13 +263,13 @@ } void decr_by_2_copy_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(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 &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); ++i; auto j = i - 2; // no-warning } @@ -278,7 +280,7 @@ } void decr_by_2_copy_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = i - 2; // no-warning } @@ -299,7 +301,7 @@ } void subscript_zero_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = i[0]; // no-warning } @@ -309,7 +311,7 @@ } void subscript_zero_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = i[0]; // no-warning } @@ -327,7 +329,7 @@ } void subscript_negative_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = i[-1]; // no-warning } @@ -337,7 +339,7 @@ } void subscript_negative_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = i[-1]; // no-warning } @@ -355,7 +357,7 @@ } void subscript_positive_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = i[1]; // no-warning } @@ -365,7 +367,7 @@ } void subscript_positive_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = i[1]; // no-warning FIXME: expected warning Past-the-end iterator dereferenced } @@ -387,7 +389,7 @@ } void advance_plus_1_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); std::advance(i, 1); // no-warning } @@ -397,7 +399,7 @@ } void advance_plus_1_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); std::advance(i, 1); // no-warning } @@ -416,7 +418,7 @@ } void advance_minus_1_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); std::advance(i, -1); // no-warning } @@ -426,7 +428,7 @@ } void advance_minus_1_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); std::advance(i, -1); // no-warning } @@ -443,7 +445,7 @@ } void advance_plus_2_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); std::advance(i, 2); // no-warning } @@ -453,7 +455,7 @@ } void advance_plus_2_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } @@ -473,7 +475,7 @@ } void advance_minus_2_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} // expected-note@-1{{Iterator decremented ahead of its valid range}} } @@ -484,7 +486,7 @@ } void advance_minus_2_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); std::advance(i, -2); // no-warning } @@ -501,7 +503,7 @@ } void advance_0_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); std::advance(i, 0); // no-warning } @@ -511,7 +513,7 @@ } void advance_0_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); std::advance(i, 0); // no-warning } @@ -532,7 +534,7 @@ } void next_plus_1_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = std::next(i); // no-warning } @@ -542,7 +544,7 @@ } void next_plus_1_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = std::next(i); // no-warning } @@ -561,7 +563,7 @@ } void next_minus_1_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = std::next(i, -1); // no-warning } @@ -571,7 +573,7 @@ } void next_minus_1_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = std::next(i, -1); // no-warning } @@ -588,7 +590,7 @@ } void next_plus_2_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = std::next(i, 2); // no-warning } @@ -598,7 +600,7 @@ } void next_plus_2_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } @@ -618,7 +620,7 @@ } void next_minus_2_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} // expected-note@-1{{Iterator decremented ahead of its valid range}} } @@ -629,7 +631,7 @@ } void next_minus_2_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = std::next(i, -2); // no-warning } @@ -646,7 +648,7 @@ } void next_0_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = std::next(i, 0); // no-warning } @@ -656,7 +658,7 @@ } void next_0_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = std::next(i, 0); // no-warning } @@ -678,7 +680,7 @@ } void prev_plus_1_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = std::prev(i); // no-warning } @@ -688,7 +690,7 @@ } void prev_plus_1_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = std::prev(i); // no-warning } @@ -705,7 +707,7 @@ } void prev_minus_1_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = std::prev(i, -1); // no-warning } @@ -715,7 +717,7 @@ } void prev_minus_1_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = std::prev(i, -1); // no-warning } @@ -734,7 +736,7 @@ } void prev_plus_2_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}} // expected-note@-1{{Iterator decremented ahead of its valid range}} } @@ -745,7 +747,7 @@ } void prev_plus_2_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = std::prev(i, 2); // no-warning } @@ -762,7 +764,7 @@ } void prev_minus_2_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = std::prev(i, -2); // no-warning } @@ -772,7 +774,7 @@ } void prev_minus_2_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } @@ -791,7 +793,7 @@ } void prev_0_behind_begin(const std::vector &V) { - auto i = ++V.begin(); + auto i = std::next(V.begin()); auto j = std::prev(i, 0); // no-warning } @@ -801,7 +803,7 @@ } void prev_0_ahead_of_end(const std::vector &V) { - auto i = --V.end(); + auto i = std::prev(V.end()); auto j = std::prev(i, 0); // no-warning } @@ -847,12 +849,12 @@ // Container modification - test path notes void deref_end_after_pop_back(std::vector &V) { - const auto i = --V.end(); + const auto i = std::prev(V.end()); V.pop_back(); // expected-note{{Container 'V' shrank from the back by 1 position}} - *i; // expected-warning{{Past-the-end iterator dereferenced}} - // expected-note@-1{{Past-the-end iterator dereferenced}} + int n = *i; // expected-warning{{Past-the-end iterator dereferenced}} + // expected-note@-1{{Past-the-end iterator dereferenced}} } template Index: clang/test/Analysis/mismatched-iterator.cpp =================================================================== --- clang/test/Analysis/mismatched-iterator.cpp +++ clang/test/Analysis/mismatched-iterator.cpp @@ -1,5 +1,7 @@ // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.MismatchedIterator -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.MismatchedIterator -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.MismatchedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -DSTD_VECTOR_ITERATOR_PTR %s -verify +// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.MismatchedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -DSTD_VECTOR_ITERATOR_PTR %s -verify #include "Inputs/system-header-simulator-cxx.h" Index: clang/test/Analysis/smart-ptr-text-output.cpp =================================================================== --- clang/test/Analysis/smart-ptr-text-output.cpp +++ clang/test/Analysis/smart-ptr-text-output.cpp @@ -80,7 +80,7 @@ void derefOnStdSwappedNullPtr() { std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}} std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}} - std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}} + std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:993 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}} // expected-note@-1 {{Calling 'swap'}} // expected-note@-2 {{Returning from 'swap'}} P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}