Skip to content

Commit 8dec751

Browse files
Tamir Dubersteinfacebook-github-bot
Tamir Duberstein
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. Reviewed By: lucylq Differential Revision: D75806635
1 parent af0a246 commit 8dec751

File tree

6 files changed

+63
-122
lines changed

6 files changed

+63
-122
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: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,29 @@ Result<FileDataLoader> FileDataLoader::from(
112112
}
113113

114114
namespace {
115+
116+
inline void* et_aligned_alloc(size_t size, std::align_val_t alignment) {
117+
return ::operator new(size, alignment);
118+
}
119+
120+
inline void et_aligned_free(void* ptr, std::align_val_t alignment) {
121+
return ::operator delete(ptr, alignment);
122+
}
123+
115124
/**
116125
* FreeableBuffer::FreeFn-compatible callback.
117126
*
118-
* `context` is the original buffer pointer. It is allocated with
119-
* ET_ALIGNED_ALLOC, and must be freed with ET_ALIGNED_FREE.
127+
* `data` is the original buffer pointer.
128+
* `context` is the original alignment.
120129
*
121-
* `data` and `size` are unused.
130+
* `size` is unused.
122131
*/
123132
void FreeSegment(void* context, void* data, ET_UNUSED size_t size) {
124-
ET_ALIGNED_FREE(context);
133+
et_aligned_free(
134+
data,
135+
static_cast<std::align_val_t>(reinterpret_cast<uintptr_t>(context)));
125136
}
137+
126138
} // namespace
127139

128140
Result<FreeableBuffer> FileDataLoader::load(
@@ -149,26 +161,31 @@ Result<FreeableBuffer> FileDataLoader::load(
149161
}
150162

151163
// Allocate memory for the FreeableBuffer.
152-
void* aligned_buffer = ET_ALIGNED_ALLOC(alignment_, size);
164+
void* aligned_buffer = et_aligned_alloc(size, alignment_);
153165
if (aligned_buffer == nullptr) {
154166
ET_LOG(
155167
Error,
156-
"Reading from %s at offset %zu: ET_ALIGNED_ALLOC(%zd, %zd) failed",
168+
"Reading from %s at offset %zu: et_aligned_alloc(%zu, %zu) failed",
157169
file_name_,
158170
offset,
159-
alignment_,
160-
size);
171+
size,
172+
static_cast<size_t>(alignment_));
161173
return Error::MemoryAllocationFailed;
162174
}
163175

164176
auto err = load_into(offset, size, segment_info, aligned_buffer);
165177
if (err != Error::Ok) {
166-
ET_ALIGNED_FREE(aligned_buffer);
178+
et_aligned_free(aligned_buffer, alignment_);
167179
return err;
168180
}
169181

170-
// Pass the aligned_buffer pointer as context to FreeSegment.
171-
return FreeableBuffer(aligned_buffer, size, FreeSegment, aligned_buffer);
182+
// Pass the alignment as context to FreeSegment.
183+
return FreeableBuffer(
184+
aligned_buffer,
185+
size,
186+
FreeSegment,
187+
// NOLINTNEXTLINE(performance-no-int-to-ptr)
188+
reinterpret_cast<void*>(static_cast<uintptr_t>(alignment_)));
172189
}
173190

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

extension/data_loader/file_data_loader.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class FileDataLoader final : public executorch::runtime::DataLoader {
5858
fd_(rhs.fd_) {
5959
const_cast<const char*&>(rhs.file_name_) = nullptr;
6060
const_cast<size_t&>(rhs.file_size_) = 0;
61-
const_cast<size_t&>(rhs.alignment_) = 0;
61+
const_cast<std::align_val_t&>(rhs.alignment_) = {};
6262
const_cast<int&>(rhs.fd_) = -1;
6363
}
6464

@@ -86,7 +86,7 @@ class FileDataLoader final : public executorch::runtime::DataLoader {
8686
const char* file_name)
8787
: file_name_(file_name),
8888
file_size_(file_size),
89-
alignment_(alignment),
89+
alignment_{alignment},
9090
fd_(fd) {}
9191

9292
// Not safely copyable.
@@ -96,7 +96,7 @@ class FileDataLoader final : public executorch::runtime::DataLoader {
9696

9797
const char* const file_name_; // Owned by the instance.
9898
const size_t file_size_;
99-
const size_t alignment_;
99+
const std::align_val_t alignment_;
100100
const int fd_; // Owned by the instance.
101101
};
102102

extension/data_loader/file_descriptor_data_loader.cpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,29 @@ FileDescriptorDataLoader::fromFileDescriptorUri(
123123
}
124124

125125
namespace {
126+
127+
inline void* et_aligned_alloc(size_t size, std::align_val_t alignment) {
128+
return ::operator new(size, alignment);
129+
}
130+
131+
inline void et_aligned_free(void* ptr, std::align_val_t alignment) {
132+
return ::operator delete(ptr, alignment);
133+
}
134+
126135
/**
127136
* FreeableBuffer::FreeFn-compatible callback.
128137
*
129-
* `context` is the original buffer pointer. It is allocated with
130-
* ET_ALIGNED_ALLOC, and must be freed with ET_ALIGNED_FREE.
138+
* `data` is the original buffer pointer.
139+
* `context` is the original alignment.
131140
*
132-
* `data` and `size` are unused.
141+
* `size` is unused.
133142
*/
134143
void FreeSegment(void* context, void* data, ET_UNUSED size_t size) {
135-
ET_ALIGNED_FREE(context);
144+
et_aligned_free(
145+
data,
146+
static_cast<std::align_val_t>(reinterpret_cast<uintptr_t>(context)));
136147
}
148+
137149
} // namespace
138150

139151
Result<FreeableBuffer> FileDescriptorDataLoader::load(
@@ -160,24 +172,31 @@ Result<FreeableBuffer> FileDescriptorDataLoader::load(
160172
}
161173

162174
// Allocate memory for the FreeableBuffer.
163-
void* aligned_buffer = ET_ALIGNED_ALLOC(alignment_, size);
175+
void* aligned_buffer = et_aligned_alloc(size, alignment_);
164176
if (aligned_buffer == nullptr) {
165177
ET_LOG(
166178
Error,
167-
"Reading from %s at offset %zu: ET_ALIGNED_ALLOC(%zd) failed",
179+
"Reading from %s at offset %zu: et_aligned_alloc(%zu, %zu) failed",
168180
file_descriptor_uri_,
169181
offset,
170-
size);
182+
size,
183+
static_cast<size_t>(alignment_));
171184
return Error::MemoryAllocationFailed;
172185
}
173186

174187
auto err = load_into(offset, size, segment_info, aligned_buffer);
175188
if (err != Error::Ok) {
176-
ET_ALIGNED_FREE(aligned_buffer);
189+
et_aligned_free(aligned_buffer, alignment_);
177190
return err;
178191
}
179192

180-
return FreeableBuffer(aligned_buffer, size, FreeSegment, aligned_buffer);
193+
// Pass the alignment as context to FreeSegment.
194+
return FreeableBuffer(
195+
aligned_buffer,
196+
size,
197+
FreeSegment,
198+
// NOLINTNEXTLINE(performance-no-int-to-ptr)
199+
reinterpret_cast<void*>(static_cast<uintptr_t>(alignment_)));
181200
}
182201

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

extension/data_loader/file_descriptor_data_loader.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class FileDescriptorDataLoader final : public executorch::runtime::DataLoader {
5656
fd_(rhs.fd_) {
5757
const_cast<const char*&>(rhs.file_descriptor_uri_) = nullptr;
5858
const_cast<size_t&>(rhs.file_size_) = 0;
59-
const_cast<size_t&>(rhs.alignment_) = 0;
59+
const_cast<std::align_val_t&>(rhs.alignment_) = {};
6060
const_cast<int&>(rhs.fd_) = -1;
6161
}
6262

@@ -84,7 +84,7 @@ class FileDescriptorDataLoader final : public executorch::runtime::DataLoader {
8484
const char* file_descriptor_uri)
8585
: file_descriptor_uri_(file_descriptor_uri),
8686
file_size_(file_size),
87-
alignment_(alignment),
87+
alignment_{alignment},
8888
fd_(fd) {}
8989

9090
// Not safely copyable.
@@ -94,7 +94,7 @@ class FileDescriptorDataLoader final : public executorch::runtime::DataLoader {
9494

9595
const char* const file_descriptor_uri_; // Owned by the instance.
9696
const size_t file_size_;
97-
const size_t alignment_;
97+
const std::align_val_t alignment_;
9898
const int fd_; // Owned by the instance.
9999
};
100100

runtime/platform/compiler.h

Lines changed: 0 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -171,101 +171,6 @@
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-
}
256-
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);
262-
}
263-
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
268-
269174
// DEPRECATED: Use the non-underscore-prefixed versions instead.
270175
// TODO(T199005537): Remove these once all users have stopped using them.
271176
#define __ET_DEPRECATED ET_DEPRECATED

0 commit comments

Comments
 (0)