chromium/tools/clang/iterator_checker/tests/iterator-with-multiple-container.cpp

// 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 Bool();

void MergeWithDifferentContainerValuesIteratorUnchecked() {
  std::vector<int> v1 = {1, 10, 100};
  std::vector<int> v2 = {1, 10, 100};
  std::vector<int> v3 = {1, 10, 100};

  auto it = std::find(v1.begin(), v1.end(), 10);

  if (Bool()) {
    it = std::find(v2.begin(), v2.end(), 10);
  } else {
    it = std::find(v3.begin(), v3.end(), 10);
  }

  v1.clear();

  // As for now, the tool doesn't handle well merges with different container
  // values. see https://crbug.com/1455371.
  // However, since the iterator was never checked against `end`, accessing it
  // is still considered invalid.
  *it = 20;
}

void MergeWithDifferentContainerValueIteratorChecked() {
  std::vector<int> v1 = {1, 10, 100};
  std::vector<int> v2 = {1, 10, 100};
  std::vector<int> v3 = {1, 10, 100};

  auto it = std::find(v1.begin(), v1.end(), 10);

  if (Bool()) {
    it = std::find(v2.begin(), v2.end(), 10);
    if (it == std::end(v2)) {
      return;
    }
  } else {
    it = std::find(v3.begin(), v3.end(), 10);
    if (it == std::end(v3)) {
      return;
    }
  }

  v1.clear();

  // This is in practice valid, because it can only be true here.
  // Although the tool does well on this case, the fact that multiple
  // containers are being used for the same iterator above means that the tool
  // is lucky.
  *it = 20;
}

void MergeWithDifferentContainersInvalidateAll() {
  std::vector<int> v1 = {1, 10, 100};
  std::vector<int> v2 = {1, 10, 100};

  auto it = std::find(v1.begin(), v1.end(), 10);

  if (Bool()) {
    it = std::find(v2.begin(), v2.end(), 10);
    if (it == std::end(v2)) {
      return;
    }
  } else {
    it = std::find(v1.begin(), v1.end(), 10);
    if (it == std::end(v1)) {
      return;
    }
  }

  v1.clear();

  // It is invalid because the iterator could still point to `v1`, which is
  // invalidated by `v1.clear()`.
  *it = 20;
}

void MergeWithSameContainerValueIteratorChecked() {
  std::vector<int> v1 = {1, 10, 100};
  std::vector<int> v2 = {1, 10, 100};
  std::vector<int> v3 = {1, 10, 100};

  auto it = std::find(v1.begin(), v1.end(), 10);

  if (Bool()) {
    it = std::find(v1.begin(), v1.end(), 10);
    if (it == std::end(v1)) {
      return;
    }
  } else {
    it = std::find(v1.begin(), v1.end(), 10);
    if (it == std::end(v1)) {
      return;
    }
  }

  // It is valid here because we would have returned from the function in the
  // previous conditional blocks if not.
  *it;
  v1.clear();

  // It just got invalidated by `v1.clear()`.
  *it = 20;
}