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