Loading...
--- libmalloc/libmalloc-521.100.59/src/sanitizer_malloc.c
+++ libmalloc/libmalloc-792.80.2/src/sanitizer_malloc.c
@@ -21,9 +21,6 @@
* @APPLE_LICENSE_HEADER_END@
*/
-#include <malloc/_platform.h>
-#include <stddef.h>
-
#include "internal.h"
#if CONFIG_SANITIZER
@@ -126,7 +123,7 @@
kern_return_t kr = mach_vm_map(target, &address, size_rounded, mask, flags,
object, offset, copy, cur_protection, max_protection, inheritance);
MALLOC_ASSERT(kr == KERN_SUCCESS);
- return address;
+ return (vm_address_t)address;
}
static void
@@ -193,7 +190,7 @@
ssize_t num_pcs = backtrace(pcs, countof(pcs));
#else
uint32_t num_pcs;
- thread_stack_pcs((uintptr_t *)pcs, (unsigned)countof(pcs), &num_pcs);
+ thread_stack_pcs((vm_address_t *)pcs, (unsigned)countof(pcs), &num_pcs);
#endif // MALLOC_TARGET_EXCLAVES
if (num_pcs <= top_frames_to_ignore) {
return 0;
@@ -343,12 +340,16 @@
if (zone->debug) malloc_report(ASL_LEVEL_INFO, "evicting %p from quarantine, size = 0x%lx\n", iterator, iterator_size);
+ // Forge the pointer because it is only sized for quarantined_chunk_t
+ void *iterator_ptr = __unsafe_forge_bidi_indexable(void *, iterator,
+ iterator_size);
+
// Same as above, perform actual unpoisoning
if (zone->do_poisoning) {
- unpoison(zone, iterator, iterator_size);
+ unpoison(zone, iterator_ptr, iterator_size);
}
- DELEGATE(free_definite_size, iterator, iterator_size);
+ DELEGATE(free_definite_size, iterator_ptr, iterator_size);
iterator = next;
}
@@ -384,7 +385,9 @@
murmur2_add_uintptr(uint32_t *hstate, uintptr_t ptr)
{
murmur2_add_uint32(hstate, (uint32_t)ptr);
+#if MALLOC_TARGET_64BIT
murmur2_add_uint32(hstate, (uint32_t)(ptr >> 32));
+#endif
}
static uint32_t
@@ -474,7 +477,7 @@
uint32_t index_pos = wrap(hash, depo->index);
index_entry entry;
- entry.i = os_atomic_load(&depo->index[index_pos], relaxed);
+ entry.i = os_atomic_load_wide(&depo->index[index_pos], relaxed);
if (entry.parts.count == count && entry.parts.hash == hash) {
return hash;
}
@@ -484,10 +487,10 @@
entry.parts.hash = hash;
entry.parts.pos = (uint32_t)old_storage_pos;
entry.parts.count = (uint32_t)count;
- os_atomic_store(&depo->index[index_pos], entry.i, relaxed);
+ os_atomic_store_wide(&depo->index[index_pos], entry.i, relaxed);
for (int i = 0; i < count; i++) {
uint32_t pos = wrap(old_storage_pos + i, depo->storage);
- os_atomic_store(&depo->storage[pos], pcs[i], relaxed);
+ os_atomic_store_wide(&depo->storage[pos], pcs[i], relaxed);
}
return hash;
}
@@ -509,7 +512,8 @@
for (int i = 0; i < entry.parts.count; i++) {
uint32_t pos = wrap(entry.parts.pos + i, depo->storage);
if (i < max_size) {
- pcs[i] = depo->storage[pos];
+ // Explicit cast as it doesn't otherwise compile on watchOS (error: implicit conversion loses integer precision)
+ pcs[i] = (uintptr_t)depo->storage[pos];
}
murmur2_add_uintptr(&hstate, pcs[i]);
}
@@ -604,7 +608,12 @@
// checks against the shadow map, instead of letting the compiled program's
// instrumentation handle it. This means we need to bypass it since the size
// is stored within the allocation redzone
- const size_t redzone_size = _malloc_read_uint64_via_rsp(redzone_size_ptr);
+ // Explicit cast as it doesn't otherwise compile on watchOS (error: implicit conversion loses integer precision)
+#if MALLOC_TARGET_64BIT
+ const size_t redzone_size = (size_t)_malloc_read_uint64_via_rsp(redzone_size_ptr);
+#else
+ const size_t redzone_size = (size_t)*(uint32_t *)redzone_size_ptr;
+#endif
MALLOC_ASSERT(redzone_size >= zone->redzone_size && redzone_size < size);
return redzone_size;
}
@@ -616,7 +625,11 @@
sizeof(size_t) + (usr_size + redzone_size) % sizeof(size_t);
size_t *redzone_size_ptr = ptr + (usr_size + redzone_size - offset);
// Same as above, this may be a reallocation that has not yet been unpoisoned
+#if MALLOC_TARGET_64BIT
_malloc_write_uint64_via_rsp(redzone_size_ptr, redzone_size);
+#else
+ *(uint32_t *)redzone_size_ptr = redzone_size;
+#endif
}
static void poison_alloc(sanitizer_zone_t *zone, void * __sized_by(usr_size + redzone_size) ptr, size_t usr_size, size_t redzone_size)
@@ -671,6 +684,10 @@
sanitizer_size(sanitizer_zone_t *zone, const void * __unsafe_indexable ptr)
{
size_t size = DELEGATE(size, ptr);
+ if (!size) {
+ return 0;
+ }
+
if (zone->do_poisoning) {
const size_t redzone_size = get_redzone_size(zone, __unsafe_forge_bidi_indexable(void *, ptr, size), size);
if (zone->debug) malloc_report(ASL_LEVEL_INFO, "size(%p) = 0x%lx - redzone 0x%lx\n", ptr, size, redzone_size);
@@ -683,9 +700,14 @@
return size;
}
-static void * __alloc_size(2)
-sanitizer_malloc(sanitizer_zone_t *zone, size_t size)
-{
+static void * __alloc_size(2) __sized_by_or_null(size)
+sanitizer_malloc_type_malloc_noalign_with_options(sanitizer_zone_t *zone,
+ size_t size, malloc_zone_malloc_options_t options,
+ malloc_type_id_t type_id)
+{
+ if (!size) {
+ size = 1;
+ }
size_t redzone_size = zone->redzone_size;
const size_t usr_size = size;
if (zone->do_poisoning) {
@@ -700,7 +722,60 @@
return NULL;
}
}
- void *ptr = DELEGATE(malloc, size);
+
+ void *ptr;
+#if MALLOC_TARGET_64BIT
+ malloc_type_descriptor_t type_desc = { .type_id = type_id };
+#endif // MALLOC_TARGET_64BIT
+ if (zone->wrapped_zone->version >= 16) {
+ if (zone->wrapped_zone->malloc_type_malloc_with_options) {
+ // Dispatch directly with pass-thru options
+ ptr = DELEGATE(malloc_type_malloc_with_options, 0, size, options,
+ type_id);
+ } else if (options & MALLOC_ZONE_MALLOC_OPTION_CLEAR) {
+ // Need fallback for this option
+ ptr = DELEGATE(malloc_type_calloc, 1, size, type_id);
+ } else {
+ // Remaining options already handled in parent, ignore them
+ ptr = DELEGATE(malloc_type_malloc, size, type_id);
+ }
+ } else if (zone->wrapped_zone->version >= 15 &&
+ zone->wrapped_zone->malloc_with_options) {
+ // Dispatch directly with type TSD and pass-thru options
+#if MALLOC_TARGET_64BIT
+ malloc_set_tsd_type_descriptor(type_desc);
+#endif // MALLOC_TARGET_64BIT
+ ptr = DELEGATE(malloc_with_options, 0, size, options);
+#if MALLOC_TARGET_64BIT
+ malloc_set_tsd_type_descriptor(MALLOC_TYPE_DESCRIPTOR_NONE);
+#endif // MALLOC_TARGET_64BIT
+ } else {
+ const malloc_zone_malloc_options_t known_options =
+ MALLOC_ZONE_MALLOC_OPTION_CLEAR
+ ;
+ if (options & ~known_options) {
+ malloc_zone_error(MALLOC_ABORT_ON_ERROR, true,
+ "sanitizer_malloc_with_options: unsupported options 0x%llx\n",
+ options);
+ __builtin_trap();
+ }
+
+ // Set the type TSD and check the options
+#if MALLOC_TARGET_64BIT
+ malloc_set_tsd_type_descriptor(type_desc);
+#endif // MALLOC_TARGET_64BIT
+ if (options & MALLOC_ZONE_MALLOC_OPTION_CLEAR) {
+ // Need fallback for this option
+ ptr = DELEGATE(calloc, 1, size);
+ } else {
+ // Remaining options already handled in parent, ignore them
+ ptr = DELEGATE(malloc, size);
+ }
+#if MALLOC_TARGET_64BIT
+ malloc_set_tsd_type_descriptor(MALLOC_TYPE_DESCRIPTOR_NONE);
+#endif // MALLOC_TARGET_64BIT
+ }
+
#if !MALLOC_TARGET_EXCLAVES
record_alloc_stacktrace(zone->depo, zone->map, ptr, usr_size);
#endif /* !MALLOC_TARGET_EXCLAVES */
@@ -717,11 +792,29 @@
return ptr;
}
-static void * __alloc_size(2,3)
-sanitizer_calloc(sanitizer_zone_t *zone, size_t num_items, size_t size)
+static void * __alloc_size(2) __sized_by_or_null(size)
+sanitizer_malloc(sanitizer_zone_t *zone, size_t size)
+{
+ return sanitizer_malloc_type_malloc_noalign_with_options(zone, size, 0,
+ malloc_get_tsd_type_id());
+}
+
+static void * __alloc_size(2) __sized_by_or_null(size)
+sanitizer_malloc_type_malloc(sanitizer_zone_t *zone, size_t size,
+ malloc_type_id_t type_id)
+{
+ return sanitizer_malloc_type_malloc_noalign_with_options(zone, size, 0,
+ type_id);
+}
+
+static void * __alloc_size(2,3) __sized_by_or_null(num_items * size)
+sanitizer_malloc_type_calloc(sanitizer_zone_t *zone, size_t num_items,
+ size_t size, malloc_type_id_t type_id)
{
size_t usr_size;
- if (calloc_get_size(num_items, size, 0, &usr_size)) {
+ if (!size || !num_items) {
+ usr_size = 1;
+ } else if (calloc_get_size(num_items, size, 0, &usr_size)) {
malloc_set_errno_fast(MZ_POSIX, ENOMEM);
return NULL;
}
@@ -739,7 +832,23 @@
return NULL;
}
}
- void *ptr = __unsafe_forge_bidi_indexable(void *, DELEGATE(calloc, num_items, size), usr_size);
+
+ void *ptr;
+ if (zone->wrapped_zone->version >= 16) {
+ ptr = __unsafe_forge_bidi_indexable(void *,
+ DELEGATE(malloc_type_calloc, num_items, size, type_id), usr_size);
+ } else {
+#if MALLOC_TARGET_64BIT
+ malloc_set_tsd_type_descriptor(
+ (malloc_type_descriptor_t){ .type_id = type_id });
+#endif // MALLOC_TARGET_64BIT
+ ptr = __unsafe_forge_bidi_indexable(void *,
+ DELEGATE(calloc, num_items, size), usr_size);
+#if MALLOC_TARGET_64BIT
+ malloc_set_tsd_type_descriptor(MALLOC_TYPE_DESCRIPTOR_NONE);
+#endif // MALLOC_TARGET_64BIT
+ }
+
if (zone->debug) malloc_report(ASL_LEVEL_INFO, "calloc(0x%lx, 0x%lx) = %p\n", num_items, size, ptr);
#if !MALLOC_TARGET_EXCLAVES
record_alloc_stacktrace(zone->depo, zone->map, ptr, usr_size);
@@ -756,9 +865,20 @@
return ptr;
}
-static void * __alloc_size(2)
+
+static void * __alloc_size(2,3) __sized_by_or_null(num_items * size)
+sanitizer_calloc(sanitizer_zone_t *zone, size_t num_items, size_t size)
+{
+ return sanitizer_malloc_type_calloc(zone, num_items, size,
+ malloc_get_tsd_type_id());
+}
+
+static void * __alloc_size(2) __sized_by_or_null(size)
sanitizer_valloc(sanitizer_zone_t *zone, size_t size)
{
+ if (!size) {
+ size = 1;
+ }
size_t redzone_size = zone->redzone_size;
const size_t usr_size = size;
if (zone->do_poisoning) {
@@ -791,6 +911,10 @@
static void
sanitizer_free(sanitizer_zone_t *zone, void * __unsafe_indexable ptr)
{
+ if (os_unlikely(!ptr)) {
+ return;
+ }
+
size_t size = 0;
if (zone->do_poisoning) {
size = DELEGATE(size, ptr);
@@ -800,8 +924,10 @@
place_into_quarantine(zone, ptr, size);
}
-static void * __alloc_size(3)
-sanitizer_realloc(sanitizer_zone_t *zone, void * __unsafe_indexable ptr, size_t new_size)
+static void * __alloc_size(3) __sized_by_or_null(new_size)
+sanitizer_malloc_type_realloc(sanitizer_zone_t *zone,
+ void * __unsafe_indexable ptr, size_t new_size,
+ malloc_type_id_t type_id)
{
if (new_size == 0) {
new_size = 1;
@@ -820,7 +946,20 @@
}
}
- void *new_ptr = DELEGATE(malloc, new_size);
+ void *new_ptr;
+ if (zone->wrapped_zone->version >= 16) {
+ new_ptr = DELEGATE(malloc_type_malloc, new_size, type_id);
+ } else {
+#if MALLOC_TARGET_64BIT
+ malloc_set_tsd_type_descriptor(
+ (malloc_type_descriptor_t){ .type_id = type_id });
+#endif // MALLOC_TARGET_64BIT
+ new_ptr = DELEGATE(malloc, new_size);
+#if MALLOC_TARGET_64BIT
+ malloc_set_tsd_type_descriptor(MALLOC_TYPE_DESCRIPTOR_NONE);
+#endif // MALLOC_TARGET_64BIT
+ }
+
#if !MALLOC_TARGET_EXCLAVES
record_alloc_stacktrace(zone->depo, zone->map, new_ptr, usr_new_size);
#endif /* !MALLOC_TARGET_EXCLAVES */
@@ -863,6 +1002,13 @@
return new_ptr;
}
+static void * __alloc_size(3) __sized_by_or_null(new_size)
+sanitizer_realloc(sanitizer_zone_t *zone, void * __unsafe_indexable ptr, size_t new_size)
+{
+ return sanitizer_malloc_type_realloc(zone, ptr, new_size,
+ malloc_get_tsd_type_id());
+}
+
static void
sanitizer_destroy(sanitizer_zone_t *zone)
{
@@ -876,9 +1022,13 @@
#endif /* !MALLOC_TARGET_EXCLAVES */
}
-static void * __alloc_align(2) __alloc_size(3)
-sanitizer_memalign(sanitizer_zone_t *zone, size_t alignment, size_t size)
-{
+static void * __alloc_align(2) __alloc_size(3) __sized_by_or_null(size)
+sanitizer_malloc_type_memalign(sanitizer_zone_t *zone, size_t align,
+ size_t size, malloc_type_id_t type_id)
+{
+ if (!size) {
+ size = 1;
+ }
size_t redzone_size = zone->redzone_size;
const size_t usr_size = size;
if (zone->do_poisoning) {
@@ -889,11 +1039,25 @@
return NULL;
}
}
- void *ptr = DELEGATE(memalign, alignment, size);
+
+ void *ptr;
+ if (zone->wrapped_zone->version >= 16) {
+ ptr = DELEGATE(malloc_type_memalign, align, size, type_id);
+ } else {
+#if MALLOC_TARGET_64BIT
+ malloc_set_tsd_type_descriptor(
+ (malloc_type_descriptor_t){ .type_id = type_id });
+#endif // MALLOC_TARGET_64BIT
+ ptr = DELEGATE(memalign, align, size);
+#if MALLOC_TARGET_64BIT
+ malloc_set_tsd_type_descriptor(MALLOC_TYPE_DESCRIPTOR_NONE);
+#endif // MALLOC_TARGET_64BIT
+ }
+
#if !MALLOC_TARGET_EXCLAVES
record_alloc_stacktrace(zone->depo, zone->map, ptr, usr_size);
#endif /* !MALLOC_TARGET_EXCLAVES */
- if (zone->debug) malloc_report(ASL_LEVEL_INFO, "memalign(0x%lx, 0x%lx)\n", alignment, size);
+ if (zone->debug) malloc_report(ASL_LEVEL_INFO, "memalign(0x%lx, 0x%lx)\n", align, size);
if (ptr && zone->do_poisoning) {
// Recalculate the redzone size to include allocator padding
size_t actual_size = DELEGATE(size, ptr);
@@ -906,6 +1070,71 @@
return ptr;
}
+static void * __alloc_align(2) __alloc_size(3) __sized_by_or_null(size)
+sanitizer_memalign(sanitizer_zone_t *zone, size_t align, size_t size)
+{
+ return sanitizer_malloc_type_memalign(zone, align, size,
+ malloc_get_tsd_type_id());
+}
+
+static void * __alloc_align(2) __alloc_size(3) __sized_by_or_null(size)
+sanitizer_malloc_type_malloc_with_options(sanitizer_zone_t *zone, size_t align,
+ size_t size, malloc_zone_malloc_options_t options,
+ malloc_type_id_t type_id)
+{
+#if CONFIG_MTE
+ // rdar://140822174
+ // When dyld interposition or a wrapper zone that does not support
+ // forwarding malloc options is enabled, we need to set a flag in
+ // the TSD to preserve the semantics of canonical tagging.
+ bool use_tsd_fallback =
+ (options & MALLOC_ZONE_MALLOC_OPTION_CANONICAL_TAG) &&
+ (zone->wrapped_zone->version < 15 ||
+ !zone->wrapped_zone->malloc_with_options);
+#if !MALLOC_TARGET_EXCLAVES
+ malloc_thread_options_t opts;
+ if (use_tsd_fallback) {
+ opts = malloc_get_thread_options();
+ malloc_thread_options_t newopts = opts;
+ newopts.ReservedFlag = true;
+ _malloc_set_thread_options(newopts);
+ }
+#else
+ MALLOC_ASSERT(!use_tsd_fallback);
+#endif // MALLOC_TARGET_EXCLAVES
+#endif // CONFIG_MTE
+
+ void *ptr;
+ if (!align) {
+ ptr = sanitizer_malloc_type_malloc_noalign_with_options(zone, size,
+ options, type_id);
+ } else {
+ ptr = sanitizer_malloc_type_memalign(zone, align, size, type_id);
+ if (ptr && (options & MALLOC_ZONE_MALLOC_OPTION_CLEAR)) {
+ bzero(ptr, size);
+ }
+ }
+
+#if CONFIG_MTE
+#if !MALLOC_TARGET_EXCLAVES
+ // Restore the saved TSD flags
+ if (use_tsd_fallback) {
+ _malloc_set_thread_options(opts);
+ }
+#endif // MALLOC_TARGET_EXCLAVES
+#endif // CONFIG_MTE
+
+ return ptr;
+}
+
+static void * __alloc_align(2) __alloc_size(3) __sized_by_or_null(size)
+sanitizer_malloc_with_options(sanitizer_zone_t *zone, size_t align, size_t size,
+ malloc_zone_malloc_options_t options)
+{
+ return sanitizer_malloc_type_malloc_with_options(zone, align, size, options,
+ malloc_get_tsd_type_id());
+}
+
static void
sanitizer_free_definite_size(sanitizer_zone_t *zone, void * __sized_by(size) ptr, size_t size)
{
@@ -918,12 +1147,6 @@
poison_free(zone, ptr, size);
}
place_into_quarantine(zone, ptr, size);
-}
-
-static size_t
-sanitizer_pressure_relief(sanitizer_zone_t *zone, size_t goal)
-{
- return DELEGATE(pressure_relief, goal);
}
static bool
@@ -1074,7 +1297,7 @@
}
g_crm_reader = NULL;
- memset(report, 0, sizeof(*report));
+ bzero(report, sizeof(*report));
report->fault_address = fault_address;
if (enumeration_context.found_range.address != 0) {
@@ -1086,12 +1309,14 @@
uint32_t dealloc_handle = (uint32_t)(chunk->stacktrace_hashes >> 32);
report->alloc_trace.thread_id = 0;
+ // Explicit cast (report->alloc_trace.frames) as it doesn't otherwise compile on watchOS (error: implicit conversion loses integer precision)
report->alloc_trace.num_frames = (uint32_t)stacktrace_depo_find(remote_depo, alloc_handle,
- report->alloc_trace.frames, countof(report->alloc_trace.frames));
+ (uintptr_t *)report->alloc_trace.frames, countof(report->alloc_trace.frames));
report->dealloc_trace.thread_id = 0;
+ // Explicit cast (report->dealloc_trace.frames) as it doesn't otherwise compile on watchOS (error: implicit conversion loses integer precision)
report->dealloc_trace.num_frames = (uint32_t)stacktrace_depo_find(remote_depo, dealloc_handle,
- report->dealloc_trace.frames, countof(report->dealloc_trace.frames));
+ (uintptr_t *)report->dealloc_trace.frames, countof(report->dealloc_trace.frames));
_free(chunk);
}
@@ -1168,15 +1393,24 @@
// Introspection
.zone_name = "SanitizerMallocZone",
- .version = 14,
+ .version = 16,
.introspect = &sanitizer_zone_introspect_template,
// Specialized operations
.memalign = FN_PTR(sanitizer_memalign),
.free_definite_size = FN_PTR(sanitizer_free_definite_size),
- .pressure_relief = FN_PTR(sanitizer_pressure_relief),
+ .pressure_relief = malloc_zone_pressure_relief_fallback,
.claimed_address = FN_PTR(sanitizer_claimed_address),
.try_free_default = NULL,
+ .malloc_with_options = FN_PTR(sanitizer_malloc_with_options),
+
+ // Typed operations
+ .malloc_type_malloc = FN_PTR(sanitizer_malloc_type_malloc),
+ .malloc_type_calloc = FN_PTR(sanitizer_malloc_type_calloc),
+ .malloc_type_realloc = FN_PTR(sanitizer_malloc_type_realloc),
+ .malloc_type_memalign = FN_PTR(sanitizer_malloc_type_memalign),
+ .malloc_type_malloc_with_options =
+ FN_PTR(sanitizer_malloc_type_malloc_with_options),
};