Skip to content

Commit 6a27594

Browse files
Tamir Dubersteinfacebook-github-bot
authored andcommitted
Use __cpp_aligned_new instead of hand-rolling the implementation (#11293)
Summary: The current feature detection seems to be incorrect, resulting in fallback to the manual implementation, which in turn returns untagged pointers under hwasan. Use new expressions instead to delegate the work to the C++ compiler. Differential Revision: D75806635
1 parent 4348319 commit 6a27594

File tree

4 files changed

+34
-109
lines changed

4 files changed

+34
-109
lines changed

.github/workflows/pull.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ jobs:
406406
output=$(ls -la cmake-out/test/size_test)
407407
arr=($output)
408408
size=${arr[4]}
409-
threshold="47560"
409+
threshold="47568"
410410
if [[ "$size" -le "$threshold" ]]; then
411411
echo "Success $size <= $threshold"
412412
else

extension/data_loader/file_data_loader.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,13 @@ namespace {
115115
/**
116116
* FreeableBuffer::FreeFn-compatible callback.
117117
*
118-
* `context` is the original buffer pointer. It is allocated with
119-
* ET_ALIGNED_ALLOC, and must be freed with ET_ALIGNED_FREE.
118+
* `data` is the original buffer pointer.
119+
* `context` is the original alignment.
120120
*
121-
* `data` and `size` are unused.
121+
* `size` is unused.
122122
*/
123123
void FreeSegment(void* context, void* data, ET_UNUSED size_t size) {
124-
ET_ALIGNED_FREE(context);
124+
et_aligned_free(data, reinterpret_cast<uintptr_t>(context));
125125
}
126126
} // namespace
127127

@@ -149,11 +149,11 @@ Result<FreeableBuffer> FileDataLoader::load(
149149
}
150150

151151
// Allocate memory for the FreeableBuffer.
152-
void* aligned_buffer = ET_ALIGNED_ALLOC(alignment_, size);
152+
void* aligned_buffer = et_aligned_alloc(alignment_, size);
153153
if (aligned_buffer == nullptr) {
154154
ET_LOG(
155155
Error,
156-
"Reading from %s at offset %zu: ET_ALIGNED_ALLOC(%zd, %zd) failed",
156+
"Reading from %s at offset %zu: et_aligned_alloc(%zd, %zd) failed",
157157
file_name_,
158158
offset,
159159
alignment_,
@@ -163,12 +163,16 @@ Result<FreeableBuffer> FileDataLoader::load(
163163

164164
auto err = load_into(offset, size, segment_info, aligned_buffer);
165165
if (err != Error::Ok) {
166-
ET_ALIGNED_FREE(aligned_buffer);
166+
et_aligned_free(aligned_buffer, alignment_);
167167
return err;
168168
}
169169

170-
// Pass the aligned_buffer pointer as context to FreeSegment.
171-
return FreeableBuffer(aligned_buffer, size, FreeSegment, aligned_buffer);
170+
// Pass the alignment as context to FreeSegment.
171+
return FreeableBuffer(
172+
aligned_buffer,
173+
size,
174+
FreeSegment,
175+
reinterpret_cast<void*>(static_cast<uintptr_t>(alignment_)));
172176
}
173177

174178
Result<size_t> FileDataLoader::size() const {

extension/data_loader/file_descriptor_data_loader.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,13 @@ namespace {
126126
/**
127127
* FreeableBuffer::FreeFn-compatible callback.
128128
*
129-
* `context` is the original buffer pointer. It is allocated with
130-
* ET_ALIGNED_ALLOC, and must be freed with ET_ALIGNED_FREE.
129+
* `data` is the original buffer pointer.
130+
* `context` is the original alignment.
131131
*
132-
* `data` and `size` are unused.
132+
* `size` is unused.
133133
*/
134134
void FreeSegment(void* context, void* data, ET_UNUSED size_t size) {
135-
ET_ALIGNED_FREE(context);
135+
et_aligned_free(data, reinterpret_cast<uintptr_t>(context));
136136
}
137137
} // namespace
138138

@@ -160,24 +160,30 @@ Result<FreeableBuffer> FileDescriptorDataLoader::load(
160160
}
161161

162162
// Allocate memory for the FreeableBuffer.
163-
void* aligned_buffer = ET_ALIGNED_ALLOC(alignment_, size);
163+
void* aligned_buffer = et_aligned_alloc(alignment_, size);
164164
if (aligned_buffer == nullptr) {
165165
ET_LOG(
166166
Error,
167-
"Reading from %s at offset %zu: ET_ALIGNED_ALLOC(%zd) failed",
167+
"Reading from %s at offset %zu: et_aligned_alloc(%zd, %zd) failed",
168168
file_descriptor_uri_,
169169
offset,
170+
alignment_,
170171
size);
171172
return Error::MemoryAllocationFailed;
172173
}
173174

174175
auto err = load_into(offset, size, segment_info, aligned_buffer);
175176
if (err != Error::Ok) {
176-
ET_ALIGNED_FREE(aligned_buffer);
177+
et_aligned_free(aligned_buffer, alignment_);
177178
return err;
178179
}
179180

180-
return FreeableBuffer(aligned_buffer, size, FreeSegment, aligned_buffer);
181+
// Pass the alignment as context to FreeSegment.
182+
return FreeableBuffer(
183+
aligned_buffer,
184+
size,
185+
FreeSegment,
186+
reinterpret_cast<void*>(static_cast<uintptr_t>(alignment_)));
181187
}
182188

183189
Result<size_t> FileDescriptorDataLoader::size() const {

runtime/platform/compiler.h

Lines changed: 6 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -171,100 +171,15 @@
171171
using ssize_t = ptrdiff_t;
172172
#endif
173173

174-
/**
175-
* Platform-specific aligned memory allocation and deallocation.
176-
*
177-
* Usage:
178-
* void* ptr = ET_ALIGNED_ALLOC(alignment, size);
179-
* // use ptr...
180-
* ET_ALIGNED_FREE(ptr);
181-
*
182-
* Note: alignment must be a power of 2 and size must be an integral multiple of
183-
* alignment.
184-
*/
185-
#if defined(_MSC_VER)
186-
#include <malloc.h>
187-
#define ET_ALIGNED_ALLOC(alignment, size) \
188-
_aligned_malloc(((size + alignment - 1) & ~(alignment - 1)), (alignment))
189-
#define ET_ALIGNED_FREE(ptr) _aligned_free(ptr)
190-
#elif defined(__APPLE__)
191-
#include <stdlib.h> // For posix_memalign and free
192-
inline void* et_apple_aligned_alloc(size_t alignment, size_t size) {
193-
void* ptr = nullptr;
194-
// The address of the allocated memory must be a multiple of sizeof(void*).
195-
if (alignment < sizeof(void*)) {
196-
alignment = sizeof(void*);
197-
}
198-
if (posix_memalign(
199-
&ptr, alignment, (size + alignment - 1) & ~(alignment - 1)) != 0) {
200-
return nullptr;
201-
}
202-
return ptr;
203-
}
204-
#define ET_ALIGNED_ALLOC(alignment, size) \
205-
et_apple_aligned_alloc((alignment), (size))
206-
#define ET_ALIGNED_FREE(ptr) free(ptr)
207-
#elif __has_builtin(__builtin_aligned_alloc) || defined(_ISOC11_SOURCE)
208-
// Linux and posix systems that support aligned_alloc and are >= C++17.
209-
#include <cstdlib>
210-
#define ET_ALIGNED_ALLOC(alignment, size) \
211-
::aligned_alloc(alignment, (size + alignment - 1) & ~(alignment - 1))
212-
#define ET_ALIGNED_FREE(ptr) free(ptr)
213-
#else
214-
// If the platform doesn't support aligned_alloc, fallback to malloc.
215-
#include <stdint.h>
216-
#include <cstdlib>
217-
inline void* et_aligned_malloc(size_t alignment, size_t size) {
218-
// Place to store the offset to the original pointer.
219-
size_t offset_size = sizeof(uint16_t);
220-
221-
// Malloc extra space for offset + alignment.
222-
size_t alloc_size = size + offset_size + alignment - 1;
223-
void* ptr = std::malloc(alloc_size);
224-
225-
if (ptr == nullptr) {
226-
// Malloc failed.
227-
return nullptr;
228-
}
229-
230-
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
231-
// Align the address past addr + offset_size bytes.
232-
// This provides space to store the offset before the aligned pointer.
233-
addr = addr + offset_size;
234-
uintptr_t aligned_ptr = (addr + alignment - 1) & ~(alignment - 1);
235-
236-
// Check that alignment didn't overflow the buffer.
237-
if (reinterpret_cast<uintptr_t>(aligned_ptr) + size >
238-
reinterpret_cast<uintptr_t>(ptr) + alloc_size) {
239-
std::free(ptr);
240-
return nullptr;
241-
}
242-
243-
// Store the offset to the original pointer.
244-
// Used to free the original allocated buffer.
245-
*(reinterpret_cast<uint16_t*>(aligned_ptr) - 1) =
246-
(uint16_t)(reinterpret_cast<uintptr_t>(aligned_ptr) -
247-
reinterpret_cast<uintptr_t>(ptr));
248-
249-
return reinterpret_cast<uint16_t*>(aligned_ptr);
250-
}
251-
252-
inline void et_aligned_free(void* ptr) {
253-
if (ptr == nullptr) {
254-
return;
255-
}
174+
#include <new>
256175

257-
// Get the original pointer using the offset.
258-
uint16_t* original_ptr = reinterpret_cast<uint16_t*>(
259-
reinterpret_cast<uintptr_t>(ptr) -
260-
*(reinterpret_cast<uint16_t*>(ptr) - 1));
261-
std::free(original_ptr);
176+
inline void* et_aligned_alloc(size_t alignment, size_t size) {
177+
return ::operator new(size, std::align_val_t(alignment));
262178
}
263179

264-
#define ET_ALIGNED_ALLOC(alignment, size) et_aligned_malloc((alignment), (size))
265-
#define ET_ALIGNED_FREE(ptr) et_aligned_free(ptr)
266-
267-
#endif
180+
inline void et_aligned_free(void* ptr, size_t alignment) {
181+
::operator delete(ptr, std::align_val_t(alignment));
182+
}
268183

269184
// DEPRECATED: Use the non-underscore-prefixed versions instead.
270185
// TODO(T199005537): Remove these once all users have stopped using them.

0 commit comments

Comments
 (0)