xref: /aosp_15_r20/external/libgav1/src/utils/memory_test.cc (revision 095378508e87ed692bf8dfeb34008b65b3735891)
1 // Copyright 2021 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/utils/memory.h"
16 
17 #include <cstddef>
18 #include <cstdint>
19 #include <memory>
20 #include <new>
21 
22 #include "absl/base/config.h"
23 #include "gtest/gtest.h"
24 
25 #ifdef ABSL_HAVE_EXCEPTIONS
26 #include <exception>
27 #endif
28 
29 namespace libgav1 {
30 namespace {
31 
32 constexpr size_t kMaxAllocableSize = 0x40000000;
33 
34 struct Small : public Allocable {
35   uint8_t x;
36 };
37 
38 struct Huge : public Allocable {
39   uint8_t x[kMaxAllocableSize + 1];
40 };
41 
42 struct SmallMaxAligned : public MaxAlignedAllocable {
43   alignas(kMaxAlignment) uint8_t x;
44 };
45 
46 struct HugeMaxAligned : public MaxAlignedAllocable {
47   alignas(kMaxAlignment) uint8_t x[kMaxAllocableSize + 1];
48 };
49 
50 #ifdef ABSL_HAVE_EXCEPTIONS
51 struct ThrowingConstructor : public Allocable {
ThrowingConstructorlibgav1::__anonaea7041f0111::ThrowingConstructor52   ThrowingConstructor() { throw std::exception(); }
53 
54   uint8_t x;
55 };
56 
57 struct MaxAlignedThrowingConstructor : public MaxAlignedAllocable {
MaxAlignedThrowingConstructorlibgav1::__anonaea7041f0111::MaxAlignedThrowingConstructor58   MaxAlignedThrowingConstructor() { throw std::exception(); }
59 
60   uint8_t x;
61 };
62 #endif
63 
TEST(MemoryTest,TestAlignedAllocFree)64 TEST(MemoryTest, TestAlignedAllocFree) {
65   for (size_t alignment = 1; alignment <= 1 << 20; alignment <<= 1) {
66     void* p = AlignedAlloc(alignment, 1);
67     // Note this additional check is to avoid an incorrect static-analysis
68     // warning for leaked memory with a plain ASSERT_NE().
69     if (p == nullptr) {
70       FAIL() << "AlignedAlloc(" << alignment << ", 1)";
71     }
72     const auto p_value = reinterpret_cast<uintptr_t>(p);
73     EXPECT_EQ(p_value % alignment, 0)
74         << "AlignedAlloc(" << alignment << ", 1) = " << p;
75     AlignedFree(p);
76   }
77 }
78 
TEST(MemoryTest,TestAlignedUniquePtrAlloc)79 TEST(MemoryTest, TestAlignedUniquePtrAlloc) {
80   for (size_t alignment = 1; alignment <= 1 << 20; alignment <<= 1) {
81     auto p = MakeAlignedUniquePtr<uint8_t>(alignment, 1);
82     ASSERT_NE(p, nullptr) << "MakeAlignedUniquePtr(" << alignment << ", 1)";
83     const auto p_value = reinterpret_cast<uintptr_t>(p.get());
84     EXPECT_EQ(p_value % alignment, 0)
85         << "MakeAlignedUniquePtr(" << alignment << ", 1) = " << p.get();
86   }
87 }
88 
TEST(MemoryTest,TestAllocable)89 TEST(MemoryTest, TestAllocable) {
90   // Allocable::operator new (std::nothrow) is called.
91   std::unique_ptr<Small> small(new (std::nothrow) Small);
92   EXPECT_NE(small, nullptr);
93   // Allocable::operator delete is called.
94   small = nullptr;
95 
96   // Allocable::operator new[] (std::nothrow) is called.
97   std::unique_ptr<Small[]> small_array_of_smalls(new (std::nothrow) Small[10]);
98   EXPECT_NE(small_array_of_smalls, nullptr);
99   // Allocable::operator delete[] is called.
100   small_array_of_smalls = nullptr;
101 
102   // Allocable::operator new (std::nothrow) is called.
103   std::unique_ptr<Huge> huge(new (std::nothrow) Huge);
104   EXPECT_EQ(huge, nullptr);
105 
106   // Allocable::operator new[] (std::nothrow) is called.
107   std::unique_ptr<Small[]> huge_array_of_smalls(
108       new (std::nothrow) Small[kMaxAllocableSize / sizeof(Small) + 1]);
109   EXPECT_EQ(huge_array_of_smalls, nullptr);
110 
111 #ifdef ABSL_HAVE_EXCEPTIONS
112   try {
113     // Allocable::operator new (std::nothrow) is called.
114     // The constructor throws an exception.
115     // Allocable::operator delete (std::nothrow) is called.
116     ThrowingConstructor* always = new (std::nothrow) ThrowingConstructor;
117     static_cast<void>(always);
118   } catch (...) {
119   }
120 
121   try {
122     // Allocable::operator new[] (std::nothrow) is called.
123     // The constructor throws an exception.
124     // Allocable::operator delete[] (std::nothrow) is called.
125     ThrowingConstructor* always = new (std::nothrow) ThrowingConstructor[2];
126     static_cast<void>(always);
127   } catch (...) {
128   }
129 #endif  // ABSL_HAVE_EXCEPTIONS
130 }
131 
TEST(MemoryTest,TestMaxAlignedAllocable)132 TEST(MemoryTest, TestMaxAlignedAllocable) {
133   // MaxAlignedAllocable::operator new (std::nothrow) is called.
134   std::unique_ptr<SmallMaxAligned> small(new (std::nothrow) SmallMaxAligned);
135   EXPECT_NE(small, nullptr);
136   // Note this check doesn't guarantee conformance as a suitably aligned
137   // address may be returned from any allocator.
138   EXPECT_EQ(reinterpret_cast<uintptr_t>(small.get()) & (kMaxAlignment - 1), 0);
139   // MaxAlignedAllocable::operator delete is called.
140   small = nullptr;
141 
142   // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
143   std::unique_ptr<SmallMaxAligned[]> small_array_of_smalls(
144       new (std::nothrow) SmallMaxAligned[10]);
145   EXPECT_NE(small_array_of_smalls, nullptr);
146   EXPECT_EQ(reinterpret_cast<uintptr_t>(small_array_of_smalls.get()) &
147                 (kMaxAlignment - 1),
148             0);
149   // MaxAlignedAllocable::operator delete[] is called.
150   small_array_of_smalls = nullptr;
151 
152   // MaxAlignedAllocable::operator new (std::nothrow) is called.
153   std::unique_ptr<HugeMaxAligned> huge(new (std::nothrow) HugeMaxAligned);
154   EXPECT_EQ(huge, nullptr);
155 
156   // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
157   std::unique_ptr<SmallMaxAligned[]> huge_array_of_smalls(
158       new (std::nothrow)
159           SmallMaxAligned[kMaxAllocableSize / sizeof(SmallMaxAligned) + 1]);
160   EXPECT_EQ(huge_array_of_smalls, nullptr);
161 
162 #ifdef ABSL_HAVE_EXCEPTIONS
163   try {
164     // MaxAlignedAllocable::operator new (std::nothrow) is called.
165     // The constructor throws an exception.
166     // MaxAlignedAllocable::operator delete (std::nothrow) is called.
167     auto* always = new (std::nothrow) MaxAlignedThrowingConstructor;
168     static_cast<void>(always);
169   } catch (...) {
170   }
171 
172   try {
173     // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
174     // The constructor throws an exception.
175     // MaxAlignedAllocable::operator delete[] (std::nothrow) is called.
176     auto* always = new (std::nothrow) MaxAlignedThrowingConstructor[2];
177     static_cast<void>(always);
178   } catch (...) {
179   }
180 #endif  // ABSL_HAVE_EXCEPTIONS
181 }
182 
183 }  // namespace
184 }  // namespace libgav1
185