aboutsummaryrefslogtreecommitdiff
path: root/libc/bionic/malloc_common.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libc/bionic/malloc_common.cpp')
-rw-r--r--libc/bionic/malloc_common.cpp127
1 files changed, 103 insertions, 24 deletions
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 9dc4d12d1..ed5537f5f 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -39,10 +39,13 @@
#include <stdio.h>
#include <private/bionic_config.h>
-#include <private/bionic_malloc.h>
+#include <platform/bionic/malloc.h>
+#include "gwp_asan_wrappers.h"
+#include "heap_tagging.h"
#include "malloc_common.h"
#include "malloc_limit.h"
+#include "malloc_tagged_pointers.h"
// =============================================================================
// Global variables instantations.
@@ -61,17 +64,18 @@ void* (*volatile __memalign_hook)(size_t, size_t, const void*);
extern "C" void* calloc(size_t n_elements, size_t elem_size) {
auto dispatch_table = GetDispatchTable();
if (__predict_false(dispatch_table != nullptr)) {
- return dispatch_table->calloc(n_elements, elem_size);
+ return MaybeTagPointer(dispatch_table->calloc(n_elements, elem_size));
}
void* result = Malloc(calloc)(n_elements, elem_size);
if (__predict_false(result == nullptr)) {
warning_log("calloc(%zu, %zu) failed: returning null pointer", n_elements, elem_size);
}
- return result;
+ return MaybeTagPointer(result);
}
extern "C" void free(void* mem) {
auto dispatch_table = GetDispatchTable();
+ mem = MaybeUntagAndCheckPointer(mem);
if (__predict_false(dispatch_table != nullptr)) {
dispatch_table->free(mem);
} else {
@@ -105,18 +109,22 @@ extern "C" int mallopt(int param, int value) {
extern "C" void* malloc(size_t bytes) {
auto dispatch_table = GetDispatchTable();
+ void *result;
if (__predict_false(dispatch_table != nullptr)) {
- return dispatch_table->malloc(bytes);
+ result = dispatch_table->malloc(bytes);
+ } else {
+ result = Malloc(malloc)(bytes);
}
- void* result = Malloc(malloc)(bytes);
if (__predict_false(result == nullptr)) {
warning_log("malloc(%zu) failed: returning null pointer", bytes);
+ return nullptr;
}
- return result;
+ return MaybeTagPointer(result);
}
extern "C" size_t malloc_usable_size(const void* mem) {
auto dispatch_table = GetDispatchTable();
+ mem = MaybeUntagAndCheckPointer(mem);
if (__predict_false(dispatch_table != nullptr)) {
return dispatch_table->malloc_usable_size(mem);
}
@@ -126,45 +134,52 @@ extern "C" size_t malloc_usable_size(const void* mem) {
extern "C" void* memalign(size_t alignment, size_t bytes) {
auto dispatch_table = GetDispatchTable();
if (__predict_false(dispatch_table != nullptr)) {
- return dispatch_table->memalign(alignment, bytes);
+ return MaybeTagPointer(dispatch_table->memalign(alignment, bytes));
}
void* result = Malloc(memalign)(alignment, bytes);
if (__predict_false(result == nullptr)) {
warning_log("memalign(%zu, %zu) failed: returning null pointer", alignment, bytes);
}
- return result;
+ return MaybeTagPointer(result);
}
extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size) {
auto dispatch_table = GetDispatchTable();
+ int result;
if (__predict_false(dispatch_table != nullptr)) {
- return dispatch_table->posix_memalign(memptr, alignment, size);
+ result = dispatch_table->posix_memalign(memptr, alignment, size);
+ } else {
+ result = Malloc(posix_memalign)(memptr, alignment, size);
}
- return Malloc(posix_memalign)(memptr, alignment, size);
+ if (result == 0) {
+ *memptr = MaybeTagPointer(*memptr);
+ }
+ return result;
}
extern "C" void* aligned_alloc(size_t alignment, size_t size) {
auto dispatch_table = GetDispatchTable();
if (__predict_false(dispatch_table != nullptr)) {
- return dispatch_table->aligned_alloc(alignment, size);
+ return MaybeTagPointer(dispatch_table->aligned_alloc(alignment, size));
}
void* result = Malloc(aligned_alloc)(alignment, size);
if (__predict_false(result == nullptr)) {
warning_log("aligned_alloc(%zu, %zu) failed: returning null pointer", alignment, size);
}
- return result;
+ return MaybeTagPointer(result);
}
extern "C" __attribute__((__noinline__)) void* realloc(void* old_mem, size_t bytes) {
auto dispatch_table = GetDispatchTable();
+ old_mem = MaybeUntagAndCheckPointer(old_mem);
if (__predict_false(dispatch_table != nullptr)) {
- return dispatch_table->realloc(old_mem, bytes);
+ return MaybeTagPointer(dispatch_table->realloc(old_mem, bytes));
}
void* result = Malloc(realloc)(old_mem, bytes);
if (__predict_false(result == nullptr && bytes != 0)) {
warning_log("realloc(%p, %zu) failed: returning null pointer", old_mem, bytes);
}
- return result;
+ return MaybeTagPointer(result);
}
extern "C" void* reallocarray(void* old_mem, size_t item_count, size_t item_size) {
@@ -182,42 +197,66 @@ extern "C" void* reallocarray(void* old_mem, size_t item_count, size_t item_size
extern "C" void* pvalloc(size_t bytes) {
auto dispatch_table = GetDispatchTable();
if (__predict_false(dispatch_table != nullptr)) {
- return dispatch_table->pvalloc(bytes);
+ return MaybeTagPointer(dispatch_table->pvalloc(bytes));
}
void* result = Malloc(pvalloc)(bytes);
if (__predict_false(result == nullptr)) {
warning_log("pvalloc(%zu) failed: returning null pointer", bytes);
}
- return result;
+ return MaybeTagPointer(result);
}
extern "C" void* valloc(size_t bytes) {
auto dispatch_table = GetDispatchTable();
if (__predict_false(dispatch_table != nullptr)) {
- return dispatch_table->valloc(bytes);
+ return MaybeTagPointer(dispatch_table->valloc(bytes));
}
void* result = Malloc(valloc)(bytes);
if (__predict_false(result == nullptr)) {
warning_log("valloc(%zu) failed: returning null pointer", bytes);
}
- return result;
+ return MaybeTagPointer(result);
}
#endif
// =============================================================================
+struct CallbackWrapperArg {
+ void (*callback)(uintptr_t base, size_t size, void* arg);
+ void* arg;
+};
+
+void CallbackWrapper(uintptr_t base, size_t size, void* arg) {
+ CallbackWrapperArg* wrapper_arg = reinterpret_cast<CallbackWrapperArg*>(arg);
+ wrapper_arg->callback(
+ reinterpret_cast<uintptr_t>(MaybeTagPointer(reinterpret_cast<void*>(base))),
+ size, wrapper_arg->arg);
+}
+
// =============================================================================
// Exported for use by libmemunreachable.
// =============================================================================
// Calls callback for every allocation in the anonymous heap mapping
-// [base, base+size). Must be called between malloc_disable and malloc_enable.
+// [base, base+size). Must be called between malloc_disable and malloc_enable.
+// `base` in this can take either a tagged or untagged pointer, but we always
+// provide a tagged pointer to the `base` argument of `callback` if the kernel
+// supports tagged pointers.
extern "C" int malloc_iterate(uintptr_t base, size_t size,
void (*callback)(uintptr_t base, size_t size, void* arg), void* arg) {
auto dispatch_table = GetDispatchTable();
+ // Wrap the malloc_iterate callback we were provided, in order to provide
+ // pointer tagging support.
+ CallbackWrapperArg wrapper_arg;
+ wrapper_arg.callback = callback;
+ wrapper_arg.arg = arg;
+ uintptr_t untagged_base =
+ reinterpret_cast<uintptr_t>(UntagPointer(reinterpret_cast<void*>(base)));
if (__predict_false(dispatch_table != nullptr)) {
- return dispatch_table->iterate(base, size, callback, arg);
+ return dispatch_table->malloc_iterate(
+ untagged_base, size, CallbackWrapper, &wrapper_arg);
}
- return Malloc(iterate)(base, size, callback, arg);
+ return Malloc(malloc_iterate)(
+ untagged_base, size, CallbackWrapper, &wrapper_arg);
}
// Disable calls to malloc so malloc_iterate gets a consistent view of
@@ -247,9 +286,10 @@ extern "C" ssize_t malloc_backtrace(void*, uintptr_t*, size_t) {
#if __has_feature(hwaddress_sanitizer)
// FIXME: implement these in HWASan allocator.
-extern "C" int __sanitizer_iterate(uintptr_t base __unused, size_t size __unused,
- void (*callback)(uintptr_t base, size_t size, void* arg) __unused,
- void* arg __unused) {
+extern "C" int __sanitizer_malloc_iterate(uintptr_t base __unused, size_t size __unused,
+ void (*callback)(uintptr_t base, size_t size, void* arg)
+ __unused,
+ void* arg __unused) {
return 0;
}
@@ -274,8 +314,47 @@ extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) {
if (opcode == M_SET_ALLOCATION_LIMIT_BYTES) {
return LimitEnable(arg, arg_size);
}
+ if (opcode == M_SET_HEAP_TAGGING_LEVEL) {
+ return SetHeapTaggingLevel(arg, arg_size);
+ }
+ if (opcode == M_INITIALIZE_GWP_ASAN) {
+ if (arg == nullptr || arg_size != sizeof(bool)) {
+ errno = EINVAL;
+ return false;
+ }
+ __libc_globals.mutate([&](libc_globals* globals) {
+ return MaybeInitGwpAsan(globals, *reinterpret_cast<bool*>(arg));
+ });
+ }
errno = ENOTSUP;
return false;
}
#endif
// =============================================================================
+
+static constexpr MallocDispatch __libc_malloc_default_dispatch __attribute__((unused)) = {
+ Malloc(calloc),
+ Malloc(free),
+ Malloc(mallinfo),
+ Malloc(malloc),
+ Malloc(malloc_usable_size),
+ Malloc(memalign),
+ Malloc(posix_memalign),
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+ Malloc(pvalloc),
+#endif
+ Malloc(realloc),
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+ Malloc(valloc),
+#endif
+ Malloc(malloc_iterate),
+ Malloc(malloc_disable),
+ Malloc(malloc_enable),
+ Malloc(mallopt),
+ Malloc(aligned_alloc),
+ Malloc(malloc_info),
+};
+
+const MallocDispatch* NativeAllocatorDispatch() {
+ return &__libc_malloc_default_dispatch;
+}