mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-17 12:33:54 +02:00
114 lines
3.7 KiB
C++
114 lines
3.7 KiB
C++
//===-- scudo_hooks_test.cpp ------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "tests/scudo_unit_test.h"
|
|
|
|
#include "allocator_config.h"
|
|
#include "combined.h"
|
|
|
|
namespace {
|
|
void *LastAllocatedPtr = nullptr;
|
|
size_t LastRequestSize = 0;
|
|
void *LastDeallocatedPtr = nullptr;
|
|
} // namespace
|
|
|
|
// Scudo defines weak symbols that can be defined by a client binary
|
|
// to register callbacks at key points in the allocation timeline. In
|
|
// order to enforce those invariants, we provide definitions that
|
|
// update some global state every time they are called, so that tests
|
|
// can inspect their effects. An unfortunate side effect of this
|
|
// setup is that because those symbols are part of the binary, they
|
|
// can't be selectively enabled; that means that they will get called
|
|
// on unrelated tests in the same compilation unit. To mitigate this
|
|
// issue, we insulate those tests in a separate compilation unit.
|
|
extern "C" {
|
|
__attribute__((visibility("default"))) void __scudo_allocate_hook(void *Ptr,
|
|
size_t Size) {
|
|
LastAllocatedPtr = Ptr;
|
|
LastRequestSize = Size;
|
|
}
|
|
__attribute__((visibility("default"))) void __scudo_deallocate_hook(void *Ptr) {
|
|
LastDeallocatedPtr = Ptr;
|
|
}
|
|
}
|
|
|
|
// Simple check that allocation callbacks, when registered, are called:
|
|
// 1) __scudo_allocate_hook is called when allocating.
|
|
// 2) __scudo_deallocate_hook is called when deallocating.
|
|
// 3) Both hooks are called when reallocating.
|
|
// 4) Neither are called for a no-op reallocation.
|
|
TEST(ScudoHooksTest, AllocateHooks) {
|
|
scudo::Allocator<scudo::DefaultConfig> Allocator;
|
|
constexpr scudo::uptr DefaultSize = 16U;
|
|
constexpr scudo::Chunk::Origin Origin = scudo::Chunk::Origin::Malloc;
|
|
|
|
// Simple allocation and deallocation.
|
|
{
|
|
LastAllocatedPtr = nullptr;
|
|
LastRequestSize = 0;
|
|
|
|
void *Ptr = Allocator.allocate(DefaultSize, Origin);
|
|
|
|
EXPECT_EQ(Ptr, LastAllocatedPtr);
|
|
EXPECT_EQ(DefaultSize, LastRequestSize);
|
|
|
|
LastDeallocatedPtr = nullptr;
|
|
|
|
Allocator.deallocate(Ptr, Origin);
|
|
|
|
EXPECT_EQ(Ptr, LastDeallocatedPtr);
|
|
}
|
|
|
|
// Simple no-op, same size reallocation.
|
|
{
|
|
void *Ptr = Allocator.allocate(DefaultSize, Origin);
|
|
|
|
LastAllocatedPtr = nullptr;
|
|
LastRequestSize = 0;
|
|
LastDeallocatedPtr = nullptr;
|
|
|
|
void *NewPtr = Allocator.reallocate(Ptr, DefaultSize);
|
|
|
|
EXPECT_EQ(Ptr, NewPtr);
|
|
EXPECT_EQ(nullptr, LastAllocatedPtr);
|
|
EXPECT_EQ(0U, LastRequestSize);
|
|
EXPECT_EQ(nullptr, LastDeallocatedPtr);
|
|
}
|
|
|
|
// Reallocation in increasing size classes. This ensures that at
|
|
// least one of the reallocations will be meaningful.
|
|
{
|
|
void *Ptr = Allocator.allocate(0, Origin);
|
|
|
|
for (scudo::uptr ClassId = 1U;
|
|
ClassId <= scudo::DefaultConfig::Primary::SizeClassMap::LargestClassId;
|
|
++ClassId) {
|
|
const scudo::uptr Size =
|
|
scudo::DefaultConfig::Primary::SizeClassMap::getSizeByClassId(
|
|
ClassId);
|
|
|
|
LastAllocatedPtr = nullptr;
|
|
LastRequestSize = 0;
|
|
LastDeallocatedPtr = nullptr;
|
|
|
|
void *NewPtr = Allocator.reallocate(Ptr, Size);
|
|
|
|
if (NewPtr != Ptr) {
|
|
EXPECT_EQ(NewPtr, LastAllocatedPtr);
|
|
EXPECT_EQ(Size, LastRequestSize);
|
|
EXPECT_EQ(Ptr, LastDeallocatedPtr);
|
|
} else {
|
|
EXPECT_EQ(nullptr, LastAllocatedPtr);
|
|
EXPECT_EQ(0U, LastRequestSize);
|
|
EXPECT_EQ(nullptr, LastDeallocatedPtr);
|
|
}
|
|
|
|
Ptr = NewPtr;
|
|
}
|
|
}
|
|
}
|