Skip to content

Commit

Permalink
i#4087: Statically retarget libelftc malloc to DR (#4094)
Browse files Browse the repository at this point in the history
Re-builds the ELF libeltc binaries to directly target the __wrap_
versions of malloc, calloc, realloc, free, and strdup.  This avoids libc for
statically linked uses rather than solely relying on the DR private
loader to redirect.  Updates *all* of the binaries: aarch64, android,
arm EABI, arm EABIHF, macho, pecoff lib32, pecoff lib64.

Due to a bug in libelftc r3531 (https://sourceforge.net/p/elftoolchain/tickets/581/)
all the new binaries are built at r3531.

Changes the __wrap_ and redirect_ malloc routines to be cross-platform
and usable on Windows.

Clang-formats the libelftc headers we share.

Fixes libelftc-pecoff.patch which had all the added files stripped out
by e345a54!!

Fixes #4087
  • Loading branch information
derekbruening authored Feb 14, 2020
1 parent 2d699bc commit 7fd5d95
Show file tree
Hide file tree
Showing 58 changed files with 4,467 additions and 3,928 deletions.
2 changes: 1 addition & 1 deletion api/docs/intro.dox
Original file line number Diff line number Diff line change
Expand Up @@ -1375,7 +1375,7 @@ DynamoRIO's global memory pool. Use the -Xlinker flag with gcc to replace
the libc routines with DynamoRIO's _wrap routines, e.g.,

\code
gcc -Xlinker -wrap=malloc -Xlinker -wrap=realloc -Xlinker -wrap=free ...
gcc -Xlinker -wrap=malloc -Xlinker -wrap=realloc -Xlinker -wrap=free -Xlinker -wrap=strdup ...
\endcode

The ability to override the memory allocation routines makes it
Expand Down
9 changes: 7 additions & 2 deletions core/lib/instrument.c
Original file line number Diff line number Diff line change
Expand Up @@ -3206,7 +3206,6 @@ dr_custom_free(void *drcontext, dr_alloc_flags_t flags, void *addr, size_t size)
return res;
}

# ifdef UNIX
DR_API
/* With ld's -wrap option, we can supply a replacement for malloc.
* This routine allocates memory from DR's global memory pool. Unlike
Expand Down Expand Up @@ -3253,7 +3252,13 @@ __wrap_free(void *mem)
{
redirect_free(mem);
}
# endif

DR_API
char *
__wrap_strdup(const char *str)
{
return redirect_strdup(str);
}

DR_API
bool
Expand Down
17 changes: 11 additions & 6 deletions core/lib/instrument_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -2299,7 +2299,6 @@ void *
dr_raw_brk(void *new_address);
# endif

# ifdef UNIX
DR_API
/**
* Allocates memory from DR's global memory pool, but mimics the
Expand All @@ -2309,7 +2308,6 @@ DR_API
* versions that allocate memory from DR's private pool. With -wrap,
* clients can link to libraries that allocate heap memory without
* interfering with application allocations.
* \note Currently Linux only.
*/
void *
__wrap_malloc(size_t size);
Expand All @@ -2320,7 +2318,6 @@ DR_API
* behavior of realloc. Memory must be freed with __wrap_free(). The
* __wrap routines are intended to be used with ld's -wrap option; see
* __wrap_malloc() for more information.
* \note Currently Linux only.
*/
void *
__wrap_realloc(void *mem, size_t size);
Expand All @@ -2331,7 +2328,6 @@ DR_API
* behavior of calloc. Memory must be freed with __wrap_free(). The
* __wrap routines are intended to be used with ld's -wrap option; see
* __wrap_malloc() for more information.
* \note Currently Linux only.
*/
void *
__wrap_calloc(size_t nmemb, size_t size);
Expand All @@ -2342,11 +2338,20 @@ DR_API
* allocated with __wrap_malloc(). The __wrap routines are intended to
* be used with ld's -wrap option; see __wrap_malloc() for more
* information.
* \note Currently Linux only.
*/
void
__wrap_free(void *mem);
# endif /* UNIX */

DR_API
/**
* Allocates memory for a new string identical to 'str' and copies the
* contents of 'str' into the new string, including a terminating
* null. Memory must be freed with __wrap_free(). The __wrap
* routines are intended to be used with ld's -wrap option; see
* __wrap_malloc() for more information.
*/
char *
__wrap_strdup(const char *str);

/* DR_API EXPORT BEGIN */

Expand Down
147 changes: 147 additions & 0 deletions core/loader_shared.c
Original file line number Diff line number Diff line change
Expand Up @@ -908,3 +908,150 @@ privload_print_modules(bool path, bool lock, char *buf, size_t bufsz, size_t *so
release_recursive_lock(&privload_lock);
return true;
}

/****************************************************************************
* Function Redirection
*/

#ifdef DEBUG
/* i#975: used for debug checks for static-link-ready clients. */
DECLARE_NEVERPROT_VAR(bool disallow_unsafe_static_calls, false);
#endif

void
loader_allow_unsafe_static_behavior(void)
{
#ifdef DEBUG
disallow_unsafe_static_calls = false;
#endif
}

/* This routine allocates memory from DR's global memory pool. Unlike
* dr_global_alloc(), however, we store the size of the allocation in
* the first few bytes so redirect_free() can retrieve it. This memory
* is also not guaranteed-reachable.
*/
void *
redirect_malloc(size_t size)
{
void *mem;
ASSERT(sizeof(size_t) >= HEAP_ALIGNMENT);
size += sizeof(size_t);
mem = global_heap_alloc(size HEAPACCT(ACCT_LIBDUP));
if (mem == NULL) {
CLIENT_ASSERT(false, "malloc failed: out of memory");
return NULL;
}
*((size_t *)mem) = size;
/* XXX: This is not aligned to 8 for 32-bit as some callers might expect,
* nor to 16 for x64.
*/
return (byte *)mem + sizeof(size_t);
}

/* This routine allocates memory from DR's global memory pool. Unlike
* dr_global_alloc(), however, we store the size of the allocation in
* the first few bytes so redirect_free() can retrieve it.
*/
void *
redirect_realloc(void *mem, size_t size)
{
void *buf = NULL;
if (size > 0) {
buf = redirect_malloc(size);
if (buf != NULL && mem != NULL) {
size_t old_size = *((size_t *)((byte *)mem - sizeof(size_t)));
size_t min_size = MIN(old_size, size);
memcpy(buf, mem, min_size);
}
}
redirect_free(mem);
return buf;
}

/* This routine allocates memory from DR's global memory pool.
* It uses redirect_malloc to get the memory and then set to all 0.
*/
void *
redirect_calloc(size_t nmemb, size_t size)
{
void *buf = NULL;
size = size * nmemb;

buf = redirect_malloc(size);
if (buf != NULL)
memset(buf, 0, size);
return buf;
}

/* This routine frees memory allocated by redirect_malloc and expects the
* allocation size to be available in the few bytes before 'mem'.
*/
void
redirect_free(void *mem)
{
/* PR 200203: leave_call_native() is assuming this routine calls
* no other DR routines besides global_heap_free!
*/
if (mem != NULL) {
mem = (byte *)mem - sizeof(size_t);
global_heap_free(mem, *((size_t *)mem)HEAPACCT(ACCT_LIBDUP));
}
}

char *
redirect_strdup(const char *str)
{
char *dup;
size_t str_len;
if (str == NULL)
return NULL;
str_len = strlen(str) + 1 /* null char */;
dup = (char *)redirect_malloc(str_len);
strncpy(dup, str, str_len);
dup[str_len - 1] = '\0';
return dup;
}

#ifdef DEBUG
/* i#975: these help clients support static linking with the app. */
void *
redirect_malloc_initonly(size_t size)
{
CLIENT_ASSERT(!disallow_unsafe_static_calls || !dynamo_initialized || dynamo_exited,
"malloc invoked mid-run when disallowed by DR_DISALLOW_UNSAFE_STATIC");
return redirect_malloc(size);
}

void *
redirect_realloc_initonly(void *mem, size_t size)
{
CLIENT_ASSERT(!disallow_unsafe_static_calls || !dynamo_initialized || dynamo_exited,
"realloc invoked mid-run when disallowed by DR_DISALLOW_UNSAFE_STATIC");
return redirect_realloc(mem, size);
}

void *
redirect_calloc_initonly(size_t nmemb, size_t size)
{
CLIENT_ASSERT(!disallow_unsafe_static_calls || !dynamo_initialized || dynamo_exited,
"calloc invoked mid-run when disallowed by DR_DISALLOW_UNSAFE_STATIC");
return redirect_calloc(nmemb, size);
}

void
redirect_free_initonly(void *mem)
{
CLIENT_ASSERT(!disallow_unsafe_static_calls || !dynamo_initialized || dynamo_exited,
"free invoked mid-run when disallowed by DR_DISALLOW_UNSAFE_STATIC");
redirect_free(mem);
}

char *
redirect_strdup_initonly(const char *str)
{
CLIENT_ASSERT(!disallow_unsafe_static_calls || !dynamo_initialized || dynamo_exited,
"strdup invoked mid-run when disallowed by DR_DISALLOW_UNSAFE_STATIC");
return redirect_strdup(str);
}
#endif
44 changes: 41 additions & 3 deletions core/module_shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
* DAMAGE.
*/

#ifndef MODULE_LIST_H
#define MODULE_LIST_H
#ifndef MODULE_SHARED_H
#define MODULE_SHARED_H

#include "heap.h" /* for HEAPACCT */

Expand Down Expand Up @@ -672,4 +672,42 @@ bool
privload_attach_parent_console(app_pc app_kernel32);
#endif

#endif /* MODULE_LIST_H */
/* Redirected functions for loaded module,
* they are also used by __wrap_* functions in instrument.c
*/

#ifdef DEBUG
/* i#975: used for debug checks for static-link-ready clients. */
# define DR_DISALLOW_UNSAFE_STATIC_NAME "_DR_DISALLOW_UNSAFE_STATIC_"
extern bool disallow_unsafe_static_calls;
#endif

void *
redirect_calloc(size_t nmemb, size_t size);

void *
redirect_malloc(size_t size);

void
redirect_free(void *ptr);

void *
redirect_realloc(void *ptr, size_t size);

char *
redirect_strdup(const char *str);

#ifdef DEBUG
void *
redirect_malloc_initonly(size_t size);
void *
redirect_realloc_initonly(void *mem, size_t size);
void *
redirect_calloc_initonly(size_t nmemb, size_t size);
void
redirect_free_initonly(void *mem);
char *
redirect_strdup_initonly(const char *str);
#endif

#endif /* MODULE_SHARED_H */
15 changes: 2 additions & 13 deletions core/unix/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -1262,19 +1262,6 @@ privload_fill_os_module_info(app_pc base, OUT app_pc *out_base /* relative pc */
* Function Redirection
*/

#ifdef DEBUG
/* i#975: used for debug checks for static-link-ready clients. */
bool disallow_unsafe_static_calls;
#endif

void
loader_allow_unsafe_static_behavior(void)
{
#ifdef DEBUG
disallow_unsafe_static_calls = false;
#endif
}

#if defined(LINUX) && !defined(ANDROID)
/* These are not yet supported by Android's Bionic */
void *
Expand Down Expand Up @@ -1378,6 +1365,7 @@ static const redirect_import_t redirect_imports[] = {
{ "malloc", (app_pc)redirect_malloc },
{ "free", (app_pc)redirect_free },
{ "realloc", (app_pc)redirect_realloc },
{ "strdup", (app_pc)redirect_strdup },
/* FIXME: we should also redirect functions including:
* malloc_usable_size, memalign, valloc, mallinfo, mallopt, etc.
* Any other functions need to be redirected?
Expand Down Expand Up @@ -1423,6 +1411,7 @@ static const redirect_import_t redirect_debug_imports[] = {
{ "malloc", (app_pc)redirect_malloc_initonly },
{ "free", (app_pc)redirect_free_initonly },
{ "realloc", (app_pc)redirect_realloc_initonly },
{ "strdup", (app_pc)redirect_strdup_initonly },
};
# define REDIRECT_DEBUG_IMPORTS_NUM \
(sizeof(redirect_debug_imports) / sizeof(redirect_debug_imports[0]))
Expand Down
Loading

0 comments on commit 7fd5d95

Please sign in to comment.