[sanitizers] introduce yet another API function: __sanitizer_install_malloc_and_free_hooks

llvm-svn: 272943
This commit is contained in:
Kostya Serebryany 2016-06-16 20:06:06 +00:00
parent 595bc5db4b
commit bf6a04fde8
10 changed files with 114 additions and 16 deletions

View File

@ -59,6 +59,23 @@ extern "C" {
deallocation of "ptr". */
void __sanitizer_malloc_hook(const volatile void *ptr, size_t size);
void __sanitizer_free_hook(const volatile void *ptr);
/* Installs a pair of hooks for malloc/free.
Several (currently, 5) hook pairs may be installed, they are executed
in the order they were installed and after calling
__sanitizer_malloc_hook/__sanitizer_free_hook.
Unlike __sanitizer_malloc_hook/__sanitizer_free_hook these hooks can be
chained and do not rely on weak symbols working on the platform, but
require __sanitizer_install_malloc_and_free_hooks to be called at startup
and thus will not be called on malloc/free very early in the process.
Returns the number of hooks currently installed or 0 on failure.
Not thread-safe, should be called in the main thread before starting
other threads.
*/
int __sanitizer_install_malloc_and_free_hooks(
void (*malloc_hook)(const volatile void *, size_t),
void (*free_hook)(const volatile void *));
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -110,10 +110,16 @@ bool PlatformHasDifferentMemcpyAndMemmove();
// Add convenient macro for interface functions that may be represented as
// weak hooks.
#define ASAN_MALLOC_HOOK(ptr, size) \
if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
#define ASAN_FREE_HOOK(ptr) \
if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
#define ASAN_MALLOC_HOOK(ptr, size) \
do { \
if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size); \
RunMallocHooks(ptr, size); \
} while (false)
#define ASAN_FREE_HOOK(ptr) \
do { \
if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr); \
RunFreeHooks(ptr); \
} while (false)
#define ASAN_ON_ERROR() \
if (&__asan_on_error) __asan_on_error()

View File

@ -343,6 +343,7 @@ INTERFACE_FUNCTION(__sanitizer_unaligned_store16)
INTERFACE_FUNCTION(__sanitizer_unaligned_store32)
INTERFACE_FUNCTION(__sanitizer_unaligned_store64)
INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks)
// TODO(timurrrr): Add more interface functions on the as-needed basis.

View File

@ -99,11 +99,13 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
memset(p, 0, size);
RegisterAllocation(stack, p, size);
if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(p, size);
RunMallocHooks(p, size);
return p;
}
void Deallocate(void *p) {
if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
RunFreeHooks(p);
RegisterDeallocation(p);
allocator.Deallocate(&cache, p);
}

View File

@ -309,15 +309,21 @@ void MsanTSDDtor(void *tsd);
} // namespace __msan
#define MSAN_MALLOC_HOOK(ptr, size) \
if (&__sanitizer_malloc_hook) { \
UnpoisonParam(2); \
__sanitizer_malloc_hook(ptr, size); \
}
#define MSAN_FREE_HOOK(ptr) \
if (&__sanitizer_free_hook) { \
UnpoisonParam(1); \
__sanitizer_free_hook(ptr); \
}
#define MSAN_MALLOC_HOOK(ptr, size) \
do { \
if (&__sanitizer_malloc_hook) { \
UnpoisonParam(2); \
__sanitizer_malloc_hook(ptr, size); \
} \
RunMallocHooks(ptr, size); \
} while (false)
#define MSAN_FREE_HOOK(ptr) \
do { \
if (&__sanitizer_free_hook) { \
UnpoisonParam(1); \
__sanitizer_free_hook(ptr); \
} \
RunFreeHooks(ptr); \
} while (false)
#endif // MSAN_H

View File

@ -29,6 +29,10 @@ SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_heap_size();
SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_free_bytes();
SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_unmapped_bytes();
SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_install_malloc_and_free_hooks(
void (*malloc_hook)(const void *, uptr),
void (*free_hook)(const void *));
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ void __sanitizer_malloc_hook(void *ptr, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE

View File

@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common.h"
#include "sanitizer_allocator_interface.h"
#include "sanitizer_allocator_internal.h"
#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
@ -421,6 +422,44 @@ void PrintCmdline() {
Printf("\n\n");
}
// Malloc hooks.
static const int kMaxMallocFreeHooks = 5;
struct MallocFreeHook {
void (*malloc_hook)(const void *, uptr);
void (*free_hook)(const void *);
};
static MallocFreeHook MFHooks[kMaxMallocFreeHooks];
void RunMallocHooks(const void *ptr, uptr size) {
for (int i = 0; i < kMaxMallocFreeHooks; i++) {
auto hook = MFHooks[i].malloc_hook;
if (!hook) return;
hook(ptr, size);
}
}
void RunFreeHooks(const void *ptr) {
for (int i = 0; i < kMaxMallocFreeHooks; i++) {
auto hook = MFHooks[i].free_hook;
if (!hook) return;
hook(ptr);
}
}
static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),
void (*free_hook)(const void *)) {
if (!malloc_hook || !free_hook) return 0;
for (int i = 0; i < kMaxMallocFreeHooks; i++) {
if (MFHooks[i].malloc_hook == nullptr) {
MFHooks[i].malloc_hook = malloc_hook;
MFHooks[i].free_hook = free_hook;
return i + 1;
}
}
return 0;
}
} // namespace __sanitizer
using namespace __sanitizer; // NOLINT
@ -443,4 +482,11 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_set_death_callback(void (*callback)(void)) {
SetUserDieCallback(callback);
}
SANITIZER_INTERFACE_ATTRIBUTE
int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,
uptr),
void (*free_hook)(const void *)) {
return InstallMallocFreeHooks(malloc_hook, free_hook);
}
} // extern "C"

View File

@ -103,6 +103,8 @@ void NoHugePagesInRegion(uptr addr, uptr length);
void DontDumpShadowMemory(uptr addr, uptr length);
// Check if the built VMA size matches the runtime one.
void CheckVMASize();
void RunMallocHooks(const void *ptr, uptr size);
void RunFreeHooks(const void *ptr);
// InternalScopedBuffer can be used instead of large stack arrays to
// keep frame size low.

View File

@ -228,6 +228,7 @@ void invoke_malloc_hook(void *ptr, uptr size) {
if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
return;
__sanitizer_malloc_hook(ptr, size);
RunMallocHooks(ptr, size);
}
void invoke_free_hook(void *ptr) {
@ -235,6 +236,7 @@ void invoke_free_hook(void *ptr) {
if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
return;
__sanitizer_free_hook(ptr);
RunFreeHooks(ptr);
}
void *internal_alloc(MBlockType typ, uptr sz) {

View File

@ -10,22 +10,28 @@
extern "C" {
const volatile void *global_ptr;
#define WRITE(s) write(1, s, sizeof(s))
// Note: avoid calling functions that allocate memory in malloc/free
// to avoid infinite recursion.
void __sanitizer_malloc_hook(const volatile void *ptr, size_t sz) {
if (__sanitizer_get_ownership(ptr) && sz == 4) {
write(1, "MallocHook\n", sizeof("MallocHook\n"));
WRITE("MallocHook\n");
global_ptr = ptr;
}
}
void __sanitizer_free_hook(const volatile void *ptr) {
if (__sanitizer_get_ownership(ptr) && ptr == global_ptr)
write(1, "FreeHook\n", sizeof("FreeHook\n"));
WRITE("FreeHook\n");
}
} // extern "C"
volatile int *x;
void MallocHook1(const volatile void *ptr, size_t sz) { WRITE("MH1\n"); }
void MallocHook2(const volatile void *ptr, size_t sz) { WRITE("MH2\n"); }
void FreeHook1(const volatile void *ptr) { WRITE("FH1\n"); }
void FreeHook2(const volatile void *ptr) { WRITE("FH2\n"); }
// Call this function with uninitialized arguments to poison
// TLS shadow for function parameters before calling operator
// new and, eventually, user-provided hook.
@ -34,9 +40,13 @@ __attribute__((noinline)) void allocate(int *unused1, int *unused2) {
}
int main() {
__sanitizer_install_malloc_and_free_hooks(MallocHook1, FreeHook1);
__sanitizer_install_malloc_and_free_hooks(MallocHook2, FreeHook2);
int *undef1, *undef2;
allocate(undef1, undef2);
// CHECK: MallocHook
// CHECK: MH1
// CHECK: MH2
// Check that malloc hook was called with correct argument.
if (global_ptr != (void*)x) {
_exit(1);
@ -44,5 +54,7 @@ int main() {
*x = 0;
delete x;
// CHECK: FreeHook
// CHECK: FH1
// CHECK: FH2
return 0;
}