aboutsummaryrefslogtreecommitdiff
path: root/src/utils/memory_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/memory_test.cc')
-rw-r--r--src/utils/memory_test.cc184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/utils/memory_test.cc b/src/utils/memory_test.cc
new file mode 100644
index 0000000..42f6a15
--- /dev/null
+++ b/src/utils/memory_test.cc
@@ -0,0 +1,184 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/memory.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <new>
+
+#include "absl/base/config.h"
+#include "gtest/gtest.h"
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+#include <exception>
+#endif
+
+namespace libgav1 {
+namespace {
+
+constexpr size_t kMaxAllocableSize = 0x40000000;
+
+struct Small : public Allocable {
+ uint8_t x;
+};
+
+struct Huge : public Allocable {
+ uint8_t x[kMaxAllocableSize + 1];
+};
+
+struct SmallMaxAligned : public MaxAlignedAllocable {
+ alignas(kMaxAlignment) uint8_t x;
+};
+
+struct HugeMaxAligned : public MaxAlignedAllocable {
+ alignas(kMaxAlignment) uint8_t x[kMaxAllocableSize + 1];
+};
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+struct ThrowingConstructor : public Allocable {
+ ThrowingConstructor() { throw std::exception(); }
+
+ uint8_t x;
+};
+
+struct MaxAlignedThrowingConstructor : public MaxAlignedAllocable {
+ MaxAlignedThrowingConstructor() { throw std::exception(); }
+
+ uint8_t x;
+};
+#endif
+
+TEST(MemoryTest, TestAlignedAllocFree) {
+ for (size_t alignment = 1; alignment <= 1 << 20; alignment <<= 1) {
+ void* p = AlignedAlloc(alignment, 1);
+ // Note this additional check is to avoid an incorrect static-analysis
+ // warning for leaked memory with a plain ASSERT_NE().
+ if (p == nullptr) {
+ FAIL() << "AlignedAlloc(" << alignment << ", 1)";
+ }
+ const auto p_value = reinterpret_cast<uintptr_t>(p);
+ EXPECT_EQ(p_value % alignment, 0)
+ << "AlignedAlloc(" << alignment << ", 1) = " << p;
+ AlignedFree(p);
+ }
+}
+
+TEST(MemoryTest, TestAlignedUniquePtrAlloc) {
+ for (size_t alignment = 1; alignment <= 1 << 20; alignment <<= 1) {
+ auto p = MakeAlignedUniquePtr<uint8_t>(alignment, 1);
+ ASSERT_NE(p, nullptr) << "MakeAlignedUniquePtr(" << alignment << ", 1)";
+ const auto p_value = reinterpret_cast<uintptr_t>(p.get());
+ EXPECT_EQ(p_value % alignment, 0)
+ << "MakeAlignedUniquePtr(" << alignment << ", 1) = " << p.get();
+ }
+}
+
+TEST(MemoryTest, TestAllocable) {
+ // Allocable::operator new (std::nothrow) is called.
+ std::unique_ptr<Small> small(new (std::nothrow) Small);
+ EXPECT_NE(small, nullptr);
+ // Allocable::operator delete is called.
+ small = nullptr;
+
+ // Allocable::operator new[] (std::nothrow) is called.
+ std::unique_ptr<Small[]> small_array_of_smalls(new (std::nothrow) Small[10]);
+ EXPECT_NE(small_array_of_smalls, nullptr);
+ // Allocable::operator delete[] is called.
+ small_array_of_smalls = nullptr;
+
+ // Allocable::operator new (std::nothrow) is called.
+ std::unique_ptr<Huge> huge(new (std::nothrow) Huge);
+ EXPECT_EQ(huge, nullptr);
+
+ // Allocable::operator new[] (std::nothrow) is called.
+ std::unique_ptr<Small[]> huge_array_of_smalls(
+ new (std::nothrow) Small[kMaxAllocableSize / sizeof(Small) + 1]);
+ EXPECT_EQ(huge_array_of_smalls, nullptr);
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+ try {
+ // Allocable::operator new (std::nothrow) is called.
+ // The constructor throws an exception.
+ // Allocable::operator delete (std::nothrow) is called.
+ ThrowingConstructor* always = new (std::nothrow) ThrowingConstructor;
+ static_cast<void>(always);
+ } catch (...) {
+ }
+
+ try {
+ // Allocable::operator new[] (std::nothrow) is called.
+ // The constructor throws an exception.
+ // Allocable::operator delete[] (std::nothrow) is called.
+ ThrowingConstructor* always = new (std::nothrow) ThrowingConstructor[2];
+ static_cast<void>(always);
+ } catch (...) {
+ }
+#endif // ABSL_HAVE_EXCEPTIONS
+}
+
+TEST(MemoryTest, TestMaxAlignedAllocable) {
+ // MaxAlignedAllocable::operator new (std::nothrow) is called.
+ std::unique_ptr<SmallMaxAligned> small(new (std::nothrow) SmallMaxAligned);
+ EXPECT_NE(small, nullptr);
+ // Note this check doesn't guarantee conformance as a suitably aligned
+ // address may be returned from any allocator.
+ EXPECT_EQ(reinterpret_cast<uintptr_t>(small.get()) & (kMaxAlignment - 1), 0);
+ // MaxAlignedAllocable::operator delete is called.
+ small = nullptr;
+
+ // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
+ std::unique_ptr<SmallMaxAligned[]> small_array_of_smalls(
+ new (std::nothrow) SmallMaxAligned[10]);
+ EXPECT_NE(small_array_of_smalls, nullptr);
+ EXPECT_EQ(reinterpret_cast<uintptr_t>(small_array_of_smalls.get()) &
+ (kMaxAlignment - 1),
+ 0);
+ // MaxAlignedAllocable::operator delete[] is called.
+ small_array_of_smalls = nullptr;
+
+ // MaxAlignedAllocable::operator new (std::nothrow) is called.
+ std::unique_ptr<HugeMaxAligned> huge(new (std::nothrow) HugeMaxAligned);
+ EXPECT_EQ(huge, nullptr);
+
+ // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
+ std::unique_ptr<SmallMaxAligned[]> huge_array_of_smalls(
+ new (std::nothrow)
+ SmallMaxAligned[kMaxAllocableSize / sizeof(SmallMaxAligned) + 1]);
+ EXPECT_EQ(huge_array_of_smalls, nullptr);
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+ try {
+ // MaxAlignedAllocable::operator new (std::nothrow) is called.
+ // The constructor throws an exception.
+ // MaxAlignedAllocable::operator delete (std::nothrow) is called.
+ auto* always = new (std::nothrow) MaxAlignedThrowingConstructor;
+ static_cast<void>(always);
+ } catch (...) {
+ }
+
+ try {
+ // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
+ // The constructor throws an exception.
+ // MaxAlignedAllocable::operator delete[] (std::nothrow) is called.
+ auto* always = new (std::nothrow) MaxAlignedThrowingConstructor[2];
+ static_cast<void>(always);
+ } catch (...) {
+ }
+#endif // ABSL_HAVE_EXCEPTIONS
+}
+
+} // namespace
+} // namespace libgav1