IDA C++ SDK 9.2
Loading...
Searching...
No Matches
qalloc_shim.hpp
Go to the documentation of this file.
1// qalloc_shim.hpp
2#pragma once
3#include <cstddef>
4#include <cstdint>
5#include <cstdlib>
6#include <new>
7#include <type_traits>
8
9// This is for linters that do not understand __cpp_aligned_new
10#if defined(__cpp_aligned_new) && (__cpp_aligned_new >= 201606)
11 #define Q_HAS_ALIGNED_NEW 1
12#else
13 #define Q_HAS_ALIGNED_NEW 0
14#endif
15
16// ---------------------------------------------
17// Policy *concept*
18// ---------------------------------------------
19// Policy must provide:
20// static void *allocate(std::size_t bytes) noexcept;
21// static void deallocate(void *p) noexcept;
22//
23// The aligned path is implemented *here* via a portable bumping shim
24// layered on top of the unaligned functions.
25// See `qida_alloc_shim.hpp` for an example policy (used everywhere but tests).
26// ---------------------------------------------
27
29{
30 // If you call IDA's allocators, they will return pointers aligned to this
31 static constexpr std::size_t k_min_platform_align = alignof(void *);
32
33 // Since IDA does not provide alligned allocators, and C++17 often uses the
34 // concept of aligned allocation, we provide a portable shim here.
35 template<class Policy>
37 {
38 static inline bool is_pow2(std::size_t x) { return x && ((x & (x - 1)) == 0); }
39
40 // This is the main entry point for aligned allocation. Since IDA's
41 // allocators guarantee k_min_platform_align alignment, we only bump for
42 // larger alignments.
43 static void *aligned_allocate(std::size_t n, std::size_t al) noexcept
44 {
45 if ( al <= k_min_platform_align )
46 return Policy::allocate(n);
47 return portable_aligned_alloc(n, al);
48 }
49
50 // Call the above, and throw on failure.
51 static void *aligned_allocate_or_throw(std::size_t n, std::size_t al)
52 {
54 return p;
55 throw std::bad_alloc();
56 }
57
58 // Aligned deallocation: only unbump if a > alignof(void*).
59 static void aligned_deallocate(void *p, std::size_t al) noexcept
60 {
61 if ( !p )
62 return;
63 if ( al <= k_min_platform_align )
64 Policy::deallocate(p);
65 else
66 portable_aligned_free(p);
67 }
68
69 private:
70 // Portable aligned allocation via overallocation + bumping (if needed).
71 static inline void *portable_aligned_alloc(std::size_t size, std::size_t align) noexcept
72 {
73 if ( align < alignof(void *) )
74 align = alignof(void *);
75 if ( !is_pow2(align) )
76 return nullptr;
77 const std::size_t extra = align - 1 + sizeof(void *);
78 if ( size > SIZE_MAX - extra )
79 return nullptr;
80 void *base = Policy::allocate(size + extra);
81 if ( !base )
82 return nullptr;
83 std::uintptr_t raw = reinterpret_cast<std::uintptr_t>(base) + sizeof(void *);
84 std::uintptr_t aligned = (raw + (align - 1)) & ~(static_cast<std::uintptr_t>(align) - 1);
85 reinterpret_cast<void **>(aligned)[-1] = base; // store base just before aligned
86 return reinterpret_cast<void *>(aligned);
87 }
88
89 // Freeing the portable aligned allocation above.
90 static inline void portable_aligned_free(void *p) noexcept
91 {
92 if ( !p )
93 return;
94 void *base = reinterpret_cast<void **>(p)[-1];
95 Policy::deallocate(base);
96 }
97 };
98}
99
100// ---------------------------------------------
101// Class-local new/delete for a *container type*,
102// wired to a *Policy* that only has unaligned hooks.
103// The aligned overloads use the portable shim above.
104// ---------------------------------------------
105// Always-available: scalar/array/placement using unaligned hooks
106#define CXX17_MEMORY_ALLOCATION_FUNCS_USING_UNALIGNED_POLICY(Policy) \
107 /* scalar new/delete via unaligned hooks */ \
108 static void *operator new(std::size_t n) \
109 { \
110 if ( void *p = Policy::allocate(n) ) \
111 return p; \
112 throw std::bad_alloc(); \
113 } \
114 static void operator delete(void *p) noexcept { Policy::deallocate(p); } \
115 static void operator delete(void *p, std::size_t) noexcept { Policy::deallocate(p); } \
116 /* array delegates to scalar (keeps one code path) */ \
117 static void *operator new[](std::size_t n) { return operator new(n); } \
118 static void operator delete[](void *p) noexcept { operator delete(p); } \
119 static void operator delete[](void *p, std::size_t n) noexcept { operator delete(p, n); } \
120 /* placement */ \
121 static void *operator new(std::size_t, void *p) noexcept { return p; } \
122 static void operator delete(void*, void*) noexcept {}
123
124#if Q_HAS_ALIGNED_NEW
125 // Only compiled when aligned new/delete are supported by the toolchain
126#define CXX17_ALIGNED_NEWDELETE_USING_UNALIGNED_POLICY(Policy) \
127 /* aligned scalar new/delete: only bump if a > alignof(void*) */ \
128 static void *operator new(std::size_t n, std::align_val_t a) \
129 { \
130 const std::size_t al = static_cast<std::size_t>(a); \
131 return qalloc_detail::unaligned_alloc_aligner<Policy>::aligned_allocate_or_throw(n, al); \
132 } \
133 static void operator delete(void *p, std::align_val_t a) noexcept \
134 { \
135 const std::size_t al = static_cast<std::size_t>(a); \
136 qalloc_detail::unaligned_alloc_aligner<Policy>::aligned_deallocate(p, al); \
137 } \
138 static void operator delete(void *p, std::size_t, std::align_val_t a) noexcept \
139 { \
140 operator delete(p, a); \
141 } \
142 /* aligned array delegates to aligned scalar */ \
143 static void *operator new[](std::size_t n, std::align_val_t a) { return operator new(n, a); } \
144 static void operator delete[](void *p, std::align_val_t a) noexcept { operator delete(p, a); }\
145 static void operator delete[](void *p, std::size_t n, std::align_val_t a) noexcept \
146 { \
147 operator delete(p, n, a); \
148 }
149#else
150 // No aligned new/delete available: expand to nothing
151#define CXX17_ALIGNED_NEWDELETE_USING_UNALIGNED_POLICY(Policy)
152#endif
153
154// Final convenience macro: unaligned + (conditionally) aligned
155#define CXX17_MEMORY_ALLOCATION_FUNCS_USING_POLICY(Policy) \
156 CXX17_MEMORY_ALLOCATION_FUNCS_USING_UNALIGNED_POLICY(Policy) \
157 CXX17_ALIGNED_NEWDELETE_USING_UNALIGNED_POLICY(Policy)
idaman size_t n
Definition pro.h:1000
asize_t size
Definition kernwin.hpp:6701
Definition qalloc_shim.hpp:29
Definition qalloc_shim.hpp:37
static void * aligned_allocate(std::size_t n, std::size_t al) noexcept
Definition qalloc_shim.hpp:43
static void aligned_deallocate(void *p, std::size_t al) noexcept
Definition qalloc_shim.hpp:59
static void * aligned_allocate_or_throw(std::size_t n, std::size_t al)
Definition qalloc_shim.hpp:51
static bool is_pow2(std::size_t x)
Definition qalloc_shim.hpp:38