Skip to content

Commit cb7244c

Browse files
committed
Merge branch 'main' of https://github.com/cursey/safetyhook
# Conflicts: # include/safetyhook/utility.hpp
2 parents 4c93319 + 60bdee3 commit cb7244c

File tree

3 files changed

+26
-13
lines changed

3 files changed

+26
-13
lines changed

include/safetyhook/allocator.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class Allocation final {
3636

3737
/// @brief Returns the address of the allocation.
3838
/// @return The address of the allocation.
39-
[[nodiscard]] uintptr_t address() const noexcept { return (uintptr_t)m_address; }
39+
[[nodiscard]] uintptr_t address() const noexcept { return reinterpret_cast<uintptr_t>(m_address); }
4040

4141
/// @brief Returns the size of the allocation.
4242
/// @return The size of the allocation.

include/safetyhook/utility.hpp

+13-7
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,16 @@ template <typename T> constexpr void store(uint8_t* address, const T& value) {
1414
std::copy_n(reinterpret_cast<const uint8_t*>(&value), sizeof(T), address);
1515
}
1616

17+
template <typename T> constexpr T address_cast(auto address) {
18+
if constexpr (std::is_integral_v<T> && std::is_integral_v<decltype(address)>) {
19+
return static_cast<T>(address);
20+
} else {
21+
return reinterpret_cast<T>(address);
22+
}
23+
}
1724

18-
//template <typename T>
19-
//concept FnPtr = requires(T f) { std::is_pointer_v<T>&& std::is_function_v<std::remove_pointer_t<T>>; };
20-
typedef void* FnPtr;
25+
template <typename T>
26+
concept FnPtr = requires(T f) { std::is_pointer_v<T>&& std::is_function_v<std::remove_pointer_t<T>>; };
2127

2228
bool is_executable(uint8_t* address);
2329

@@ -44,14 +50,14 @@ class UnprotectMemory {
4450
[[nodiscard]] std::optional<UnprotectMemory> unprotect(uint8_t* address, size_t size);
4551

4652
template <typename T> constexpr T align_up(T address, size_t align) {
47-
const auto unaligned_address = (uintptr_t)address;
53+
const auto unaligned_address = address_cast<uintptr_t>(address);
4854
const auto aligned_address = (unaligned_address + align - 1) & ~(align - 1);
49-
return (T)aligned_address;
55+
return address_cast<T>(aligned_address);
5056
}
5157

5258
template <typename T> constexpr T align_down(T address, size_t align) {
53-
const auto unaligned_address = (uintptr_t)address;
59+
const auto unaligned_address = address_cast<uintptr_t>(address);
5460
const auto aligned_address = unaligned_address & ~(align - 1);
55-
return (T)aligned_address;
61+
return address_cast<T>(aligned_address);
5662
}
5763
} // namespace safetyhook

src/allocator.cpp

+12-5
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,20 @@ void Allocator::free(uint8_t* address, size_t size) {
8484

8585
std::expected<Allocation, Allocator::Error> Allocator::internal_allocate_near(
8686
const std::vector<uint8_t*>& desired_addresses, size_t size, size_t max_distance) {
87+
// Align to 2 bytes to pass MFP virtual method check
88+
// See https://itanium-cxx-abi.github.io/cxx-abi/abi.html#member-function-pointers
89+
size_t aligned_size = align_up(size, 2);
90+
8791
// First search through our list of allocations for a free block that is large
8892
// enough.
8993
for (const auto& allocation : m_memory) {
90-
if (allocation->size < size) {
94+
if (allocation->size < aligned_size) {
9195
continue;
9296
}
9397

9498
for (auto node = allocation->freelist.get(); node != nullptr; node = node->next.get()) {
9599
// Enough room?
96-
if (static_cast<size_t>(node->end - node->start) < size) {
100+
if (static_cast<size_t>(node->end - node->start) < aligned_size) {
97101
continue;
98102
}
99103

@@ -104,14 +108,14 @@ std::expected<Allocation, Allocator::Error> Allocator::internal_allocate_near(
104108
continue;
105109
}
106110

107-
node->start += size;
111+
node->start += aligned_size;
108112

109113
return Allocation{shared_from_this(), address, size};
110114
}
111115
}
112116

113117
// If we didn't find a free block, we need to allocate a new one.
114-
auto allocation_size = align_up(size, system_info().allocation_granularity);
118+
auto allocation_size = align_up(aligned_size, system_info().allocation_granularity);
115119
auto allocation_address = allocate_nearby_memory(desired_addresses, allocation_size, max_distance);
116120

117121
if (!allocation_address) {
@@ -123,13 +127,16 @@ std::expected<Allocation, Allocator::Error> Allocator::internal_allocate_near(
123127
allocation->address = *allocation_address;
124128
allocation->size = allocation_size;
125129
allocation->freelist = std::make_unique<FreeNode>();
126-
allocation->freelist->start = *allocation_address + size;
130+
allocation->freelist->start = *allocation_address + aligned_size;
127131
allocation->freelist->end = *allocation_address + allocation_size;
128132

129133
return Allocation{shared_from_this(), *allocation_address, size};
130134
}
131135

132136
void Allocator::internal_free(uint8_t* address, size_t size) {
137+
// See internal_allocate_near
138+
size = align_up(size, 2);
139+
133140
for (const auto& allocation : m_memory) {
134141
if (allocation->address > address || allocation->address + allocation->size < address) {
135142
continue;

0 commit comments

Comments
 (0)