diff --git a/androidtest/memtag/memtag_test.cc b/androidtest/memtag/memtag_test.cc index 86d5f4ca..d7655d15 100644 --- a/androidtest/memtag/memtag_test.cc +++ b/androidtest/memtag/memtag_test.cc @@ -139,7 +139,7 @@ void tag_distinctness() { p[j]++; } - allocations[i] = addr; + allocations[i] = (uptr) p; } // free some of allocations to allow their slots to be reused diff --git a/h_malloc.c b/h_malloc.c index 46a6d481..3616c9ed 100644 --- a/h_malloc.c +++ b/h_malloc.c @@ -801,7 +801,13 @@ static void enqueue_free_slab(struct size_class *c, struct slab_metadata *metada } // preserves errno -static inline void deallocate_small(void *p, const size_t *expected_size) { +static inline void deallocate_small(void *tagged_p, const size_t *expected_size) { +#ifdef HAS_ARM_MTE + u8 supplied_tag = get_pointer_tag(tagged_p); +#endif + + void *p = untag_pointer(tagged_p); + struct slab_size_class_info size_class_info = slab_size_class(p); size_t class = size_class_info.class; @@ -830,6 +836,14 @@ static inline void deallocate_small(void *p, const size_t *expected_size) { fatal_error("double free"); } +#ifdef HAS_ARM_MTE + if (likely51(is_memtag_enabled())) { + if (unlikely(supplied_tag != get_pointer_tag(__arm_mte_get_tag(p)))) { + fatal_error("invalid free (memory tag)"); + } + } +#endif + if (likely(!is_zero_size)) { check_canary(metadata, p, size); @@ -1684,7 +1698,7 @@ EXPORT void *h_realloc(void *old, size_t size) { } memcpy(new, old_orig, copy_size); if (old_in_slab_region) { - deallocate_small(old, NULL); + deallocate_small(old_orig, NULL); } else { deallocate_large(old, NULL); } @@ -1735,9 +1749,9 @@ EXPORT void h_free(void *p) { return; } - p = untag_pointer(p); + void *untagged_p = untag_pointer(p); - if (p < get_slab_region_end() && p >= ro.slab_region_start) { + if (untagged_p < get_slab_region_end() && untagged_p >= ro.slab_region_start) { thread_unseal_metadata(); deallocate_small(p, NULL); thread_seal_metadata(); @@ -1745,7 +1759,7 @@ EXPORT void h_free(void *p) { } int saved_errno = errno; - deallocate_large(p, NULL); + deallocate_large(untagged_p, NULL); errno = saved_errno; thread_seal_metadata(); @@ -1760,11 +1774,11 @@ EXPORT void h_free_sized(void *p, size_t expected_size) { return; } - p = untag_pointer(p); + void *untagged_p = untag_pointer(p); expected_size = adjust_size_for_canary(expected_size); - if (p < get_slab_region_end() && p >= ro.slab_region_start) { + if (untagged_p < get_slab_region_end() && untagged_p >= ro.slab_region_start) { if (unlikely(expected_size > max_slab_size_class)) { fatal_error("sized deallocation mismatch (small)"); } @@ -1777,7 +1791,7 @@ EXPORT void h_free_sized(void *p, size_t expected_size) { } int saved_errno = errno; - deallocate_large(p, &expected_size); + deallocate_large(untagged_p, &expected_size); errno = saved_errno; thread_seal_metadata(); @@ -1788,11 +1802,11 @@ EXPORT void h_free_aligned_sized(void *p, size_t alignment, size_t expected_size return; } - p = untag_pointer(p); + void *untagged_p = untag_pointer(p); expected_size = adjust_size_for_canary(expected_size); - if (p < get_slab_region_end() && p >= ro.slab_region_start) { + if (untagged_p < get_slab_region_end() && untagged_p >= ro.slab_region_start) { if (unlikely((alignment - 1) & alignment || alignment > PAGE_SIZE)) { fatal_error("invalid sized deallocation alignment (small)"); } @@ -1814,7 +1828,7 @@ EXPORT void h_free_aligned_sized(void *p, size_t alignment, size_t expected_size } int saved_errno = errno; - deallocate_large(p, &expected_size); + deallocate_large(untagged_p, &expected_size); errno = saved_errno; thread_seal_metadata();