1 // Copyright 2020 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 "tests/utils.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 #include "src/utils/memory.h"
25
26 #ifdef ABSL_HAVE_EXCEPTIONS
27 #include <exception>
28 #endif
29
30 namespace libgav1 {
31 namespace test_utils {
32 namespace {
33
34 constexpr size_t kMaxAllocableSize = 0x40000000;
35
36 // Has a trivial default constructor that performs no action.
37 struct SmallMaxAligned : public MaxAlignedAllocable {
38 alignas(kMaxAlignment) uint8_t x;
39 };
40
41 // Has a nontrivial default constructor that initializes the data member.
42 struct SmallMaxAlignedNontrivialConstructor : public MaxAlignedAllocable {
43 alignas(kMaxAlignment) uint8_t x = 0;
44 };
45
46 // Has a trivial default constructor that performs no action.
47 struct HugeMaxAligned : public MaxAlignedAllocable {
48 alignas(kMaxAlignment) uint8_t x[kMaxAllocableSize + 1];
49 };
50
51 // Has a nontrivial default constructor that initializes the data member.
52 struct HugeMaxAlignedNontrivialConstructor : public MaxAlignedAllocable {
53 alignas(kMaxAlignment) uint8_t x[kMaxAllocableSize + 1] = {};
54 };
55
56 #ifdef ABSL_HAVE_EXCEPTIONS
57 struct MaxAlignedThrowingConstructor : public MaxAlignedAllocable {
MaxAlignedThrowingConstructorlibgav1::test_utils::__anon81aa64620111::MaxAlignedThrowingConstructor58 MaxAlignedThrowingConstructor() { throw std::exception(); }
59
60 uint8_t x;
61 };
62 #endif
63
TEST(TestUtilsTest,TestMaxAlignedAllocable)64 TEST(TestUtilsTest, TestMaxAlignedAllocable) {
65 {
66 // MaxAlignedAllocable::operator new (std::nothrow) is called.
67 std::unique_ptr<SmallMaxAligned> small(new (std::nothrow) SmallMaxAligned);
68 EXPECT_NE(small, nullptr);
69 // Note this check doesn't guarantee conformance as a suitably aligned
70 // address may be returned from any allocator.
71 EXPECT_EQ(reinterpret_cast<uintptr_t>(small.get()) & (kMaxAlignment - 1),
72 0);
73 // MaxAlignedAllocable::operator delete is called.
74 }
75
76 {
77 // MaxAlignedAllocable::operator new is called.
78 std::unique_ptr<SmallMaxAligned> small(new SmallMaxAligned);
79 EXPECT_NE(small, nullptr);
80 // Note this check doesn't guarantee conformance as a suitably aligned
81 // address may be returned from any allocator.
82 EXPECT_EQ(reinterpret_cast<uintptr_t>(small.get()) & (kMaxAlignment - 1),
83 0);
84 // MaxAlignedAllocable::operator delete is called.
85 }
86
87 {
88 // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
89 std::unique_ptr<SmallMaxAligned[]> small_array_of_smalls(
90 new (std::nothrow) SmallMaxAligned[10]);
91 EXPECT_NE(small_array_of_smalls, nullptr);
92 EXPECT_EQ(reinterpret_cast<uintptr_t>(small_array_of_smalls.get()) &
93 (kMaxAlignment - 1),
94 0);
95 // MaxAlignedAllocable::operator delete[] is called.
96 }
97
98 {
99 // MaxAlignedAllocable::operator new[] is called.
100 std::unique_ptr<SmallMaxAligned[]> small_array_of_smalls(
101 new SmallMaxAligned[10]);
102 EXPECT_NE(small_array_of_smalls, nullptr);
103 EXPECT_EQ(reinterpret_cast<uintptr_t>(small_array_of_smalls.get()) &
104 (kMaxAlignment - 1),
105 0);
106 // MaxAlignedAllocable::operator delete[] is called.
107 }
108
109 {
110 // MaxAlignedAllocable::operator new (std::nothrow) is called.
111 std::unique_ptr<HugeMaxAligned> huge(new (std::nothrow) HugeMaxAligned);
112 EXPECT_EQ(huge, nullptr);
113 }
114
115 {
116 // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
117 std::unique_ptr<SmallMaxAligned[]> huge_array_of_smalls(
118 new (std::nothrow)
119 SmallMaxAligned[kMaxAllocableSize / sizeof(SmallMaxAligned) + 1]);
120 EXPECT_EQ(huge_array_of_smalls, nullptr);
121 }
122
123 #ifdef ABSL_HAVE_EXCEPTIONS
124 try {
125 // MaxAlignedAllocable::operator new (std::nothrow) is called.
126 // The constructor throws an exception.
127 // MaxAlignedAllocable::operator delete (std::nothrow) is called.
128 auto* always = new (std::nothrow) MaxAlignedThrowingConstructor;
129 static_cast<void>(always);
130 } catch (...) {
131 }
132
133 try {
134 // MaxAlignedAllocable::operator new is called.
135 // The constructor throws an exception.
136 // MaxAlignedAllocable::operator delete is called.
137 auto* always = new MaxAlignedThrowingConstructor;
138 static_cast<void>(always);
139 } catch (...) {
140 }
141
142 try {
143 // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
144 // The constructor throws an exception.
145 // MaxAlignedAllocable::operator delete[] (std::nothrow) is called.
146 auto* always = new (std::nothrow) MaxAlignedThrowingConstructor[2];
147 static_cast<void>(always);
148 } catch (...) {
149 }
150
151 try {
152 // MaxAlignedAllocable::operator new[] is called.
153 // The constructor throws an exception.
154 // MaxAlignedAllocable::operator delete[] is called.
155 auto* always = new MaxAlignedThrowingConstructor[2];
156 static_cast<void>(always);
157 } catch (...) {
158 }
159
160 // Note these calls are only safe with exceptions enabled as if the throwing
161 // operator new returns the object is expected to be valid. In this case an
162 // attempt to invoke the object's constructor on a nullptr may be made which
163 // is undefined behavior.
164 try {
165 // MaxAlignedAllocable::operator new is called.
166 std::unique_ptr<HugeMaxAlignedNontrivialConstructor> huge(
167 new HugeMaxAlignedNontrivialConstructor);
168 ADD_FAILURE() << "huge allocation should fail.";
169 } catch (...) {
170 SUCCEED();
171 }
172
173 try {
174 // MaxAlignedAllocable::operator new[] is called.
175 std::unique_ptr<SmallMaxAlignedNontrivialConstructor[]>
176 huge_array_of_smalls(
177 new SmallMaxAlignedNontrivialConstructor
178 [kMaxAllocableSize /
179 sizeof(SmallMaxAlignedNontrivialConstructor) +
180 1]);
181 ADD_FAILURE() << "huge_array_of_smalls allocation should fail.";
182 } catch (...) {
183 SUCCEED();
184 }
185 #endif // ABSL_HAVE_EXCEPTIONS
186 }
187
188 } // namespace
189 } // namespace test_utils
190 } // namespace libgav1
191