chromium/base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ref_unittest.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "partition_alloc/pointers/raw_ref.h"

#include <functional>
#include <type_traits>

#include "base/test/gtest_util.h"
#include "partition_alloc/buildflags.h"
#include "partition_alloc/pointers/raw_ptr.h"
#include "partition_alloc/pointers/raw_ptr_counting_impl_for_test.h"
#include "partition_alloc/pointers/raw_ptr_test_support.h"
#include "testing/gtest/include/gtest/gtest.h"
#if PA_BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
#include "base/debug/asan_service.h"
#include "base/memory/raw_ptr_asan_service.h"
#endif  // PA_BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)

namespace {

class BaseClass {};
class SubClass : public BaseClass {};

// raw_ref just defers to the superclass for implementations, so it
// can't add more data types.
static_assert;

// Since it can't hold null, raw_ref is not default-constructible.
static_assert;
static_assert;

// A mutable reference can only be constructed from a mutable lvalue reference.
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
// Same for assignment.
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;

// A const reference can be constructed from a const or mutable lvalue
// reference.
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
// Same for assignment.
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;

// Same trivial operations (or not) as raw_ptr<T>.
static_assert;
static_assert;
// But constructing from another raw_ref must check if it's internally null
// (which indicates use-after-move).
static_assert;
static_assert;
static_assert;
static_assert;

// A raw_ref can be copied or moved.
static_assert;
static_assert;
static_assert;
static_assert;

// A SubClass can be converted to a BaseClass.
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
// A BaseClass can't be implicitly downcasted.
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;

// A raw_ref<BaseClass> can be constructed directly from a SubClass.
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
// But a raw_ref<SubClass> can't be constructed from an implicit downcast from a
// BaseClass.
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;

// A mutable reference can be converted to const reference.
static_assert;
static_assert;
// A const reference can't be converted to mutable.
static_assert;
static_assert;

// The deref operator gives the internal reference.
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
// A const T is always returned as const.
static_assert;

// The arrow operator gives a (non-null) pointer to the internal reference.
static_assert;
static_assert;

// Verify that raw_ref is a literal type, and its entire interface is constexpr.
//
// Constexpr destructors were introduced in C++20. PartitionAlloc's minimum
// supported C++ version is C++17, so raw_ref is not a literal type in C++17.
// Thus we only test for constexpr in C++20.
#if defined(__cpp_constexpr) && __cpp_constexpr >= 201907L
static_assert;
#endif

struct StructWithoutTypeBasedTraits {};
struct BaseWithTypeBasedTraits {};
struct DerivedWithTypeBasedTraits : BaseWithTypeBasedTraits {};

}  // namespace

namespace base::raw_ptr_traits {
// `BaseWithTypeBasedTraits` and any derived classes have
// `RawPtrTraits::kDummyForTest`.
kTypeTraits;
}  // namespace base::raw_ptr_traits

// `raw_ptr<T>` should have traits based on specialization of `kTypeTraits<T>`.
static_assert;
static_assert;
static_assert;

namespace {

TEST(RawRef, Construct) {}

TEST(RawRef, CopyConstruct) {}

TEST(RawRef, MoveConstruct) {}

TEST(RawRef, CopyAssign) {}

TEST(RawRef, CopyReassignAfterMove) {}

TEST(RawRef, MoveAssign) {}

TEST(RawRef, MoveReassignAfterMove) {}

TEST(RawRef, CopyConstructUpCast) {}

TEST(RawRef, MoveConstructUpCast) {}

TEST(RawRef, FromPtr) {}

TEST(RawRef, CopyAssignUpCast) {}

TEST(RawRef, MoveAssignUpCast) {}

TEST(RawRef, Deref) {}

TEST(RawRef, Arrow) {}

TEST(RawRef, Swap) {}

TEST(RawRef, Equals) {}

TEST(RawRef, NotEquals) {}

TEST(RawRef, LessThan) {}

TEST(RawRef, GreaterThan) {}

TEST(RawRef, LessThanOrEqual) {}

TEST(RawRef, GreaterThanOrEqual) {}

// Death Tests: If we're only using the no-op version of `raw_ptr` and
// have `!PA_BUILDFLAG(DCHECKS_ARE_ON)`, the `PA_RAW_PTR_CHECK()`s used in
// `raw_ref` evaluate to nothing. Therefore, death tests relying on
// these CHECKs firing are disabled in their absence.

#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || \
    PA_BUILDFLAG(USE_ASAN_BACKUP_REF_PTR) || PA_BUILDFLAG(DCHECKS_ARE_ON)

TEST(RawRefDeathTest, CopyConstructAfterMove) {}

TEST(RawRefDeathTest, MoveConstructAfterMove) {}

TEST(RawRefDeathTest, CopyAssignAfterMove) {}

TEST(RawRefDeathTest, MoveAssignAfterMove) {}

TEST(RawRefDeathTest, CopyConstructAfterMoveUpCast) {}

TEST(RawRefDeathTest, MoveConstructAfterMoveUpCast) {}

TEST(RawRefDeathTest, FromPtrWithNullptr) {}

TEST(RawRefDeathTest, CopyAssignAfterMoveUpCast) {}

TEST(RawRefDeathTest, MoveAssignAfterMoveUpCast) {}

TEST(RawRefDeathTest, DerefAfterMove) {}

TEST(RawRefDeathTest, ArrowAfterMove) {}

TEST(RawRefDeathTest, SwapAfterMove) {}

TEST(RawRefDeathTest, EqualsAfterMove) {}

TEST(RawRefDeathTest, NotEqualsAfterMove) {}

TEST(RawRefDeathTest, LessThanAfterMove) {}

TEST(RawRefDeathTest, GreaterThanAfterMove) {}

TEST(RawRefDeathTest, LessThanOrEqualAfterMove) {}

TEST(RawRefDeathTest, GreaterThanOrEqualAfterMove) {}

#endif  // PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) ||
        // PA_BUILDFLAG(USE_ASAN_BACKUP_REF_PTR) ||
        // PA_BUILDFLAG(DCHECKS_ARE_ON)

TEST(RawRef, CTAD) {}

TEST(RawRefPtr, CTADWithConst) {}

// Shorter name for expected test impl.
RawPtrCountingImpl;

CountingRawRef;

// Ensure that the `kUseCountingImplForTest` flag selects the test impl.
static_assert;

CountingRawRefMayDangle;

// Ensure that the `kUseCountingImplForTest` flag selects the test impl.
static_assert;

TEST(RawRef, StdLess) {}

// Verifies that comparing `raw_ref`s with different underlying Traits
// is a valid utterance and primarily uses the `GetForComparison()` methods.
TEST(RawRef, OperatorsUseGetForComparison) {}

TEST(RawRef, CrossKindConversion) {}

TEST(RawRef, CrossKindAssignment) {}

#if PA_BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)

TEST(AsanBackupRefPtrImpl, RawRefGet) {
  base::debug::AsanService::GetInstance()->Initialize();

  if (!base::RawPtrAsanService::GetInstance().IsEnabled()) {
    base::RawPtrAsanService::GetInstance().Configure(
        base::EnableDereferenceCheck(true), base::EnableExtractionCheck(true),
        base::EnableInstantiationCheck(true));
  } else {
    ASSERT_TRUE(
        base::RawPtrAsanService::GetInstance().is_dereference_check_enabled());
    ASSERT_TRUE(
        base::RawPtrAsanService::GetInstance().is_extraction_check_enabled());
    ASSERT_TRUE(base::RawPtrAsanService::GetInstance()
                    .is_instantiation_check_enabled());
  }

  auto ptr = ::std::make_unique<int>();
  raw_ref<int> safe_ref(*ptr);
  ptr.reset();

  // This test is specifically to ensure that raw_ref.get() does not cause a
  // dereference of the memory referred to by the reference. If there is a
  // dereference, then this test will crash.
  [[maybe_unused]] volatile int& ref = safe_ref.get();
}

TEST(AsanBackupRefPtrImpl, RawRefOperatorStar) {
  base::debug::AsanService::GetInstance()->Initialize();

  if (!base::RawPtrAsanService::GetInstance().IsEnabled()) {
    base::RawPtrAsanService::GetInstance().Configure(
        base::EnableDereferenceCheck(true), base::EnableExtractionCheck(true),
        base::EnableInstantiationCheck(true));
  } else {
    ASSERT_TRUE(
        base::RawPtrAsanService::GetInstance().is_dereference_check_enabled());
    ASSERT_TRUE(
        base::RawPtrAsanService::GetInstance().is_extraction_check_enabled());
    ASSERT_TRUE(base::RawPtrAsanService::GetInstance()
                    .is_instantiation_check_enabled());
  }

  auto ptr = ::std::make_unique<int>();
  raw_ref<int> safe_ref(*ptr);
  ptr.reset();

  // This test is specifically to ensure that &*raw_ref does not cause a
  // dereference of the memory referred to by the reference. If there is a
  // dereference, then this test will crash.
  [[maybe_unused]] volatile int& ref = *safe_ref;
}

#endif  // PA_BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)

}  // namespace