blob: 0757442813e6fc1376a6fadeec2a4f1abd5aa4c2 [file] [log] [blame]
// Copyright 2017 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/fxcrt/unowned_ptr.h"
#include <atomic>
#include <functional>
#include <memory>
#include <set>
#include <utility>
#include "core/fxcrt/containers/contains.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(PDF_USE_PARTITION_ALLOC)
#include "partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h"
#endif
namespace fxcrt {
namespace {
template <typename T, typename C = std::less<T>>
class NoLinearSearchSet : public std::set<T, C> {
public:
typename std::set<T, C>::iterator begin() noexcept = delete;
typename std::set<T, C>::const_iterator cbegin() const noexcept = delete;
};
class Clink {
public:
UnownedPtr<Clink> next_ = nullptr;
};
void DeleteDangling() {
auto ptr2 = std::make_unique<Clink>();
{
auto ptr1 = std::make_unique<Clink>();
ptr2->next_ = ptr1.get();
}
}
void AssignDangling() {
auto ptr2 = std::make_unique<Clink>();
{
auto ptr1 = std::make_unique<Clink>();
ptr2->next_ = ptr1.get();
}
ptr2->next_ = nullptr;
}
void ReleaseDangling() {
auto ptr2 = std::make_unique<Clink>();
{
auto ptr1 = std::make_unique<Clink>();
ptr2->next_ = ptr1.get();
}
ptr2->next_.ExtractAsDangling();
}
} // namespace
TEST(UnownedPtr, DefaultCtor) {
UnownedPtr<Clink> ptr;
EXPECT_FALSE(ptr);
}
TEST(UnownedPtr, NullptrCtor) {
UnownedPtr<Clink> ptr(nullptr);
EXPECT_FALSE(ptr);
}
TEST(UnownedPtr, RawCtor) {
auto obj = std::make_unique<Clink>();
UnownedPtr<Clink> ptr(obj.get());
EXPECT_EQ(obj.get(), ptr);
}
TEST(UnownedPtr, CopyCtor) {
std::unique_ptr<Clink> obj = std::make_unique<Clink>();
UnownedPtr<Clink> ptr1(obj.get());
UnownedPtr<Clink> ptr2(ptr1);
EXPECT_EQ(obj.get(), ptr2);
EXPECT_EQ(obj.get(), ptr1);
}
TEST(UnownedPtr, MoveCtor) {
std::unique_ptr<Clink> obj = std::make_unique<Clink>();
UnownedPtr<Clink> ptr1(obj.get());
UnownedPtr<Clink> ptr2(std::move(ptr1));
EXPECT_EQ(obj.get(), ptr2);
EXPECT_FALSE(ptr1);
}
TEST(UnownedPtr, CopyConversionCtor) {
std::unique_ptr<Clink> obj = std::make_unique<Clink>();
UnownedPtr<Clink> ptr1(obj.get());
UnownedPtr<const Clink> ptr2(ptr1);
EXPECT_EQ(obj.get(), ptr2);
EXPECT_EQ(obj.get(), ptr1);
}
TEST(UnownedPtr, MoveConversionCtor) {
std::unique_ptr<Clink> obj = std::make_unique<Clink>();
UnownedPtr<Clink> ptr1(obj.get());
UnownedPtr<const Clink> ptr2(std::move(ptr1));
EXPECT_EQ(obj.get(), ptr2);
EXPECT_FALSE(ptr1);
}
TEST(UnownedPtr, NullptrAssign) {
std::unique_ptr<Clink> obj = std::make_unique<Clink>();
UnownedPtr<Clink> ptr(obj.get());
ptr = nullptr;
EXPECT_FALSE(ptr);
}
TEST(UnownedPtr, RawAssign) {
std::unique_ptr<Clink> obj = std::make_unique<Clink>();
UnownedPtr<Clink> ptr;
ptr = obj.get();
EXPECT_EQ(obj.get(), ptr);
}
TEST(UnownedPtr, CopyAssign) {
std::unique_ptr<Clink> obj = std::make_unique<Clink>();
UnownedPtr<Clink> ptr1(obj.get());
UnownedPtr<Clink> ptr2;
ptr2 = ptr1;
EXPECT_EQ(obj.get(), ptr1);
EXPECT_EQ(obj.get(), ptr2);
}
TEST(UnownedPtr, MoveAssign) {
std::unique_ptr<Clink> obj = std::make_unique<Clink>();
UnownedPtr<Clink> ptr1(obj.get());
UnownedPtr<Clink> ptr2;
ptr2 = std::move(ptr1);
EXPECT_FALSE(ptr1);
EXPECT_EQ(obj.get(), ptr2);
}
TEST(UnownedPtr, CopyConversionAssign) {
std::unique_ptr<Clink> obj = std::make_unique<Clink>();
UnownedPtr<Clink> ptr1(obj.get());
UnownedPtr<const Clink> ptr2;
ptr2 = ptr1;
EXPECT_EQ(obj.get(), ptr1);
EXPECT_EQ(obj.get(), ptr2);
}
TEST(UnownedPtr, MoveConversionAssign) {
std::unique_ptr<Clink> obj = std::make_unique<Clink>();
UnownedPtr<Clink> ptr1(obj.get());
UnownedPtr<const Clink> ptr2;
ptr2 = std::move(ptr1);
EXPECT_FALSE(ptr1);
EXPECT_EQ(obj.get(), ptr2);
}
TEST(UnownedPtr, PtrOk) {
auto ptr1 = std::make_unique<Clink>();
{
auto ptr2 = std::make_unique<Clink>();
ptr2->next_ = ptr1.get();
}
}
TEST(UnownedPtr, PtrNotOk) {
#if defined(UNOWNED_PTR_DANGLING_CHECKS)
EXPECT_DEATH(DeleteDangling(), "");
#else
DeleteDangling();
#endif
}
TEST(UnownedPtr, AssignOk) {
auto ptr1 = std::make_unique<Clink>();
{
auto ptr2 = std::make_unique<Clink>();
ptr2->next_ = ptr1.get();
ptr2->next_ = nullptr;
}
}
TEST(UnownedPtr, AssignNotOk) {
#if defined(UNOWNED_PTR_DANGLING_CHECKS)
EXPECT_DEATH(AssignDangling(), "");
#else
AssignDangling();
#endif
}
TEST(UnownedPtr, ReleaseOk) {
auto ptr2 = std::make_unique<Clink>();
{
auto ptr1 = std::make_unique<Clink>();
ptr2->next_ = ptr1.get();
ptr2->next_.ExtractAsDangling();
}
}
TEST(UnownedPtr, ReleaseNotOk) {
#if defined(UNOWNED_PTR_DANGLING_CHECKS)
EXPECT_DEATH(ReleaseDangling(), "");
#else
ReleaseDangling();
#endif
}
TEST(UnownedPtr, OperatorEQ) {
int foo;
UnownedPtr<int> ptr1;
EXPECT_TRUE(ptr1 == ptr1);
UnownedPtr<int> ptr2;
EXPECT_TRUE(ptr1 == ptr2);
UnownedPtr<int> ptr3(&foo);
EXPECT_TRUE(&foo == ptr3);
EXPECT_TRUE(ptr3 == &foo);
EXPECT_FALSE(ptr1 == ptr3);
ptr1 = &foo;
EXPECT_TRUE(ptr1 == ptr3);
}
TEST(UnownedPtr, OperatorNE) {
int foo;
UnownedPtr<int> ptr1;
EXPECT_FALSE(ptr1 != ptr1);
UnownedPtr<int> ptr2;
EXPECT_FALSE(ptr1 != ptr2);
UnownedPtr<int> ptr3(&foo);
EXPECT_FALSE(&foo != ptr3);
EXPECT_FALSE(ptr3 != &foo);
EXPECT_TRUE(ptr1 != ptr3);
ptr1 = &foo;
EXPECT_FALSE(ptr1 != ptr3);
}
TEST(UnownedPtr, OperatorLT) {
int foos[2];
UnownedPtr<int> ptr1(&foos[0]);
UnownedPtr<int> ptr2(&foos[1]);
EXPECT_FALSE(ptr1 < ptr1);
EXPECT_TRUE(ptr1 < ptr2);
EXPECT_FALSE(ptr2 < ptr1);
}
TEST(UnownedPtr, TransparentCompare) {
int foos[2];
UnownedPtr<int> ptr1(&foos[0]);
UnownedPtr<int> ptr2(&foos[1]);
NoLinearSearchSet<UnownedPtr<int>, std::less<>> holder;
holder.insert(ptr1);
EXPECT_NE(holder.end(), holder.find(&foos[0]));
EXPECT_EQ(holder.end(), holder.find(&foos[1]));
EXPECT_TRUE(pdfium::Contains(holder, &foos[0]));
EXPECT_FALSE(pdfium::Contains(holder, &foos[1]));
}
#if defined(PDF_USE_PARTITION_ALLOC)
#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) && \
!PA_BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS) && \
PA_BUILDFLAG(HAS_64_BIT_POINTERS)
TEST(UnownedPtr, DanglingGetsQuarantined) {
partition_alloc::PartitionRoot* root =
allocator_shim::internal::PartitionAllocMalloc::Allocator();
size_t original_byte_count =
root->total_size_of_brp_quarantined_bytes.load(std::memory_order_relaxed);
auto ptr = std::make_unique<double>(4.0);
UnownedPtr<double> dangler = ptr.get();
EXPECT_EQ(
root->total_size_of_brp_quarantined_bytes.load(std::memory_order_relaxed),
original_byte_count);
ptr.reset();
EXPECT_GE(
root->total_size_of_brp_quarantined_bytes.load(std::memory_order_relaxed),
original_byte_count + sizeof(double));
dangler = nullptr;
EXPECT_EQ(
root->total_size_of_brp_quarantined_bytes.load(std::memory_order_relaxed),
original_byte_count);
}
#endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) ...
#endif // PDF_USE_PARTITION_ALLOC
} // namespace fxcrt