|  | // Copyright 2024 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  | #include <algorithm> | 
|  | #include <vector> | 
|  |  | 
|  | bool A(); | 
|  | bool B(); | 
|  |  | 
|  | void SameConditionInvalidatesThenValidatesIterator() { | 
|  | std::vector<int> container = {1, 2, 3}; | 
|  | auto it = container.begin() + 1; | 
|  | if (it == container.end()) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | const bool a = A(); | 
|  |  | 
|  | if (a) { | 
|  | container.clear(); | 
|  | } | 
|  |  | 
|  | if (a) { | 
|  | container.push_back(1); | 
|  | container.push_back(2); | 
|  | it = container.begin() + 1; | 
|  | if (it == std::end(container)) { | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // This is valid because although the container was invalidated in the first | 
|  | // `if(a)` block, the second one reassigns the iterator and ensures that it | 
|  | // is different than `end`. Since the same check is made at the very | 
|  | // beginning of the function, the iterator is logically valid at this point | 
|  | // of the execution. | 
|  | *it = 10; | 
|  | } | 
|  |  | 
|  | void SameConditionUncheckedIterator() { | 
|  | std::vector<int> container = {1, 2, 3}; | 
|  | auto it = container.begin() + 1; | 
|  | if (it == std::end(container)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | const bool a = A(); | 
|  |  | 
|  | if (a) { | 
|  | container.clear(); | 
|  | } | 
|  |  | 
|  | if (!a) { | 
|  | container.push_back(1); | 
|  | container.push_back(2); | 
|  | it = container.begin() + 1; | 
|  | } | 
|  |  | 
|  | // This is invalid because although the iterator is getting reassigned in the | 
|  | // second `a` conditional block, it is not checked against the `end` iterator. | 
|  | *it = 10;  // Invalid. | 
|  | } | 
|  |  | 
|  | void DifferentConditionsWithCheckedIterator() { | 
|  | std::vector<int> container = {1, 2, 3}; | 
|  | auto it = container.begin() + 1; | 
|  | if (it == std::end(container)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | const bool a = A(); | 
|  | const bool b = B(); | 
|  |  | 
|  | if (a && b) { | 
|  | container.clear(); | 
|  | } | 
|  |  | 
|  | if (a || b) { | 
|  | container.push_back(1); | 
|  | container.push_back(2); | 
|  | it = container.begin() + 1; | 
|  | if (it == std::end(container)) { | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Valid since in all cases it is checked against the `end` iterator. | 
|  | *it = 10; | 
|  | } | 
|  |  | 
|  | void DifferentConditionsWithUncheckedIterator() { | 
|  | std::vector<int> container = {1, 2, 3}; | 
|  | auto it = container.begin() + 1; | 
|  | if (it == std::end(container)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | const bool a = A(); | 
|  | const bool b = B(); | 
|  |  | 
|  | if (a && b) { | 
|  | container.clear(); | 
|  | } | 
|  |  | 
|  | if (a || b) { | 
|  | container.push_back(1); | 
|  | container.push_back(2); | 
|  | it = container.begin() + 1; | 
|  | } | 
|  |  | 
|  | // Invalid. The difference with `DifferentConditionsWithCheckedIterator` is | 
|  | // that we do not check the iterator in the last `if` block, hence we can't | 
|  | // ensure that the iterator is valid. | 
|  | *it = 10; | 
|  | } |