summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/asan/Makefile.mk4
-rw-r--r--lib/asan/Makefile.old13
-rw-r--r--lib/asan/asan_interceptors.cc128
-rw-r--r--lib/asan/asan_interceptors.h61
-rw-r--r--lib/asan/asan_mac.cc23
-rw-r--r--lib/asan/asan_mac.h10
-rw-r--r--lib/asan/asan_malloc_mac.cc4
-rw-r--r--lib/asan/interception/Makefile.mk22
-rw-r--r--lib/asan/interception/interception.h136
-rw-r--r--lib/asan/interception/interception_linux.cc27
-rw-r--r--lib/asan/interception/interception_linux.h33
-rw-r--r--lib/asan/interception/interception_mac.cc34
-rw-r--r--lib/asan/interception/interception_mac.h47
13 files changed, 364 insertions, 178 deletions
diff --git a/lib/asan/Makefile.mk b/lib/asan/Makefile.mk
index bc8c1c6e0..358e0d1e8 100644
--- a/lib/asan/Makefile.mk
+++ b/lib/asan/Makefile.mk
@@ -8,7 +8,7 @@
#===------------------------------------------------------------------------===#
ModuleName := asan
-SubDirs := mach_override
+SubDirs := interception mach_override
Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
ObjNames := $(Sources:%.cc=%.o)
@@ -17,6 +17,8 @@ Implementation := Generic
# FIXME: use automatic dependencies?
Dependencies := $(wildcard $(Dir)/*.h)
+Dependencies += $(wildcard $(Dir)/interception/*.h)
+Dependencies += $(wildcard $(Dir)/mach_override/*.h)
# Define a convenience variable for all the asan functions.
AsanFunctions := $(Sources:%.cc=%)
diff --git a/lib/asan/Makefile.old b/lib/asan/Makefile.old
index 18d2b1b15..744475ab7 100644
--- a/lib/asan/Makefile.old
+++ b/lib/asan/Makefile.old
@@ -178,6 +178,9 @@ RTL_HDR=asan_allocator.h \
asan_stats.h \
asan_thread.h \
asan_thread_registry.h \
+ interception/interception.h \
+ interception/interception_linux.h \
+ interception/interception_mac.h \
mach_override/mach_override.h
LIBASAN_OBJ=$(BIN)/asan_rtl$(SUFF).o \
@@ -195,6 +198,8 @@ LIBASAN_OBJ=$(BIN)/asan_rtl$(SUFF).o \
$(BIN)/asan_stats$(SUFF).o \
$(BIN)/asan_thread$(SUFF).o \
$(BIN)/asan_thread_registry$(SUFF).o \
+ $(BIN)/interception/interception_linux$(SUFF).o \
+ $(BIN)/interception/interception_mac$(SUFF).o \
$(BIN)/mach_override/mach_override$(SUFF).o
GTEST_ROOT=third_party/googletest
@@ -215,9 +220,9 @@ t64: b64
t32: b32
$(BIN)/asan_test32
-b64: | $(BIN)
+b64: | mk_bin_dir
$(MAKE) -f $(MAKEFILE) ARCH=x86_64 asan_test asan_benchmarks
-b32: | $(BIN)
+b32: | mk_bin_dir
$(MAKE) -f $(MAKEFILE) ARCH=i386 asan_test asan_benchmarks
lib64:
@@ -225,8 +230,9 @@ lib64:
lib32:
$(MAKE) $(MAKEFILE) ARCH=i386 lib
-$(BIN):
+mk_bin_dir:
mkdir -p $(BIN)
+ mkdir -p $(BIN)/interception
mkdir -p $(BIN)/mach_override
clang:
@@ -330,6 +336,7 @@ ADDRESS_SANITIZER_CPP=../../../../lib/Transforms/Instrumentation/AddressSanitize
lint:
third_party/cpplint/cpplint.py --filter=$(LLVM_LINT_FILTER) $(ADDRESS_SANITIZER_CPP)
third_party/cpplint/cpplint.py --filter=$(RTL_LINT_FITLER) asan_*.cc asan_*.h
+ third_party/cpplint/cpplint.py --filter=$(RTL_LINT_FITLER) interception/interception*.h interception/interception*.cc
third_party/cpplint/cpplint.py --filter=$(TEST_LINT_FITLER) tests/*.cc
get_third_party:
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index 075bb6870..1be867d51 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -21,74 +21,22 @@
#include "asan_stack.h"
#include "asan_stats.h"
#include "asan_thread_registry.h"
+#include "interception/interception.h"
#include <new>
#include <ctype.h>
#ifndef _WIN32
-#include <dlfcn.h>
#include <pthread.h>
-#endif
+#endif // _WIN32
-// To replace weak system functions on Linux we just need to declare functions
-// with same names in our library and then obtain the real function pointers
-// using dlsym(). This is not so on Mac OS, where the two-level namespace makes
-// our replacement functions invisible to other libraries. This may be overcomed
-// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
-// libraries in Chromium were noticed when doing so.
-// Instead we use mach_override, a handy framework for patching functions at
-// runtime. To avoid possible name clashes, our replacement functions have
-// the "wrap_" prefix on Mac.
-//
-// After interception, the calls to system functions will be substituted by
-// calls to our interceptors. We store pointers to system function f()
-// in __asan::real_f().
#if defined(__APPLE__)
-// Include the declarations of the original functions.
+// FIXME(samsonov): Gradually replace system headers with declarations of
+// intercepted functions.
#include <signal.h>
#include <string.h>
#include <strings.h>
-
-#include "mach_override/mach_override.h"
-
-#define OVERRIDE_FUNCTION(oldfunc, newfunc) \
- do {CHECK(0 == __asan_mach_override_ptr_custom((void*)(oldfunc), \
- (void*)(newfunc), \
- (void**)&real_##oldfunc, \
- __asan_allocate_island, \
- __asan_deallocate_island)); \
- CHECK(real_##oldfunc != NULL); } while (0)
-
-#define OVERRIDE_FUNCTION_IF_EXISTS(oldfunc, newfunc) \
- do { __asan_mach_override_ptr_custom((void*)(oldfunc), \
- (void*)(newfunc), \
- (void**)&real_##oldfunc, \
- __asan_allocate_island, \
- __asan_deallocate_island); \
- } while (0)
-
-#define INTERCEPT_FUNCTION(func) \
- OVERRIDE_FUNCTION(func, WRAP(func))
-
-#define INTERCEPT_FUNCTION_IF_EXISTS(func) \
- OVERRIDE_FUNCTION_IF_EXISTS(func, WRAP(func))
-
-#elif defined(_WIN32)
-// TODO(timurrrr): change these macros once we decide how to intercept
-// functions on Windows.
-#define INTERCEPT_FUNCTION(func) \
- do { } while (0)
-
-#define INTERCEPT_FUNCTION_IF_EXISTS(func) \
- do { } while (0)
-
-#else // __linux__
-#define INTERCEPT_FUNCTION(func) \
- CHECK((real_##func = (func##_f)dlsym(RTLD_NEXT, #func)));
-
-#define INTERCEPT_FUNCTION_IF_EXISTS(func) \
- do { real_##func = (func##_f)dlsym(RTLD_NEXT, #func); } while (0)
-#endif
+#endif // __APPLE__
namespace __asan {
@@ -581,12 +529,12 @@ INTERCEPTOR(size_t, strnlen, const char *s, size_t maxlen) {
namespace __asan {
void InitializeAsanInterceptors() {
#ifndef __APPLE__
- INTERCEPT_FUNCTION(index);
+ CHECK(INTERCEPT_FUNCTION(index));
#else
- OVERRIDE_FUNCTION(index, WRAP(strchr));
+ CHECK(OVERRIDE_FUNCTION(index, WRAP(strchr)));
#endif
- INTERCEPT_FUNCTION(memcmp);
- INTERCEPT_FUNCTION(memmove);
+ CHECK(INTERCEPT_FUNCTION(memcmp));
+ CHECK(INTERCEPT_FUNCTION(memmove));
#ifdef __APPLE__
// Wrap memcpy() on OS X 10.6 only, because on 10.7 memcpy() and memmove()
// are resolved into memmove$VARIANT$sse42.
@@ -594,44 +542,44 @@ void InitializeAsanInterceptors() {
// TODO(glider): need to check dynamically that memcpy() and memmove() are
// actually the same function.
if (GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD) {
- INTERCEPT_FUNCTION(memcpy);
+ CHECK(INTERCEPT_FUNCTION(memcpy));
} else {
REAL(memcpy) = REAL(memmove);
}
#else
// Always wrap memcpy() on non-Darwin platforms.
- INTERCEPT_FUNCTION(memcpy);
+ CHECK(INTERCEPT_FUNCTION(memcpy));
#endif
- INTERCEPT_FUNCTION(memset);
- INTERCEPT_FUNCTION(strcasecmp);
- INTERCEPT_FUNCTION(strcat); // NOLINT
- INTERCEPT_FUNCTION(strchr);
- INTERCEPT_FUNCTION(strcmp);
- INTERCEPT_FUNCTION(strcpy); // NOLINT
- INTERCEPT_FUNCTION(strdup);
- INTERCEPT_FUNCTION(strlen);
- INTERCEPT_FUNCTION(strncasecmp);
- INTERCEPT_FUNCTION(strncmp);
- INTERCEPT_FUNCTION(strncpy);
-
- INTERCEPT_FUNCTION(sigaction);
- INTERCEPT_FUNCTION(signal);
- INTERCEPT_FUNCTION(longjmp);
- INTERCEPT_FUNCTION(_longjmp);
- INTERCEPT_FUNCTION_IF_EXISTS(__cxa_throw);
- INTERCEPT_FUNCTION(pthread_create);
+ CHECK(INTERCEPT_FUNCTION(memset));
+ CHECK(INTERCEPT_FUNCTION(strcasecmp));
+ CHECK(INTERCEPT_FUNCTION(strcat)); // NOLINT
+ CHECK(INTERCEPT_FUNCTION(strchr));
+ CHECK(INTERCEPT_FUNCTION(strcmp));
+ CHECK(INTERCEPT_FUNCTION(strcpy)); // NOLINT
+ CHECK(INTERCEPT_FUNCTION(strdup));
+ CHECK(INTERCEPT_FUNCTION(strlen));
+ CHECK(INTERCEPT_FUNCTION(strncasecmp));
+ CHECK(INTERCEPT_FUNCTION(strncmp));
+ CHECK(INTERCEPT_FUNCTION(strncpy));
+
+ CHECK(INTERCEPT_FUNCTION(sigaction));
+ CHECK(INTERCEPT_FUNCTION(signal));
+ CHECK(INTERCEPT_FUNCTION(longjmp));
+ CHECK(INTERCEPT_FUNCTION(_longjmp));
+ INTERCEPT_FUNCTION(__cxa_throw);
+ CHECK(INTERCEPT_FUNCTION(pthread_create));
#ifdef __APPLE__
- INTERCEPT_FUNCTION(dispatch_async_f);
- INTERCEPT_FUNCTION(dispatch_sync_f);
- INTERCEPT_FUNCTION(dispatch_after_f);
- INTERCEPT_FUNCTION(dispatch_barrier_async_f);
- INTERCEPT_FUNCTION(dispatch_group_async_f);
+ CHECK(INTERCEPT_FUNCTION(dispatch_async_f));
+ CHECK(INTERCEPT_FUNCTION(dispatch_sync_f));
+ CHECK(INTERCEPT_FUNCTION(dispatch_after_f));
+ CHECK(INTERCEPT_FUNCTION(dispatch_barrier_async_f));
+ CHECK(INTERCEPT_FUNCTION(dispatch_group_async_f));
// We don't need to intercept pthread_workqueue_additem_np() to support the
// libdispatch API, but it helps us to debug the unsupported functions. Let's
// intercept it only during verbose runs.
if (FLAG_v >= 2) {
- INTERCEPT_FUNCTION(pthread_workqueue_additem_np);
+ CHECK(INTERCEPT_FUNCTION(pthread_workqueue_additem_np));
}
// Normally CFStringCreateCopy should not copy constant CF strings.
// Replacing the default CFAllocator causes constant strings to be copied
@@ -640,15 +588,15 @@ void InitializeAsanInterceptors() {
// http://code.google.com/p/address-sanitizer/issues/detail?id=10
// Until this problem is fixed we need to check that the string is
// non-constant before calling CFStringCreateCopy.
- INTERCEPT_FUNCTION(CFStringCreateCopy);
+ CHECK(INTERCEPT_FUNCTION(CFStringCreateCopy));
#else
// On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it
// there.
- INTERCEPT_FUNCTION(siglongjmp);
+ CHECK(INTERCEPT_FUNCTION(siglongjmp));
#endif
#ifndef __APPLE__
- INTERCEPT_FUNCTION(strnlen);
+ CHECK(INTERCEPT_FUNCTION(strnlen));
#endif
if (FLAG_v > 0) {
Printf("AddressSanitizer: libc interceptors initialized\n");
diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h
index 665339aba..93ec87b0b 100644
--- a/lib/asan/asan_interceptors.h
+++ b/lib/asan/asan_interceptors.h
@@ -15,66 +15,7 @@
#define ASAN_INTERCEPTORS_H
#include "asan_internal.h"
-
-// Suppose you need to wrap/replace system function (generally, from libc):
-// int foo(const char *bar, double baz);
-// You'll need to:
-// 1) define INTERCEPT(int, foo, const char *bar, double baz) { ... }
-// 2) add a line "INTERCEPT_FUNCTION(foo)" to InitializeAsanInterceptors()
-// You can access original function by calling __asan::real_foo(bar, baz).
-// By defualt, real_foo will be visible only inside your interceptor, and if
-// you want to use it in other parts of RTL, you'll need to:
-// 3a) add DECLARE_REAL(int, foo, const char*, double); to a
-// header file.
-// However, if you want to implement your interceptor somewhere outside
-// asan_interceptors.cc, you'll instead need to:
-// 3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double);
-// to a header.
-
-#if defined(__APPLE__)
-# define WRAP(x) wrap_##x
-# define WRAPPER_NAME(x) "wrap_"#x
-# define INTERCEPTOR_ATTRIBUTE
-#elif defined(_WIN32)
-// TODO(timurrrr): we're likely to use something else later on Windows.
-# define WRAP(x) wrap_##x
-# define WRAPPER_NAME(x) #x
-# define INTERCEPTOR_ATTRIBUTE
-#else
-# define WRAP(x) x
-# define WRAPPER_NAME(x) #x
-# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
-#endif
-
-#define REAL(x) real_##x
-#define FUNC_TYPE(x) x##_f
-
-#define DECLARE_REAL(ret_type, func, ...); \
- typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
- namespace __asan { \
- extern FUNC_TYPE(func) REAL(func); \
- }
-
-#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...); \
- DECLARE_REAL(ret_type, func, ##__VA_ARGS__); \
- extern "C" \
- ret_type WRAP(func)(__VA_ARGS__);
-
-// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR
-// macros does its job. In exceptional cases you may need to call REAL(foo)
-// without defining INTERCEPTOR(..., foo, ...). For example, if you override
-// foo with interceptor for other function.
-#define DEFINE_REAL(ret_type, func, ...); \
- typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
- namespace __asan { \
- FUNC_TYPE(func) REAL(func); \
- }
-
-#define INTERCEPTOR(ret_type, func, ...); \
- DEFINE_REAL(ret_type, func, __VA_ARGS__); \
- extern "C" \
- INTERCEPTOR_ATTRIBUTE \
- ret_type WRAP(func)(__VA_ARGS__)
+#include "interception/interception.h"
DECLARE_REAL(int, memcmp, const void *a1, const void *a2, size_t size);
DECLARE_REAL(void*, memcpy, void *to, const void *from, size_t size);
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index 90f96f346..8943a4ac2 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -36,8 +36,6 @@
namespace __asan {
-void *island_allocator_pos = NULL;
-
void GetPcSpBp(void *context, uintptr_t *pc, uintptr_t *sp, uintptr_t *bp) {
ucontext_t *ucontext = (ucontext_t*)context;
# if __WORDSIZE == 64
@@ -314,25 +312,26 @@ void AsanStackTrace::GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp) {
}
}
-// The range of pages to be used by __asan_mach_override_ptr for escape
-// islands.
+// The range of pages to be used for escape islands.
// TODO(glider): instead of mapping a fixed range we must find a range of
// unmapped pages in vmmap and take them.
// These constants were chosen empirically and may not work if the shadow
// memory layout changes. Unfortunately they do necessarily depend on
// kHighMemBeg or kHighMemEnd.
+static void *island_allocator_pos = NULL;
+
#if __WORDSIZE == 32
-#define kIslandEnd (0xffdf0000 - kPageSize)
-#define kIslandBeg (kIslandEnd - 256 * kPageSize)
+# define kIslandEnd (0xffdf0000 - kPageSize)
+# define kIslandBeg (kIslandEnd - 256 * kPageSize)
#else
-#define kIslandEnd (0x7fffffdf0000 - kPageSize)
-#define kIslandBeg (kIslandEnd - 256 * kPageSize)
+# define kIslandEnd (0x7fffffdf0000 - kPageSize)
+# define kIslandBeg (kIslandEnd - 256 * kPageSize)
#endif
extern "C"
-mach_error_t __asan_allocate_island(void **ptr,
- size_t unused_size,
- void *unused_hint) {
+mach_error_t __interception_allocate_island(void **ptr,
+ size_t unused_size,
+ void *unused_hint) {
if (!island_allocator_pos) {
island_allocator_pos =
asan_mmap((void*)kIslandBeg, kIslandEnd - kIslandBeg,
@@ -349,7 +348,7 @@ mach_error_t __asan_allocate_island(void **ptr,
}
extern "C"
-mach_error_t __asan_deallocate_island(void *ptr) {
+mach_error_t __interception_deallocate_island(void *ptr) {
// Do nothing.
// TODO(glider): allow to free and reuse the island memory.
return err_none;
diff --git a/lib/asan/asan_mac.h b/lib/asan/asan_mac.h
index 506cf87bd..59993ce07 100644
--- a/lib/asan/asan_mac.h
+++ b/lib/asan/asan_mac.h
@@ -20,7 +20,6 @@
// TODO(glider): need to check if the OS X version is 10.6 or greater.
#include <dispatch/dispatch.h>
-#include <mach/mach_error.h>
#include <setjmp.h>
#include <CoreFoundation/CFString.h>
@@ -79,15 +78,6 @@ typedef struct {
extern "C" {
-// Allocate memory for the escape island. This cannot be moved to
-// mach_override, because the allocator needs to know about the ASan shadow
-// mappings.
-// TODO(glider): in order to place a relative jump the allocated memory should
-// be within 2 Gb from the hint address.
-mach_error_t __asan_allocate_island(void **ptr, size_t unused_size,
- void *unused_hint);
-mach_error_t __asan_deallocate_island(void *ptr);
-
// dispatch_barrier_async_f() is not declared in <dispatch/dispatch.h>.
void dispatch_barrier_async_f(dispatch_queue_t dq,
void *ctxt, dispatch_function_t func);
diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index d6ff2eab6..aeacc5f7d 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/lib/asan/asan_malloc_mac.cc
@@ -310,7 +310,7 @@ extern bool kCFUseCollectableAllocator; // is GC on?
namespace __asan {
void ReplaceSystemMalloc() {
static malloc_introspection_t asan_introspection;
- __asan::REAL(memset)(&asan_introspection, 0, sizeof(asan_introspection));
+ REAL(memset)(&asan_introspection, 0, sizeof(asan_introspection));
asan_introspection.enumerator = &mi_enumerator;
asan_introspection.good_size = &mi_good_size;
@@ -321,7 +321,7 @@ void ReplaceSystemMalloc() {
asan_introspection.force_unlock = &mi_force_unlock;
static malloc_zone_t asan_zone;
- __asan::REAL(memset)(&asan_zone, 0, sizeof(malloc_zone_t));
+ REAL(memset)(&asan_zone, 0, sizeof(malloc_zone_t));
// Start with a version 4 zone which is used for OS X 10.4 and 10.5.
asan_zone.version = 4;
diff --git a/lib/asan/interception/Makefile.mk b/lib/asan/interception/Makefile.mk
new file mode 100644
index 000000000..f8071a8e6
--- /dev/null
+++ b/lib/asan/interception/Makefile.mk
@@ -0,0 +1,22 @@
+#===- lib/asan/interception/Makefile.mk --------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := asan
+SubDirs :=
+
+Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+ObjNames := $(Sources:%.cc=%.o)
+
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
+
+# Define a convenience variable for all the asan functions.
+AsanFunctions += $(Sources:%.cc=%)
diff --git a/lib/asan/interception/interception.h b/lib/asan/interception/interception.h
new file mode 100644
index 000000000..14008852f
--- /dev/null
+++ b/lib/asan/interception/interception.h
@@ -0,0 +1,136 @@
+//===-- interception.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Machinery for providing replacements/wrappers for system functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef INTERCEPTION_H
+#define INTERCEPTION_H
+
+#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
+# error "Interception doesn't work on this operating system."
+#endif
+
+// How to use this library:
+// 1) Include this header to define your own interceptors
+// (see details below).
+// 2) Build all *.cc files and link against them.
+// On Mac you will also need to:
+// 3) Provide your own implementation for the following functions:
+// mach_error_t __interception::allocate_island(void **ptr,
+// size_t size,
+// void *hint);
+// mach_error_t __interception::deallocate_island(void *ptr);
+// See "interception_mac.h" for more details.
+
+// How to add an interceptor:
+// Suppose you need to wrap/replace system function (generally, from libc):
+// int foo(const char *bar, double baz);
+// You'll need to:
+// 1) define INTERCEPTOR(int, foo, const char *bar, double baz) { ... } in
+// your source file.
+// 2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo".
+// INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was
+// intercepted successfully.
+// You can access original function by calling REAL(foo)(bar, baz).
+// By default, REAL(foo) will be visible only inside your interceptor, and if
+// you want to use it in other parts of RTL, you'll need to:
+// 3a) add DECLARE_REAL(int, foo, const char*, double); to a
+// header file.
+// However, if the call "INTERCEPT_FUNCTION(foo)" and definition for
+// INTERCEPTOR(..., foo, ...) are in different files, you'll instead need to:
+// 3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double);
+// to a header file.
+
+// Notes: 1. Things may not work properly if macro INTERCEPT(...) {...} or
+// DECLARE_REAL(...); are located inside namespaces.
+// 2. On Mac you can also use: "OVERRIDE_FUNCTION(foo, zoo);" to
+// effectively redirect calls from "foo" to "zoo". In this case
+// you aren't required to implement
+// INTERCEPTOR(int, foo, const char *bar, double baz);
+// but instead you'll have to add
+// DEFINE_REAL(int, foo, const char *bar, double baz); in your
+// source file (to define a pointer to overriden function).
+
+// How it works:
+// To replace weak system functions on Linux we just need to declare functions
+// with same names in our library and then obtain the real function pointers
+// using dlsym(). This is not so on Mac OS, where the two-level namespace makes
+// our replacement functions invisible to other libraries. This may be overcomed
+// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
+// libraries in Chromium were noticed when doing so.
+// Instead we use mach_override, a handy framework for patching functions at
+// runtime. To avoid possible name clashes, our replacement functions have
+// the "wrap_" prefix on Mac.
+
+#if defined(__APPLE__)
+# define WRAP(x) wrap_##x
+# define WRAPPER_NAME(x) "wrap_"#x
+# define INTERCEPTOR_ATTRIBUTE
+#elif defined(_WIN32)
+// TODO(timurrrr): we're likely to use something else later on Windows.
+# define WRAP(x) wrap_##x
+# define WRAPPER_NAME(x) #x
+# define INTERCEPTOR_ATTRIBUTE
+#else
+# define WRAP(x) x
+# define WRAPPER_NAME(x) #x
+# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
+#endif
+
+#define PTR_TO_REAL(x) real_##x
+#define REAL(x) __interception::PTR_TO_REAL(x)
+#define FUNC_TYPE(x) x##_f
+
+#define DECLARE_REAL(ret_type, func, ...); \
+ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
+ namespace __interception { \
+ extern FUNC_TYPE(func) PTR_TO_REAL(func); \
+ }
+
+#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...); \
+ DECLARE_REAL(ret_type, func, ##__VA_ARGS__); \
+ extern "C" ret_type WRAP(func)(__VA_ARGS__);
+
+// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR
+// macros does its job. In exceptional cases you may need to call REAL(foo)
+// without defining INTERCEPTOR(..., foo, ...). For example, if you override
+// foo with an interceptor for other function.
+#define DEFINE_REAL(ret_type, func, ...); \
+ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
+ namespace __interception { \
+ FUNC_TYPE(func) PTR_TO_REAL(func); \
+ }
+
+#define INTERCEPTOR(ret_type, func, ...) \
+ DEFINE_REAL(ret_type, func, __VA_ARGS__); \
+ extern "C" \
+ INTERCEPTOR_ATTRIBUTE \
+ ret_type WRAP(func)(__VA_ARGS__)
+
+#define INCLUDED_FROM_INTERCEPTION_LIB
+
+#if defined(__linux__)
+# include "interception_linux.h"
+# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX(func)
+#elif defined(__APPLE__)
+# include "interception_mac.h"
+# define OVERRIDE_FUNCTION(old_func, new_func) \
+ OVERRIDE_FUNCTION_MAC(old_func, new_func)
+# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
+#else // defined(_WIN32)
+ // FIXME: deal with interception on Win.
+# define INTERCEPT_FUNCTON(func) true
+#endif
+
+#undef INCLUDED_FROM_INTERCEPTION_LIB
+
+#endif // INTERCEPTION_H
diff --git a/lib/asan/interception/interception_linux.cc b/lib/asan/interception/interception_linux.cc
new file mode 100644
index 000000000..db43e81e7
--- /dev/null
+++ b/lib/asan/interception/interception_linux.cc
@@ -0,0 +1,27 @@
+//===-- interception_linux.cc -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Linux-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef __linux__
+
+#include <dlfcn.h> // for dlsym
+
+namespace __interception {
+bool GetRealFunctionAddress(const char *func_name, void **func_addr) {
+ *func_addr = dlsym(RTLD_NEXT, func_name);
+ return (*func_addr != NULL);
+}
+} // namespace __interception
+
+
+#endif // __linux__
diff --git a/lib/asan/interception/interception_linux.h b/lib/asan/interception/interception_linux.h
new file mode 100644
index 000000000..214e68319
--- /dev/null
+++ b/lib/asan/interception/interception_linux.h
@@ -0,0 +1,33 @@
+//===-- interception_linux.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Linux-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef __linux__
+
+#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
+# error "interception_mac.h should be included from interception library only"
+#endif
+
+#ifndef INTERCEPTION_LINUX_H
+#define INTERCEPTION_LINUX_H
+
+namespace __interception {
+// returns true if a function with the given name was found.
+bool GetRealFunctionAddress(const char *func_name, void **func_addr);
+} // namespace __interception
+
+#define INTERCEPT_FUNCTION_LINUX(func) \
+ ::__interception::GetRealFunctionAddress(#func, (void**)&REAL(func))
+
+#endif // INTERCEPTION_LINUX_H
+#endif // __linux__
diff --git a/lib/asan/interception/interception_mac.cc b/lib/asan/interception/interception_mac.cc
new file mode 100644
index 000000000..7c63dd3bd
--- /dev/null
+++ b/lib/asan/interception/interception_mac.cc
@@ -0,0 +1,34 @@
+//===-- interception_mac.cc -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Mac-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef __APPLE__
+
+#define INCLUDED_FROM_INTERCEPTION_LIB
+#include "interception_mac.h"
+#undef INCLUDED_FROM_INTERCEPTION_LIB
+// FIXME(samsonov): Put mach_override/ under interception/
+#include "../mach_override/mach_override.h"
+
+namespace __interception {
+bool OverrideFunction(void *old_func, void *new_func, void **orig_old_func) {
+ *orig_old_func = NULL;
+ int res = __asan_mach_override_ptr_custom(old_func, new_func,
+ orig_old_func,
+ __interception_allocate_island,
+ __interception_deallocate_island);
+ return (res == 0) && (*orig_old_func != NULL);
+}
+} // namespace __interception
+
+#endif // __APPLE__
diff --git a/lib/asan/interception/interception_mac.h b/lib/asan/interception/interception_mac.h
new file mode 100644
index 000000000..224d961ee
--- /dev/null
+++ b/lib/asan/interception/interception_mac.h
@@ -0,0 +1,47 @@
+//===-- interception_mac.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Mac-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#ifdef __APPLE__
+
+#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
+# error "interception_mac.h should be included from interception.h only"
+#endif
+
+#ifndef INTERCEPTION_MAC_H
+#define INTERCEPTION_MAC_H
+
+#include <mach/mach_error.h>
+#include <stddef.h>
+
+// Allocate memory for the escape island. This cannot be moved to
+// mach_override, because each user of interceptors may specify its
+// own memory range for escape islands.
+extern "C" {
+mach_error_t __interception_allocate_island(void **ptr, size_t unused_size,
+ void *unused_hint);
+mach_error_t __interception_deallocate_island(void *ptr);
+} // extern "C"
+
+namespace __interception {
+// returns true if the old function existed.
+bool OverrideFunction(void *old_func, void *new_func, void **orig_old_func);
+} // namespace __interception
+
+# define OVERRIDE_FUNCTION_MAC(old_func, new_func) \
+ ::__interception::OverrideFunction((void*)old_func, (void*)new_func, \
+ (void**)&REAL(old_func))
+# define INTERCEPT_FUNCTION_MAC(func) OVERRIDE_FUNCTION_MAC(func, WRAP(func))
+
+#endif // INTERCEPTION_MAC_H
+#endif // __APPLE__