Skip to content

Commit d870a7c

Browse files
committed
implement h_free_aligned_sized from the C standard
1 parent 212947c commit d870a7c

10 files changed

Lines changed: 125 additions & 4 deletions

h_malloc.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,6 +1755,40 @@ EXPORT void h_free_sized(void *p, size_t expected_size) {
17551755
thread_seal_metadata();
17561756
}
17571757

1758+
EXPORT void h_free_aligned_sized(void *p, size_t alignment, size_t expected_size) {
1759+
if (p == NULL) {
1760+
return;
1761+
}
1762+
1763+
p = untag_pointer(p);
1764+
1765+
expected_size = adjust_size_for_canary(expected_size);
1766+
1767+
if (p < get_slab_region_end() && p >= ro.slab_region_start) {
1768+
if (unlikely((alignment - 1) & alignment || alignment > PAGE_SIZE)) {
1769+
fatal_error("invalid sized deallocation alignment (small)");
1770+
}
1771+
if (unlikely(expected_size > max_slab_size_class)) {
1772+
fatal_error("sized deallocation mismatch (small)");
1773+
}
1774+
1775+
if (alignment > min_align) {
1776+
expected_size = get_size_info_align(expected_size, alignment).size;
1777+
} else {
1778+
expected_size = get_size_info(expected_size).size;
1779+
}
1780+
1781+
thread_unseal_metadata();
1782+
deallocate_small(p, &expected_size);
1783+
thread_seal_metadata();
1784+
return;
1785+
}
1786+
1787+
deallocate_large(p, &expected_size);
1788+
1789+
thread_seal_metadata();
1790+
}
1791+
17581792
static inline void memory_corruption_check_small(const void *p) {
17591793
struct slab_size_class_info size_class_info = slab_size_class(p);
17601794
size_t class = size_class_info.class;

include/h_malloc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ extern "C" {
4545
#define h_malloc_object_size malloc_object_size
4646
#define h_malloc_object_size_fast malloc_object_size_fast
4747
#define h_free_sized free_sized
48+
#define h_free_aligned_sized free_aligned_sized
4849
#endif
4950

5051
// C standard
@@ -121,6 +122,7 @@ size_t h_malloc_object_size_fast(const void *ptr);
121122
// allocator implementation uses it to improve security by checking that the
122123
// passed size matches the allocated size.
123124
void h_free_sized(void *ptr, size_t expected_size);
125+
void h_free_aligned_sized(void *p, size_t alignment, size_t expected_size);
124126

125127
#ifdef __cplusplus
126128
}

new.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,10 @@ EXPORT void operator delete[](void *ptr, std::align_val_t, const std::nothrow_t
146146
h_free(ptr);
147147
}
148148

149-
EXPORT void operator delete(void *ptr, size_t size, std::align_val_t) noexcept {
150-
h_free_sized(ptr, size);
149+
EXPORT void operator delete(void *ptr, size_t size, std::align_val_t alignment) noexcept {
150+
h_free_aligned_sized(ptr, static_cast<size_t>(alignment), size);
151151
}
152152

153-
EXPORT void operator delete[](void *ptr, size_t size, std::align_val_t) noexcept {
154-
h_free_sized(ptr, size);
153+
EXPORT void operator delete[](void *ptr, size_t size, std::align_val_t alignment) noexcept {
154+
h_free_aligned_sized(ptr, static_cast<size_t>(alignment), size);
155155
}

test/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ EXECUTABLES := \
5959
overflow_small_8_byte \
6060
string_overflow \
6161
delete_type_size_mismatch \
62+
aligned_sized_delete_small \
63+
aligned_sized_delete_small_min_align \
64+
invalid_aligned_sized_delete_small \
65+
aligned_sized_delete_large \
66+
invalid_aligned_sized_delete_large \
6267
unaligned_malloc_usable_size_small \
6368
invalid_malloc_usable_size_small \
6469
invalid_malloc_usable_size_small_quarantine \

test/aligned_sized_delete_large.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <new>
2+
3+
struct alignas(8192) S {
4+
char x[9000];
5+
};
6+
7+
int main() {
8+
S *p = new S;
9+
operator delete(p, sizeof(S), std::align_val_t(alignof(S)));
10+
}

test/aligned_sized_delete_small.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <new>
2+
3+
struct alignas(64) S {
4+
char x[24];
5+
};
6+
7+
int main() {
8+
S *p = new S;
9+
operator delete(p, sizeof(S), std::align_val_t(alignof(S)));
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include "../include/h_malloc.h"
2+
3+
int main(void) {
4+
void *p = NULL;
5+
if (posix_memalign(&p, 16, 0) != 0) {
6+
return 1;
7+
}
8+
9+
free_aligned_sized(p, 16, 0);
10+
return 0;
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <new>
2+
3+
struct alignas(8192) S {
4+
char x[9000];
5+
};
6+
7+
int main() {
8+
S *p = new S;
9+
operator delete(p, sizeof(S) - 10, std::align_val_t(alignof(S)));
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <new>
2+
3+
struct alignas(64) S {
4+
char x[24];
5+
};
6+
7+
int main() {
8+
S *p = new S;
9+
operator delete(p, sizeof(S) + 64, std::align_val_t(alignof(S)));
10+
}

test/test_smc.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,35 @@ def test_delete_type_size_mismatch(self):
2222
self.assertEqual(stderr.decode(
2323
"utf-8"), "fatal allocator error: sized deallocation mismatch (small)\n")
2424

25+
def test_aligned_sized_delete_small(self):
26+
_stdout, _stderr, returncode = self.run_test(
27+
"aligned_sized_delete_small")
28+
self.assertEqual(returncode, 0)
29+
30+
def test_aligned_sized_delete_small_min_align(self):
31+
_stdout, _stderr, returncode = self.run_test(
32+
"aligned_sized_delete_small_min_align")
33+
self.assertEqual(returncode, 0)
34+
35+
def test_invalid_aligned_sized_delete_small(self):
36+
_stdout, stderr, returncode = self.run_test(
37+
"invalid_aligned_sized_delete_small")
38+
self.assertEqual(returncode, -6)
39+
self.assertEqual(stderr.decode(
40+
"utf-8"), "fatal allocator error: sized deallocation mismatch (small)\n")
41+
42+
def test_aligned_sized_delete_large(self):
43+
_stdout, _stderr, returncode = self.run_test(
44+
"aligned_sized_delete_large")
45+
self.assertEqual(returncode, 0)
46+
47+
def test_invalid_aligned_sized_delete_large(self):
48+
_stdout, stderr, returncode = self.run_test(
49+
"invalid_aligned_sized_delete_large")
50+
self.assertEqual(returncode, -6)
51+
self.assertEqual(stderr.decode(
52+
"utf-8"), "fatal allocator error: sized deallocation mismatch (large)\n")
53+
2554
def test_double_free_large_delayed(self):
2655
_stdout, stderr, returncode = self.run_test(
2756
"double_free_large_delayed")

0 commit comments

Comments
 (0)