Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 42 additions & 37 deletions h_malloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,42 @@ static void enqueue_free_slab(struct size_class *c, struct slab_metadata *metada
c->free_slabs_tail = substitute;
}

static inline void memory_corruption_check_small(const void *p, const char *unaligned_msg, const char *unused_slot_msg,
const char *quarantine_msg) {
struct slab_size_class_info size_class_info = slab_size_class(p);
size_t class = size_class_info.class;
struct size_class *c = &ro.size_class_metadata[size_class_info.arena][class];
size_t size = c->size;
bool is_zero_size = class == 0;
size_t slab_size = c->slab_size;

mutex_lock(&c->lock);

const struct slab_metadata *metadata = get_metadata(c, p);
void *slab = get_slab(c, slab_size, metadata);
size_t slot = libdivide_u32_do((const char *)p - (const char *)slab, &c->size_divisor);

if (unlikely(slot_pointer(size, slab, slot) != p)) {
fatal_error(unaligned_msg);
}

if (unlikely(!is_used_slot(metadata, slot))) {
fatal_error(unused_slot_msg);
}

if (likely(!is_zero_size)) {
check_canary(metadata, p, size);
}

#if SLAB_QUARANTINE
if (unlikely(is_quarantine_slot(metadata, slot))) {
fatal_error(quarantine_msg);
}
#endif

mutex_unlock(&c->lock);
}

// preserves errno
static inline void deallocate_small(void *p, const size_t *expected_size) {
struct slab_size_class_info size_class_info = slab_size_class(p);
Expand Down Expand Up @@ -1558,10 +1594,13 @@ EXPORT void *h_realloc(void *old, size_t size) {
bool old_in_slab_region = old < get_slab_region_end() && old >= ro.slab_region_start;
if (old_in_slab_region) {
old_size = slab_usable_size(old);
thread_unseal_metadata();
if (size <= max_slab_size_class && get_size_info(size).size == old_size) {
memory_corruption_check_small(old, "invalid unaligned h_realloc",
"invalid h_realloc (unused)", "invalid h_realloc (quarantine)");
thread_seal_metadata();
return old_orig;
}
thread_unseal_metadata();
} else {
enforce_init();
thread_unseal_metadata();
Expand Down Expand Up @@ -1755,41 +1794,6 @@ EXPORT void h_free_sized(void *p, size_t expected_size) {
thread_seal_metadata();
}

static inline void memory_corruption_check_small(const void *p) {
struct slab_size_class_info size_class_info = slab_size_class(p);
size_t class = size_class_info.class;
struct size_class *c = &ro.size_class_metadata[size_class_info.arena][class];
size_t size = c->size;
bool is_zero_size = class == 0;
size_t slab_size = c->slab_size;

mutex_lock(&c->lock);

const struct slab_metadata *metadata = get_metadata(c, p);
void *slab = get_slab(c, slab_size, metadata);
size_t slot = libdivide_u32_do((const char *)p - (const char *)slab, &c->size_divisor);

if (unlikely(slot_pointer(size, slab, slot) != p)) {
fatal_error("invalid unaligned malloc_usable_size");
}

if (unlikely(!is_used_slot(metadata, slot))) {
fatal_error("invalid malloc_usable_size");
}

if (likely(!is_zero_size)) {
check_canary(metadata, p, size);
}

#if SLAB_QUARANTINE
if (unlikely(is_quarantine_slot(metadata, slot))) {
fatal_error("invalid malloc_usable_size (quarantine)");
}
#endif

mutex_unlock(&c->lock);
}

EXPORT size_t h_malloc_usable_size(H_MALLOC_USABLE_SIZE_CONST void *arg) {
if (arg == NULL) {
return 0;
Expand All @@ -1799,7 +1803,8 @@ EXPORT size_t h_malloc_usable_size(H_MALLOC_USABLE_SIZE_CONST void *arg) {

if (p < get_slab_region_end() && p >= ro.slab_region_start) {
thread_unseal_metadata();
memory_corruption_check_small(p);
memory_corruption_check_small(p, "invalid unaligned malloc_usable_size",
"invalid malloc_usable_size (unused)", "invalid malloc_usable_size (quarantine)");
thread_seal_metadata();

size_t size = slab_usable_size(p);
Expand Down
2 changes: 1 addition & 1 deletion test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ EXECUTABLES := \
string_overflow \
delete_type_size_mismatch \
unaligned_malloc_usable_size_small \
invalid_malloc_usable_size_small \
invalid_malloc_usable_size_small_unused \
invalid_malloc_usable_size_small_quarantine \
malloc_object_size \
malloc_object_size_offset \
Expand Down
6 changes: 3 additions & 3 deletions test/test_smc.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,12 @@ def test_invalid_malloc_usable_size_small_quarantine(self):
self.assertEqual(stderr.decode(
"utf-8"), "fatal allocator error: invalid malloc_usable_size (quarantine)\n")

def test_invalid_malloc_usable_size_small(self):
def test_invalid_malloc_usable_size_small_unused(self):
_stdout, stderr, returncode = self.run_test(
"invalid_malloc_usable_size_small")
"invalid_malloc_usable_size_small_unused")
self.assertEqual(returncode, -6)
self.assertEqual(stderr.decode(
"utf-8"), "fatal allocator error: invalid malloc_usable_size\n")
"utf-8"), "fatal allocator error: invalid malloc_usable_size (unused)\n")

def test_read_after_free_large(self):
_stdout, _stderr, returncode = self.run_test("read_after_free_large")
Expand Down