[llvm-commits] PATCH: AddressSanitizer: start factoring out interception machinery (issue 5642046)

samsonov at google.com samsonov at google.com
Tue Feb 7 04:30:28 PST 2012


Reviewers: kcc, ramosian.glider, timurrrr_at_google_com,



Please review this at http://codereview.appspot.com/5642046/

Affected files:
   M     Makefile.mk
   M     Makefile.old
   M     asan_interceptors.cc
   M     asan_interceptors.h
   M     asan_mac.cc
   M     asan_malloc_mac.cc
   A     interception/Makefile.mk
   A     interception/interception.h
   A     interception/interception_linux.cc
   A     interception/interception_mac.cc


-------------- next part --------------
Index: Makefile.mk
===================================================================
--- Makefile.mk	(revision 149970)
+++ Makefile.mk	(working copy)
@@ -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)
Index: Makefile.old
===================================================================
--- Makefile.old	(revision 149970)
+++ Makefile.old	(working copy)
@@ -178,6 +178,7 @@
 	asan_stats.h \
 	asan_thread.h \
 	asan_thread_registry.h \
+	interception/interception.h \
 	mach_override/mach_override.h
 
 LIBASAN_OBJ=$(BIN)/asan_rtl$(SUFF).o \
@@ -195,6 +196,8 @@
 	    $(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
@@ -226,6 +229,7 @@
 
 $(BIN):
 	mkdir -p $(BIN)
+	mkdir -p $(BIN)/interception
 	mkdir -p $(BIN)/mach_override
 
 clang:
@@ -329,6 +333,7 @@
 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:
Index: asan_interceptors.cc
===================================================================
--- asan_interceptors.cc	(revision 149970)
+++ asan_interceptors.cc	(working copy)
@@ -21,75 +21,23 @@
 #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>
+#endif  // __APPLE__
 
-#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
-
 namespace __asan {
 
 // Instruments read/write access to a single byte in memory.
@@ -581,12 +529,12 @@
 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 @@
   // 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);
+  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));
 
-  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(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 @@
   // 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");
Index: asan_interceptors.h
===================================================================
--- asan_interceptors.h	(revision 149970)
+++ asan_interceptors.h	(working copy)
@@ -15,67 +15,8 @@
 #define ASAN_INTERCEPTORS_H
 
 #include "asan_internal.h"
+#include "interception/interception.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__)
-
 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);
 DECLARE_REAL(void*, memset, void *block, int c, size_t size);
Index: asan_mac.cc
===================================================================
--- asan_mac.cc	(revision 149970)
+++ asan_mac.cc	(working copy)
@@ -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,47 +312,6 @@
   }
 }
 
-// The range of pages to be used by __asan_mach_override_ptr 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.
-#if __WORDSIZE == 32
-#define kIslandEnd (0xffdf0000 - kPageSize)
-#define kIslandBeg (kIslandEnd - 256 * kPageSize)
-#else
-#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) {
-  if (!island_allocator_pos) {
-    island_allocator_pos =
-        asan_mmap((void*)kIslandBeg, kIslandEnd - kIslandBeg,
-                  PROT_READ | PROT_WRITE | PROT_EXEC,
-                  MAP_PRIVATE | MAP_ANON | MAP_FIXED,
-                 -1, 0);
-    if (island_allocator_pos != (void*)kIslandBeg) {
-      return KERN_NO_SPACE;
-    }
-  };
-  *ptr = island_allocator_pos;
-  island_allocator_pos = (char*)island_allocator_pos + kPageSize;
-  return err_none;
-}
-
-extern "C"
-mach_error_t __asan_deallocate_island(void *ptr) {
-  // Do nothing.
-  // TODO(glider): allow to free and reuse the island memory.
-  return err_none;
-}
-
 // Support for the following functions from libdispatch on Mac OS:
 //   dispatch_async_f()
 //   dispatch_async()
Index: interception/Makefile.mk
===================================================================
--- interception/Makefile.mk	(revision 0)
+++ interception/Makefile.mk	(revision 0)
@@ -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=%)
Index: interception/interception_linux.cc
===================================================================
--- interception/interception_linux.cc	(revision 0)
+++ interception/interception_linux.cc	(revision 0)
@@ -0,0 +1,22 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+// Author: samsonov at google.com (Alexey Samsonov)
+
+#ifdef __linux__
+
+#include "interception.h"
+#include <dlfcn.h>  // for dlsym
+
+extern "C"
+bool OverrideFunction(void *old_func, void *new_func, void **orig_old_func) {
+  // not implemented
+  return false;
+}
+
+extern "C"
+bool GetRealFunctionAddress(const char *func_name,
+                            void **func_addr) {
+  *func_addr = dlsym(RTLD_NEXT, func_name);
+  return (*func_addr != NULL);
+}
+
+#endif  // __linux__
Index: interception/interception_mac.cc
===================================================================
--- interception/interception_mac.cc	(revision 0)
+++ interception/interception_mac.cc	(revision 0)
@@ -0,0 +1,83 @@
+//===-- 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__
+
+#include "interception.h"
+#include "../mach_override/mach_override.h"
+#include <stddef.h>  // for NULL
+#include <sys/mman.h>  // for mmap
+
+// The range of pages to be used by __asan_mach_override_ptr 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 const size_t kPageSizeBits = 12;
+static const size_t kPageSize = 1UL << kPageSizeBits;
+static void *island_allocator_pos = NULL;
+
+#if __WORDSIZE == 32
+# define kIslandEnd (0xffdf0000 - kPageSize)
+# define kIslandBeg (kIslandEnd - 256 * kPageSize)
+#else
+# 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) {
+  if (!island_allocator_pos) {
+    island_allocator_pos =
+        mmap((void*)kIslandBeg, kIslandEnd - kIslandBeg,
+                  PROT_READ | PROT_WRITE | PROT_EXEC,
+                  MAP_PRIVATE | MAP_ANON | MAP_FIXED,
+                 -1, 0);
+    if (island_allocator_pos != (void*)kIslandBeg) {
+      return KERN_NO_SPACE;
+    }
+  };
+  *ptr = island_allocator_pos;
+  island_allocator_pos = (char*)island_allocator_pos + kPageSize;
+  return err_none;
+}
+
+extern "C"
+mach_error_t __asan_deallocate_island(void *ptr) {
+  // Do nothing.
+  // TODO(glider): allow to free and reuse the island memory.
+  return err_none;
+}
+
+extern "C"
+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,
+                                            __asan_allocate_island,
+                                            __asan_deallocate_island);
+  return (res == 0) && (*orig_old_func != NULL);
+}
+
+extern "C"
+bool GetRealFunctionAddress(const char *func_name, void **func_addr) {
+  // not implemented
+  return false;
+}
+
+#endif  // __APPLE__
Index: interception/interception.h
===================================================================
--- interception/interception.h	(revision 0)
+++ interception/interception.h	(revision 0)
@@ -0,0 +1,117 @@
+//===-- 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
+
+// How to use:
+// 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 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.
+
+// Notes: 1. Things may not work properly if macro INTERCEPT(...) {...} or
+//           DECLARE_REAL(...); will be 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 REAL(x) real_##x
+#define FUNC_TYPE(x) x##_f
+
+#define DECLARE_REAL(ret_type, func, ...); \
+  typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
+  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__); \
+  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__)
+
+extern "C" {
+// returns true if the old function existed.
+bool OverrideFunction(void *old_func, void *new_func, void **orig_old_func);
+// returns true if a function with the given name was found.
+bool GetRealFunctionAddress(const char *func_name, void **func_addr);
+}  // extern "C"
+
+#if defined(__linux__)
+# define INTERCEPT_FUNCTION(func) \
+    GetRealFunctionAddress(#func, (void**)&REAL(func))
+#elif defined(__APPLE__)
+# define OVERRIDE_FUNCTION(old_func, new_func) \
+    OverrideFunction((void*)old_func, (void*)new_func, (void**)&REAL(old_func))
+# define INTERCEPT_FUNCTION(func) OVERRIDE_FUNCTION(func, WRAP(func))
+#else  // defined(_WIN32)
+  // FIXME: deal with interception on Win.
+# define INTERCEPT_FUNCTON(func) true
+#endif
+
+#endif  // INTERCEPTION_H
Index: asan_malloc_mac.cc
===================================================================
--- asan_malloc_mac.cc	(revision 149970)
+++ asan_malloc_mac.cc	(working copy)
@@ -310,7 +310,7 @@
 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 @@
   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;


More information about the llvm-commits mailing list