alloc tests: implement malloc_zone_* (#1569)

Motivation:

The Swift runtime is now using malloc_zone_*, we need to implement
replacements for these too. This is just a first pass, eventually, we
should implement _all_ replacements as `malloc_zone_memalign` which is
powerful enough to implement all others.

Modifications:

Provide new replacements.

Result:

Alloc tests work again on macOS.

Co-authored-by: Cory Benfield <lukasa@apple.com>
This commit is contained in:
Johannes Weiss 2020-06-26 11:04:37 +01:00 committed by GitHub
parent 3c5ea83a9a
commit 3a2fc0d39b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 189 additions and 24 deletions

View File

@ -16,6 +16,9 @@
#define HOOKED_FREE
#include <stdlib.h>
#if __APPLE__
# include <malloc/malloc.h>
#endif
void *replacement_malloc(size_t size);
void replacement_free(void *ptr);
@ -25,4 +28,13 @@ void *replacement_reallocf(void *ptr, size_t size);
void *replacement_valloc(size_t size);
int replacement_posix_memalign(void **memptr, size_t alignment, size_t size);
#if __APPLE__
void *replacement_malloc_zone_malloc(malloc_zone_t *zone, size_t size);
void *replacement_malloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size);
void *replacement_malloc_zone_valloc(malloc_zone_t *zone, size_t size);
void *replacement_malloc_zone_realloc(malloc_zone_t *zone, void *ptr, size_t size);
void *replacement_malloc_zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size);
void replacement_malloc_zone_free(malloc_zone_t *zone, void *ptr);
#endif
#endif

View File

@ -0,0 +1,164 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
#if __APPLE__
#define _GNU_SOURCE
#include <dlfcn.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <malloc/malloc.h>
#include <atomic-counter.h>
#include <hooked-functions.h>
#define DYLD_INTERPOSE(_replacement,_replacee) \
__attribute__((used)) static struct { const void *replacement; const void *replacee; } _interpose_##_replacee \
__attribute__ ((section("__DATA,__interpose"))) = { (const void *)(unsigned long)&_replacement, (const void *)(unsigned long)&_replacee };
/* on Darwin calling the original function is super easy, just call it, done. */
#define JUMP_INTO_LIBC_FUN(_fun, ...) /* \
*/ do { /* \
*/ return _fun(__VA_ARGS__); /* \
*/ } while(0)
void replacement_free(void *ptr) {
if (ptr) {
inc_free_counter();
JUMP_INTO_LIBC_FUN(free, ptr);
}
}
void *replacement_malloc(size_t size) {
inc_malloc_counter();
add_malloc_bytes_counter((intptr_t) size);
JUMP_INTO_LIBC_FUN(malloc, size);
}
void *replacement_realloc(void *ptr, size_t size) {
if (0 == size) {
replacement_free(ptr);
return NULL;
}
if (!ptr) {
return replacement_malloc(size);
}
inc_free_counter();
inc_malloc_counter();
add_malloc_bytes_counter((intptr_t) size);
JUMP_INTO_LIBC_FUN(realloc, ptr, size);
}
void *replacement_calloc(size_t count, size_t size) {
inc_malloc_counter();
add_malloc_bytes_counter((intptr_t)(count * size));
JUMP_INTO_LIBC_FUN(calloc, count, size);
}
void *replacement_malloc_zone_malloc(malloc_zone_t *zone, size_t size) {
inc_malloc_counter();
add_malloc_bytes_counter((intptr_t)size);
JUMP_INTO_LIBC_FUN(malloc_zone_malloc, zone, size);
}
void *replacement_malloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size) {
inc_malloc_counter();
add_malloc_bytes_counter((intptr_t)(size * num_items));
JUMP_INTO_LIBC_FUN(malloc_zone_calloc, zone, num_items, size);
}
void *replacement_malloc_zone_valloc(malloc_zone_t *zone, size_t size) {
inc_malloc_counter();
add_malloc_bytes_counter((intptr_t)size);
JUMP_INTO_LIBC_FUN(malloc_zone_valloc, zone, size);
}
void *replacement_malloc_zone_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
if (0 == size) {
replacement_free(ptr);
return NULL;
}
if (!ptr) {
return replacement_malloc(size);
}
inc_free_counter();
inc_malloc_counter();
add_malloc_bytes_counter((intptr_t)size);
JUMP_INTO_LIBC_FUN(realloc, ptr, size);
}
void *replacement_malloc_zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size) {
inc_malloc_counter();
add_malloc_bytes_counter((intptr_t)size);
JUMP_INTO_LIBC_FUN(malloc_zone_memalign, zone, alignment, size);
}
void replacement_malloc_zone_free(malloc_zone_t *zone, void *ptr) {
inc_free_counter();
JUMP_INTO_LIBC_FUN(malloc_zone_free, zone, ptr);
}
void *replacement_reallocf(void *ptr, size_t size) {
void *new_ptr = replacement_realloc(ptr, size);
if (!new_ptr) {
replacement_free(new_ptr);
}
return new_ptr;
}
void *replacement_valloc(size_t size) {
inc_malloc_counter();
add_malloc_bytes_counter((intptr_t)size);
JUMP_INTO_LIBC_FUN(valloc, size);
}
int replacement_posix_memalign(void **memptr, size_t alignment, size_t size) {
inc_malloc_counter();
add_malloc_bytes_counter((intptr_t)size);
JUMP_INTO_LIBC_FUN(posix_memalign, memptr, alignment, size);
}
DYLD_INTERPOSE(replacement_free, free)
DYLD_INTERPOSE(replacement_malloc, malloc)
DYLD_INTERPOSE(replacement_realloc, realloc)
DYLD_INTERPOSE(replacement_calloc, calloc)
DYLD_INTERPOSE(replacement_reallocf, reallocf)
DYLD_INTERPOSE(replacement_valloc, valloc)
DYLD_INTERPOSE(replacement_posix_memalign, posix_memalign)
DYLD_INTERPOSE(replacement_malloc_zone_malloc, malloc_zone_malloc)
DYLD_INTERPOSE(replacement_malloc_zone_calloc, malloc_zone_calloc)
DYLD_INTERPOSE(replacement_malloc_zone_valloc, malloc_zone_valloc)
DYLD_INTERPOSE(replacement_malloc_zone_realloc, malloc_zone_realloc)
DYLD_INTERPOSE(replacement_malloc_zone_memalign, malloc_zone_memalign)
DYLD_INTERPOSE(replacement_malloc_zone_free, malloc_zone_free)
#endif

View File

@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//
#ifndef __APPLE__
#define _GNU_SOURCE
#include <dlfcn.h>
#include <fcntl.h>
@ -33,9 +35,6 @@ static char g_recursive_malloc_mem[10 * 1024 * 1024] = {0};
/* the index of the first free byte */
static _Atomic ptrdiff_t g_recursive_malloc_next_free_ptr = ATOMIC_VAR_INIT(0);
#define DYLD_INTERPOSE(_replacement,_replacee) \
__attribute__((used)) static struct { const void *replacement; const void *replacee; } _interpose_##_replacee \
__attribute__ ((section("__DATA,__interpose"))) = { (const void *)(unsigned long)&_replacement, (const void *)(unsigned long)&_replacee };
#define LIBC_SYMBOL(_fun) "" # _fun
static __thread bool g_in_malloc = false;
@ -86,16 +85,6 @@ static void recursive_free(void *ptr) {
abort();
}
#if __APPLE__
/* on Darwin calling the original function is super easy, just call it, done. */
#define JUMP_INTO_LIBC_FUN(_fun, ...) /* \
*/ do { /* \
*/ return _fun(__VA_ARGS__); /* \
*/ } while(0)
#else
/* on other UNIX systems this is slightly harder. Basically we see if we already
* have a thread local variable that is a pointer to the original libc function.
* If yes, easy, call it. If no, we need to resolve it which we do by using
@ -117,8 +106,6 @@ static void recursive_free(void *ptr) {
*/ return g_libc_ ## _fun (__VA_ARGS__); /*
*/ } while(0)
#endif
void replacement_free(void *ptr) {
if (ptr) {
inc_free_counter();
@ -180,12 +167,4 @@ int replacement_posix_memalign(void **memptr, size_t alignment, size_t size) {
}
}
#if __APPLE__
DYLD_INTERPOSE(replacement_free, free)
DYLD_INTERPOSE(replacement_malloc, malloc)
DYLD_INTERPOSE(replacement_realloc, realloc)
DYLD_INTERPOSE(replacement_calloc, calloc)
DYLD_INTERPOSE(replacement_reallocf, reallocf)
DYLD_INTERPOSE(replacement_valloc, valloc)
DYLD_INTERPOSE(replacement_posix_memalign, posix_memalign)
#endif

View File

@ -28,7 +28,17 @@
printf("=====\n");
}
pid$target::malloc:entry, pid$target::posix_memalign:entry, pid$target::realloc:entry, pid$target::reallocf:entry, pid$target::calloc:entry, pid$target::valloc:entry, pid$target::posix_memalign:entry {
pid$target::malloc:entry,
pid$target::posix_memalign:entry,
pid$target::realloc:entry,
pid$target::reallocf:entry,
pid$target::calloc:entry,
pid$target::valloc:entry,
pid$target::malloc_zone_malloc:entry,
pid$target::malloc_zone_realloc:entry,
pid$target::malloc_zone_calloc:entry,
pid$target::malloc_zone_valloc:entry,
pid$target::malloc_zone_memalign:entry {
@malloc_calls[ustack()] = count();
}