am bb59ba11: Merge "x86_64/x32: Avoid early exit of any other project build"

* commit 'bb59ba11bac59fbe316398f1c83c8bce7aa03d4f':
  x86_64/x32: Avoid early exit of any other project build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 90062cd..21fdf29 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,10 +23,10 @@
 # Setup the paths where compiler-rt runtimes and headers should be stored.
 set(LIBCLANG_INSTALL_PATH lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION})
 string(TOLOWER ${CMAKE_SYSTEM_NAME} LIBCLANG_OS_DIR)
-set(COMPILER_RT_LIBRARY_OUTPUT_DIR 
-  ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/lib/${LIBCLANG_OS_DIR})
+set(CLANG_RESOURCE_DIR ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION})
+set(COMPILER_RT_LIBRARY_OUTPUT_DIR ${CLANG_RESOURCE_DIR}/lib/${LIBCLANG_OS_DIR})
 set(COMPILER_RT_LIBRARY_INSTALL_DIR
- ${LIBCLANG_INSTALL_PATH}/lib/${LIBCLANG_OS_DIR}) 
+  ${LIBCLANG_INSTALL_PATH}/lib/${LIBCLANG_OS_DIR})
 
 # Add path for custom modules
 set(CMAKE_MODULE_PATH
@@ -36,19 +36,19 @@
 include(AddCompilerRT)
 
 set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(COMPILER_RT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+# Setup custom SDK sysroots.
+set(COMPILER_RT_DARWIN_SDK_SYSROOT ${COMPILER_RT_SOURCE_DIR}/SDKs/darwin)
+set(COMPILER_RT_LINUX_SDK_SYSROOT ${COMPILER_RT_SOURCE_DIR}/SDKs/linux)
 
 # Detect whether the current target platform is 32-bit or 64-bit, and setup
 # the correct commandline flags needed to attempt to target 32-bit and 64-bit.
-if(CMAKE_SIZEOF_VOID_P EQUAL 4 OR LLVM_BUILD_32_BITS)
-  set(TARGET_64_BIT_CFLAGS "-m64")
-  set(TARGET_32_BIT_CFLAGS "")
-else()
-  if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
-    message(FATAL_ERROR "Please use a sane architecture with 4 or 8 byte pointers.")
-  endif()
-  set(TARGET_64_BIT_CFLAGS "")
-  set(TARGET_32_BIT_CFLAGS "-m32")
+if (NOT CMAKE_SIZEOF_VOID_P EQUAL 4 AND
+    NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
+  message(FATAL_ERROR "Please use architecture with 4 or 8 byte pointers.")
 endif()
+set(TARGET_64_BIT_CFLAGS "-m64")
+set(TARGET_32_BIT_CFLAGS "-m32")
 
 # List of architectures we can target.
 set(COMPILER_RT_SUPPORTED_ARCH)
@@ -86,21 +86,18 @@
   test_target_arch(x86_64 ${TARGET_64_BIT_CFLAGS})
   test_target_arch(i386 ${TARGET_32_BIT_CFLAGS})
 elseif("${LLVM_NATIVE_ARCH}" STREQUAL "PowerPC")
-  # Explicitly set -m flag on powerpc, because on ppc64 defaults for gcc and
-  # clang are different.
-  test_target_arch(powerpc64 "-m64")
-  test_target_arch(powerpc "-m32")
+  test_target_arch(powerpc64 ${TARGET_64_BIT_CFLAGS})
 endif()
 
 # We only support running instrumented tests when we're not cross compiling
 # and target a unix-like system. On Android we define the rules for building
 # unit tests, but don't execute them.
 if("${CMAKE_HOST_SYSTEM}" STREQUAL "${CMAKE_SYSTEM}" AND UNIX AND NOT ANDROID)
-  set(COMPILER_RT_CAN_EXECUTE_TESTS TRUE)
+  option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" ON)
 else()
-  set(COMPILER_RT_CAN_EXECUTE_TESTS FALSE)
+  option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" OFF)
 endif()
-    
+
 # Check if compiler-rt is built with libc++.
 find_flag_in_string("${CMAKE_CXX_FLAGS}" "-stdlib=libc++"
                     COMPILER_RT_USES_LIBCXX)
@@ -123,6 +120,8 @@
   -fno-exceptions
   -fomit-frame-pointer
   -funwind-tables
+  -fno-stack-protector
+  -Wno-gnu  # Variadic macros with 0 arguments for ...
   -O3
   )
 if(NOT WIN32)
@@ -144,13 +143,19 @@
 if(SUPPORTS_NO_C99_EXTENSIONS_FLAG)
   list(APPEND SANITIZER_COMMON_CFLAGS -Wno-c99-extensions)
 endif()
+# Sanitizer may not have libstdc++, so we can have problems with virtual
+# destructors.
+check_cxx_compiler_flag(-Wno-non-virtual-dtor SUPPORTS_NO_NON_VIRTUAL_DTOR_FLAG)
+if (SUPPORTS_NO_NON_VIRTUAL_DTOR_FLAG)
+  list(APPEND SANITIZER_COMMON_CFLAGS -Wno-non-virtual-dtor)
+endif()
 
 # Setup min Mac OS X version.
 if(APPLE)
   if(COMPILER_RT_USES_LIBCXX)
     set(SANITIZER_MIN_OSX_VERSION 10.7)
   else()
-    set(SANITIZER_MIN_OSX_VERSION 10.5)
+    set(SANITIZER_MIN_OSX_VERSION 10.6)
   endif()
   list(APPEND SANITIZER_COMMON_CFLAGS
     -mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
@@ -159,51 +164,15 @@
 # Architectures supported by Sanitizer runtimes. Specific sanitizers may
 # support only subset of these (e.g. TSan works on x86_64 only).
 filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
-  x86_64 i386 powerpc64 powerpc)
-
-file(GLOB_RECURSE COMPILER_RT_HEADERS
-  RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/include"
-  "include/*.h")
-
-set(output_dir ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/include)
-
-if(MSVC_IDE OR XCODE)
-   set(other_output_dir ${LLVM_BINARY_DIR}/bin/lib/clang/${CLANG_VERSION}/include)
-endif()
-
-# Copy compiler-rt headers to the build tree.
-set(out_files)
-foreach( f ${COMPILER_RT_HEADERS} )
-  set( src ${CMAKE_CURRENT_SOURCE_DIR}/include/${f} )
-  set( dst ${output_dir}/${f} )
-  add_custom_command(OUTPUT ${dst}
-    DEPENDS ${src}
-    COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
-    COMMENT "Copying compiler-rt's ${f}...")
-  list(APPEND out_files ${dst})
-
-  if(other_output_dir)
-   set(other_dst ${other_output_dir}/${f})
-    add_custom_command(OUTPUT ${other_dst}
-      DEPENDS ${src}
-      COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${other_dst}
-      COMMENT "Copying compiler-rt's ${f}...")    
-    list(APPEND out_files ${other_dst})
-  endif()
-endforeach( f )
-
-add_custom_target(compiler-rt-headers ALL DEPENDS ${out_files})
-
-# Install compiler-rt headers.
-install(DIRECTORY include/
-  DESTINATION ${LIBCLANG_INSTALL_PATH}/include
-  FILES_MATCHING
-  PATTERN "*.h"
-  PATTERN ".svn" EXCLUDE
-  )
+  x86_64 i386 powerpc64)
 
 # Add the public header's directory to the includes for all of compiler-rt.
 include_directories(include)
+add_subdirectory(include)
+
+set(SANITIZER_COMMON_LIT_TEST_DEPS
+  clang clang-headers FileCheck count not llvm-nm llvm-symbolizer
+  compiler-rt-headers)
 
 add_subdirectory(lib)
 
diff --git a/Makefile b/Makefile
index 63b0536..6747ea4 100644
--- a/Makefile
+++ b/Makefile
@@ -255,10 +255,10 @@
 	$(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c -o $$@ $$<
 $(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.c $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
 	$(Summary) "  COMPILE:   $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
-	$(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c $(COMMON_CFLAGS) -o $$@ $$<
+	$(Verb) $(Tmp.CC) $(COMMON_CFLAGS) $(Tmp.CFLAGS) -c -o $$@ $$<
 $(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.cc $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
 	$(Summary) "  COMPILE:   $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
-	$(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c $(COMMON_CXXFLAGS) -o $$@ $$<
+	$(Verb) $(Tmp.CC) $(COMMON_CXXFLAGS) $(Tmp.CFLAGS) -c -o $$@ $$<
 .PRECIOUS: $(Tmp.ObjPath)/.dir
 
 endef
diff --git a/README.android b/README.android
index 5d987f6..26a853a 100644
--- a/README.android
+++ b/README.android
@@ -15,7 +15,11 @@
 * For JellyBean: Synced to upstream r155350
 * For JellyBean MR1: Synced to upstream r162279
 * For Jellybean MR2: Synced to upstream r177337
+* For Key Lime Pie: Synced to upstream r187889
 
+* Recent downstreaming on 2013/8/8: Synced to r187889 (Contact srhines for merge questions.)
+* Recent downstreaming on 2013/6/13: Synced to r183849 (Contact srhines for merge questions.)
+* Recent downstreaming on 2013/5/3: Synced to r180792 (Contact srhines for merge questions.)
 * Recent downstreaming on 2013/3/18: Synced to r177337 (Contact srhines for merge questions.)
 * Recent downstreaming on 2013/3/5: Synced to r176091 (Contact srhines for merge questions.)
 * Recent downstreaming on 2013/1/8: Synced to r171802 (Contact srhines for merge questions.)
diff --git a/SDKs/darwin/usr/include/errno.h b/SDKs/darwin/usr/include/errno.h
new file mode 100644
index 0000000..f06e537
--- /dev/null
+++ b/SDKs/darwin/usr/include/errno.h
@@ -0,0 +1,17 @@
+/* ===-- errno.h - stub SDK header for compiler-rt --------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===-----------------------------------------------------------------------===
+ *
+ * This is a stub SDK header file. This file is not part of the interface of
+ * this library nor an official version of the appropriate SDK header. It is
+ * intended only to stub the features of this header required by compiler-rt.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#include <sys/errno.h>
diff --git a/SDKs/darwin/usr/include/fcntl.h b/SDKs/darwin/usr/include/fcntl.h
new file mode 100644
index 0000000..a5f91e3
--- /dev/null
+++ b/SDKs/darwin/usr/include/fcntl.h
@@ -0,0 +1,17 @@
+/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===-----------------------------------------------------------------------===
+ *
+ * This is a stub SDK header file. This file is not part of the interface of
+ * this library nor an official version of the appropriate SDK header. It is
+ * intended only to stub the features of this header required by compiler-rt.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#include <sys/fcntl.h>
diff --git a/SDKs/darwin/usr/include/stdio.h b/SDKs/darwin/usr/include/stdio.h
index 63b10a8..006652f 100644
--- a/SDKs/darwin/usr/include/stdio.h
+++ b/SDKs/darwin/usr/include/stdio.h
@@ -24,15 +24,18 @@
 typedef struct __sFILE FILE;
 typedef __SIZE_TYPE__ size_t;
 
-/* Determine the appropriate fopen() and fwrite() functions. */
+/* Determine the appropriate fdopen, fopen(), and fwrite() functions. */
 #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
 #  if defined(__i386)
+#    define __FDOPEN_NAME  "_fdopen$UNIX2003"
 #    define __FOPEN_NAME "_fopen$UNIX2003"
 #    define __FWRITE_NAME "_fwrite$UNIX2003"
 #  elif defined(__x86_64__)
+#    define __FDOPEN_NAME  "_fdopen"
 #    define __FOPEN_NAME "_fopen"
 #    define __FWRITE_NAME "_fwrite"
 #  elif defined(__arm)
+#    define __FDOPEN_NAME  "_fdopen"
 #    define __FOPEN_NAME "_fopen"
 #    define __FWRITE_NAME "_fwrite"
 #  else
@@ -40,9 +43,11 @@
 #  endif
 #elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
 #  if defined(__i386) || defined (__x86_64)
+#    define __FDOPEN_NAME  "_fdopen"
 #    define __FOPEN_NAME "_fopen"
 #    define __FWRITE_NAME "_fwrite"
 #  elif defined(__arm)
+#    define __FDOPEN_NAME  "_fdopen"
 #    define __FOPEN_NAME "_fopen"
 #    define __FWRITE_NAME "_fwrite"
 #  else
@@ -68,13 +73,13 @@
 int fclose(FILE *);
 int fflush(FILE *);
 FILE *fopen(const char * __restrict, const char * __restrict) __asm(__FOPEN_NAME);
+FILE *fdopen(int, const char *) __asm(__FDOPEN_NAME);
 int fprintf(FILE * __restrict, const char * __restrict, ...);
 size_t fwrite(const void * __restrict, size_t, size_t, FILE * __restrict)
   __asm(__FWRITE_NAME);
 size_t fread(void * __restrict, size_t, size_t, FILE * __restrict);
 long ftell(FILE *);
 int fseek(FILE *, long, int);
-
 int snprintf(char * __restrict, size_t, const char * __restrict, ...);
 
 #if defined(__cplusplus)
diff --git a/SDKs/darwin/usr/include/stdlib.h b/SDKs/darwin/usr/include/stdlib.h
index c18c2e4..b6d3171 100644
--- a/SDKs/darwin/usr/include/stdlib.h
+++ b/SDKs/darwin/usr/include/stdlib.h
@@ -22,9 +22,11 @@
 typedef __SIZE_TYPE__ size_t;
 
 void abort(void) __attribute__((__noreturn__));
+int atexit(void (*)(void));
 int atoi(const char *);
 void free(void *);
 char *getenv(const char *);
 void *malloc(size_t);
+void *realloc(void *, size_t);
 
 #endif /* __STDLIB_H__ */
diff --git a/SDKs/darwin/usr/include/string.h b/SDKs/darwin/usr/include/string.h
index bee9d46..c6ab5d8 100644
--- a/SDKs/darwin/usr/include/string.h
+++ b/SDKs/darwin/usr/include/string.h
@@ -21,10 +21,32 @@
 
 int memcmp(const void *, const void *, size_t);
 void *memcpy(void *, const void *, size_t);
+void *memset(void *, int, size_t);
 char *strcat(char *, const char *);
 char *strcpy(char *, const char *);
 char *strdup(const char *);
 size_t strlen(const char *);
 char *strncpy(char *, const char *, size_t);
 
+/* Determine the appropriate strerror() function. */
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
+#  if defined(__i386)
+#    define __STRERROR_NAME  "_strerror$UNIX2003"
+#  elif defined(__x86_64__) || defined(__arm)
+#    define __STRERROR_NAME  "_strerror"
+#  else
+#    error "unrecognized architecture for targetting OS X"
+#  endif
+#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
+#  if defined(__i386) || defined (__x86_64) || defined(__arm)
+#    define __STRERROR_NAME  "_strerror"
+#  else
+#    error "unrecognized architecture for targetting iOS"
+#  endif
+#else
+#  error "unrecognized architecture for targetting Darwin"
+#endif
+
+char *strerror(int) __asm(__STRERROR_NAME);
+
 #endif /* __STRING_H__ */
diff --git a/SDKs/darwin/usr/include/sys/errno.h b/SDKs/darwin/usr/include/sys/errno.h
new file mode 100644
index 0000000..4befe38
--- /dev/null
+++ b/SDKs/darwin/usr/include/sys/errno.h
@@ -0,0 +1,31 @@
+/* ===-- errno.h - stub SDK header for compiler-rt --------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===-----------------------------------------------------------------------===
+ *
+ * This is a stub SDK header file. This file is not part of the interface of
+ * this library nor an official version of the appropriate SDK header. It is
+ * intended only to stub the features of this header required by compiler-rt.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#ifndef _SYS_ERRNO_H_
+#define _SYS_ERRNO_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern int *__error(void);
+#define errno (*__error())
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/SDKs/darwin/usr/include/sys/fcntl.h b/SDKs/darwin/usr/include/sys/fcntl.h
new file mode 100644
index 0000000..b71706b
--- /dev/null
+++ b/SDKs/darwin/usr/include/sys/fcntl.h
@@ -0,0 +1,52 @@
+/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===-----------------------------------------------------------------------===
+ *
+ * This is a stub SDK header file. This file is not part of the interface of
+ * this library nor an official version of the appropriate SDK header. It is
+ * intended only to stub the features of this header required by compiler-rt.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#ifndef _SYS_FCNTL_H_
+#define _SYS_FCNTL_H_
+
+/* Determine the appropriate open function. */
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
+#  if defined(__i386)
+#    define __OPEN_NAME  "_open$UNIX2003"
+#  elif defined(__x86_64__)
+#    define __OPEN_NAME  "_open"
+#  elif defined(__arm)
+#    define __OPEN_NAME  "_open"
+#  else
+#    error "unrecognized architecture for targetting OS X"
+#  endif
+#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
+#  if defined(__i386) || defined (__x86_64)
+#    define __OPEN_NAME  "_open"
+#  elif defined(__arm)
+#    define __OPEN_NAME  "_open"
+#  else
+#    error "unrecognized architecture for targetting iOS"
+#  endif
+#else
+#  error "unrecognized architecture for targetting Darwin"
+#endif
+
+#define O_RDONLY   0x0000    /* open for reading only */
+#define O_WRONLY   0x0001    /* open for writing only */
+#define O_RDWR     0x0002    /* open for reading and writing */
+#define O_ACCMODE  0x0003    /* mask for above modes */
+
+#define O_CREAT    0x0200    /* create if nonexistant */
+
+int open(const char *, int, ...) __asm(__OPEN_NAME);
+
+#endif /* !_SYS_FCNTL_H_ */
diff --git a/SDKs/darwin/usr/include/sys/mman.h b/SDKs/darwin/usr/include/sys/mman.h
new file mode 100644
index 0000000..84561f1
--- /dev/null
+++ b/SDKs/darwin/usr/include/sys/mman.h
@@ -0,0 +1,42 @@
+/* ===-- mman.h - stub SDK header for compiler-rt ---------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===-----------------------------------------------------------------------===
+ *
+ * This is a stub SDK header file. This file is not part of the interface of
+ * this library nor an official version of the appropriate SDK header. It is
+ * intended only to stub the features of this header required by compiler-rt.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#ifndef __SYS_MMAN_H__
+#define __SYS_MMAN_H__
+
+typedef __SIZE_TYPE__ size_t;
+
+#define PROT_NONE     0x00
+#define PROT_READ     0x01
+#define PROT_WRITE    0x02
+#define PROT_EXEC     0x04
+
+#define MAP_SHARED    0x0001
+#define MAP_PRIVATE   0x0002
+
+#define MAP_FILE      0x0000
+#define MAP_ANON      0x1000
+
+#define MS_ASYNC      0x0001
+#define MS_INVALIDATE 0x0002
+#define MS_SYNC       0x0010
+
+void *mmap(void *addr, size_t len, int prot, int flags, int fd,
+           long long offset);
+int munmap(void *addr, size_t len);
+int msync(void *addr, size_t len, int flags);
+
+#endif /* __SYS_MMAN_H__ */
diff --git a/SDKs/linux/usr/include/fcntl.h b/SDKs/linux/usr/include/fcntl.h
new file mode 100644
index 0000000..a5f91e3
--- /dev/null
+++ b/SDKs/linux/usr/include/fcntl.h
@@ -0,0 +1,17 @@
+/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===-----------------------------------------------------------------------===
+ *
+ * This is a stub SDK header file. This file is not part of the interface of
+ * this library nor an official version of the appropriate SDK header. It is
+ * intended only to stub the features of this header required by compiler-rt.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#include <sys/fcntl.h>
diff --git a/SDKs/linux/usr/include/stdio.h b/SDKs/linux/usr/include/stdio.h
index 7c258d2..fba5936 100644
--- a/SDKs/linux/usr/include/stdio.h
+++ b/SDKs/linux/usr/include/stdio.h
@@ -33,6 +33,7 @@
 extern int fclose(FILE *);
 extern int fflush(FILE *);
 extern FILE *fopen(const char * restrict, const char * restrict);
+extern FILE *fdopen(int, const char * restrict);
 extern int fprintf(FILE * restrict, const char * restrict, ...);
 extern size_t fwrite(const void * restrict, size_t, size_t, FILE * restrict);
 extern size_t fread(void * restrict, size_t, size_t, FILE * restrict);
diff --git a/SDKs/linux/usr/include/stdlib.h b/SDKs/linux/usr/include/stdlib.h
index 2a6617a..966b29d 100644
--- a/SDKs/linux/usr/include/stdlib.h
+++ b/SDKs/linux/usr/include/stdlib.h
@@ -22,6 +22,7 @@
 typedef __SIZE_TYPE__ size_t;
 
 void abort(void) __attribute__((__nothrow__)) __attribute__((__noreturn__));
+int atexit(void (*)(void)) __attribute__((__nothrow__));
 int atoi(const char *) __attribute__((__nothrow__));
 void free(void *) __attribute__((__nothrow__));
 char *getenv(const char *) __attribute__((__nothrow__))
@@ -29,5 +30,7 @@
   __attribute__((__warn_unused_result__));
 void *malloc(size_t) __attribute__((__nothrow__)) __attribute((__malloc__))
      __attribute__((__warn_unused_result__));
+void *realloc(void *, size_t) __attribute__((__nothrow__)) __attribute((__malloc__))
+     __attribute__((__warn_unused_result__));
 
 #endif /* __STDLIB_H__ */
diff --git a/SDKs/linux/usr/include/string.h b/SDKs/linux/usr/include/string.h
index bee9d46..c7da1f5 100644
--- a/SDKs/linux/usr/include/string.h
+++ b/SDKs/linux/usr/include/string.h
@@ -21,6 +21,7 @@
 
 int memcmp(const void *, const void *, size_t);
 void *memcpy(void *, const void *, size_t);
+void *memset(void *, int, size_t);
 char *strcat(char *, const char *);
 char *strcpy(char *, const char *);
 char *strdup(const char *);
diff --git a/SDKs/linux/usr/include/sys/fcntl.h b/SDKs/linux/usr/include/sys/fcntl.h
new file mode 100644
index 0000000..1512bf9
--- /dev/null
+++ b/SDKs/linux/usr/include/sys/fcntl.h
@@ -0,0 +1,29 @@
+/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===-----------------------------------------------------------------------===
+ *
+ * This is a stub SDK header file. This file is not part of the interface of
+ * this library nor an official version of the appropriate SDK header. It is
+ * intended only to stub the features of this header required by compiler-rt.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#ifndef _SYS_FCNTL_H_
+#define _SYS_FCNTL_H_
+
+#define O_RDONLY   0x0000
+#define O_WRONLY   0x0001
+#define O_RDWR     0x0002
+#define O_ACCMODE  0x0003
+
+#define O_CREAT    0x0200
+
+int open(const char *, int, ...);
+
+#endif /* _SYS_FCNTL_H_ */
diff --git a/SDKs/linux/usr/include/sys/mman.h b/SDKs/linux/usr/include/sys/mman.h
index 7c4d051..bfb7f8b 100644
--- a/SDKs/linux/usr/include/sys/mman.h
+++ b/SDKs/linux/usr/include/sys/mman.h
@@ -19,10 +19,28 @@
 
 typedef __SIZE_TYPE__ size_t;
 
-#define PROT_READ 0x1
-#define PROT_WRITE 0x2
-#define PROT_EXEC 0x4
+#define PROT_NONE     0x00
+#define PROT_READ     0x01
+#define PROT_WRITE    0x02
+#define PROT_EXEC     0x04
 
+#define MAP_SHARED    0x0001
+#define MAP_PRIVATE   0x0002
+
+#define MAP_FILE      0x0000
+#define MAP_ANON      0x1000
+
+#define MS_ASYNC      0x0001
+#define MS_INVALIDATE 0x0002
+#define MS_SYNC       0x0010
+
+extern void *mmap(void *addr, size_t len, int prot, int flags, int fd,
+                  long long offset)
+  __attribute__((__nothrow__));
+extern int munmap(void *addr, size_t len)
+  __attribute__((__nothrow__));
+extern int msync(void *addr, size_t len, int flags)
+  __attribute__((__nothrow__));
 extern int mprotect (void *__addr, size_t __len, int __prot)
   __attribute__((__nothrow__));
 
diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake
index 742d81f..bf114a4 100644
--- a/cmake/Modules/AddCompilerRT.cmake
+++ b/cmake/Modules/AddCompilerRT.cmake
@@ -36,10 +36,11 @@
 # add_compiler_rt_static_runtime(<name> <arch>
 #                                SOURCES <source files>
 #                                CFLAGS <compile flags>
-#                                DEFS <compile definitions>)
+#                                DEFS <compile definitions>
+#                                SYMS <symbols file>)
 macro(add_compiler_rt_static_runtime name arch)
   if(CAN_TARGET_${arch})
-    parse_arguments(LIB "SOURCES;CFLAGS;DEFS" "" ${ARGN})
+    parse_arguments(LIB "SOURCES;CFLAGS;DEFS;SYMS" "" ${ARGN})
     add_library(${name} STATIC ${LIB_SOURCES})
     # Setup compile flags and definitions.
     set_target_compile_flags(${name}
@@ -52,6 +53,13 @@
     # Add installation command.
     install(TARGETS ${name}
       ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
+    # Generate the .syms file if possible.
+    if(LIB_SYMS)
+      get_target_property(libfile ${name} LOCATION)
+      configure_file(${LIB_SYMS} ${libfile}.syms)
+      install(FILES ${libfile}.syms
+        DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
+    endif(LIB_SYMS)
   else()
     message(FATAL_ERROR "Archtecture ${arch} can't be targeted")
   endif()
@@ -121,3 +129,13 @@
   # Make the test suite depend on the binary.
   add_dependencies(${test_suite} ${test_name})
 endmacro()
+
+macro(add_compiler_rt_resource_file target_name file_name)
+  set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}")
+  set(dst_file "${CLANG_RESOURCE_DIR}/${file_name}")
+  add_custom_target(${target_name}
+    COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src_file} ${dst_file}
+    DEPENDS ${file_name})
+  # Install in Clang resource directory.
+  install(FILES ${file_name} DESTINATION ${LIBCLANG_INSTALL_PATH})
+endmacro()
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
new file mode 100644
index 0000000..3b39dfa
--- /dev/null
+++ b/include/CMakeLists.txt
@@ -0,0 +1,40 @@
+set(SANITIZER_HEADERS
+  sanitizer/asan_interface.h
+  sanitizer/common_interface_defs.h
+  sanitizer/linux_syscall_hooks.h
+  sanitizer/lsan_interface.h
+  sanitizer/msan_interface.h)
+
+set(output_dir ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/include)
+
+if(MSVC_IDE OR XCODE)
+   set(other_output_dir ${LLVM_BINARY_DIR}/bin/lib/clang/${CLANG_VERSION}/include)
+endif()
+
+# Copy compiler-rt headers to the build tree.
+set(out_files)
+foreach( f ${SANITIZER_HEADERS} )
+  set( src ${CMAKE_CURRENT_SOURCE_DIR}/${f} )
+  set( dst ${output_dir}/${f} )
+  add_custom_command(OUTPUT ${dst}
+    DEPENDS ${src}
+    COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
+    COMMENT "Copying compiler-rt's ${f}...")
+  list(APPEND out_files ${dst})
+
+  if(other_output_dir)
+   set(other_dst ${other_output_dir}/${f})
+    add_custom_command(OUTPUT ${other_dst}
+      DEPENDS ${src}
+      COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${other_dst}
+      COMMENT "Copying compiler-rt's ${f}...")    
+    list(APPEND out_files ${other_dst})
+  endif()
+endforeach( f )
+
+add_custom_target(compiler-rt-headers ALL DEPENDS ${out_files})
+
+# Install sanitizer headers.
+install(FILES ${SANITIZER_HEADERS}
+  PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
+  DESTINATION ${LIBCLANG_INSTALL_PATH}/include/sanitizer)
diff --git a/include/sanitizer/common_interface_defs.h b/include/sanitizer/common_interface_defs.h
index 74e3b22..31d0dea 100644
--- a/include/sanitizer/common_interface_defs.h
+++ b/include/sanitizer/common_interface_defs.h
@@ -41,6 +41,16 @@
   // the error message. This function can be overridden by the client.
   void __sanitizer_report_error_summary(const char *error_summary);
 
+  // Some of the sanitizers (e.g. asan/tsan) may miss bugs that happen
+  // in unaligned loads/stores. In order to find such bugs reliably one needs
+  // to replace plain unaligned loads/stores with these calls.
+  uint16_t __sanitizer_unaligned_load16(const void *p);
+  uint32_t __sanitizer_unaligned_load32(const void *p);
+  uint64_t __sanitizer_unaligned_load64(const void *p);
+  void __sanitizer_unaligned_store16(void *p, uint16_t x);
+  void __sanitizer_unaligned_store32(void *p, uint32_t x);
+  void __sanitizer_unaligned_store64(void *p, uint64_t x);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/include/sanitizer/linux_syscall_hooks.h b/include/sanitizer/linux_syscall_hooks.h
new file mode 100644
index 0000000..13bb1a9
--- /dev/null
+++ b/include/sanitizer/linux_syscall_hooks.h
@@ -0,0 +1,803 @@
+//===-- linux_syscall_hooks.h ---------------------------------------------===//
+//
+//                     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 public sanitizer interface.
+//
+// System call handlers.
+//
+// Interface methods declared in this header implement pre- and post- syscall
+// actions for the active sanitizer.
+// Usage:
+//   __sanitizer_syscall_pre_getfoo(...args...);
+//   int res = syscall(__NR_getfoo, ...args...);
+//   __sanitizer_syscall_post_getfoo(res, ...args...);
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LINUX_SYSCALL_HOOKS_H
+#define SANITIZER_LINUX_SYSCALL_HOOKS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void __sanitizer_syscall_pre_rt_sigpending(void *p, size_t s);
+void __sanitizer_syscall_pre_getdents(int fd, void *dirp, int count);
+void __sanitizer_syscall_pre_getdents64(int fd, void *dirp, int count);
+void __sanitizer_syscall_pre_recvmsg(int sockfd, void *msg, int flags);
+void __sanitizer_syscall_pre_wait4(int pid, int *status, int options, void *r);
+void __sanitizer_syscall_pre_waitpid(int pid, int *status, int options);
+void __sanitizer_syscall_pre_clock_gettime(int clk_id, void *tp);
+void __sanitizer_syscall_pre_clock_getres(int clk_id, void *tp);
+void __sanitizer_syscall_pre_read(unsigned int fd, void *buf, size_t count);
+
+void __sanitizer_syscall_post_rt_sigpending(long res, void *p, size_t s);
+void __sanitizer_syscall_post_getdents(long res, int fd, void *dirp, int count);
+void __sanitizer_syscall_post_getdents64(long res, int fd, void *dirp,
+                                         int count);
+void __sanitizer_syscall_post_recvmsg(long res, int sockfd, void *msg,
+                                      int flags);
+void __sanitizer_syscall_post_wait4(long res, int pid, int *status, int options,
+                                    void *r);
+void __sanitizer_syscall_post_waitpid(long res, int pid, int *status,
+                                      int options);
+void __sanitizer_syscall_post_clock_gettime(long res, int clk_id, void *tp);
+void __sanitizer_syscall_post_clock_getres(long res, int clk_id, void *tp);
+void __sanitizer_syscall_post_read(long res, unsigned int fd, void *buf,
+                                   size_t count);
+
+// And now a few syscalls we don't handle yet.
+
+#define __sanitizer_syscall_pre_accept(...)
+#define __sanitizer_syscall_pre_accept4(...)
+#define __sanitizer_syscall_pre_access(...)
+#define __sanitizer_syscall_pre_acct(...)
+#define __sanitizer_syscall_pre_add_key(...)
+#define __sanitizer_syscall_pre_adjtimex(...)
+#define __sanitizer_syscall_pre_afs_syscall(...)
+#define __sanitizer_syscall_pre_alarm(...)
+#define __sanitizer_syscall_pre_arch_prctl(...)
+#define __sanitizer_syscall_pre_bdflush(...)
+#define __sanitizer_syscall_pre_bind(...)
+#define __sanitizer_syscall_pre_break(...)
+#define __sanitizer_syscall_pre_brk(...)
+#define __sanitizer_syscall_pre_capget(...)
+#define __sanitizer_syscall_pre_capset(...)
+#define __sanitizer_syscall_pre_chdir(...)
+#define __sanitizer_syscall_pre_chmod(...)
+#define __sanitizer_syscall_pre_chown(...)
+#define __sanitizer_syscall_pre_chown32(...)
+#define __sanitizer_syscall_pre_chroot(...)
+#define __sanitizer_syscall_pre_clock_adjtime(...)
+#define __sanitizer_syscall_pre_clock_nanosleep(...)
+#define __sanitizer_syscall_pre_clock_settime(...)
+#define __sanitizer_syscall_pre_clone(...)
+#define __sanitizer_syscall_pre_close(...)
+#define __sanitizer_syscall_pre_connect(...)
+#define __sanitizer_syscall_pre_creat(...)
+#define __sanitizer_syscall_pre_create_module(...)
+#define __sanitizer_syscall_pre_delete_module(...)
+#define __sanitizer_syscall_pre_dup(...)
+#define __sanitizer_syscall_pre_dup2(...)
+#define __sanitizer_syscall_pre_dup3(...)
+#define __sanitizer_syscall_pre_epoll_create(...)
+#define __sanitizer_syscall_pre_epoll_create1(...)
+#define __sanitizer_syscall_pre_epoll_ctl(...)
+#define __sanitizer_syscall_pre_epoll_ctl_old(...)
+#define __sanitizer_syscall_pre_epoll_pwait(...)
+#define __sanitizer_syscall_pre_epoll_wait(...)
+#define __sanitizer_syscall_pre_epoll_wait_old(...)
+#define __sanitizer_syscall_pre_eventfd(...)
+#define __sanitizer_syscall_pre_eventfd2(...)
+#define __sanitizer_syscall_pre_execve(...)
+#define __sanitizer_syscall_pre_exit(...)
+#define __sanitizer_syscall_pre_exit_group(...)
+#define __sanitizer_syscall_pre_faccessat(...)
+#define __sanitizer_syscall_pre_fadvise64(...)
+#define __sanitizer_syscall_pre_fadvise64_64(...)
+#define __sanitizer_syscall_pre_fallocate(...)
+#define __sanitizer_syscall_pre_fanotify_init(...)
+#define __sanitizer_syscall_pre_fanotify_mark(...)
+#define __sanitizer_syscall_pre_fchdir(...)
+#define __sanitizer_syscall_pre_fchmod(...)
+#define __sanitizer_syscall_pre_fchmodat(...)
+#define __sanitizer_syscall_pre_fchown(...)
+#define __sanitizer_syscall_pre_fchown32(...)
+#define __sanitizer_syscall_pre_fchownat(...)
+#define __sanitizer_syscall_pre_fcntl(...)
+#define __sanitizer_syscall_pre_fcntl64(...)
+#define __sanitizer_syscall_pre_fdatasync(...)
+#define __sanitizer_syscall_pre_fgetxattr(...)
+#define __sanitizer_syscall_pre_flistxattr(...)
+#define __sanitizer_syscall_pre_flock(...)
+#define __sanitizer_syscall_pre_fork(...)
+#define __sanitizer_syscall_pre_fremovexattr(...)
+#define __sanitizer_syscall_pre_fsetxattr(...)
+#define __sanitizer_syscall_pre_fstat(...)
+#define __sanitizer_syscall_pre_fstat64(...)
+#define __sanitizer_syscall_pre_fstatat64(...)
+#define __sanitizer_syscall_pre_fstatfs(...)
+#define __sanitizer_syscall_pre_fstatfs64(...)
+#define __sanitizer_syscall_pre_fsync(...)
+#define __sanitizer_syscall_pre_ftime(...)
+#define __sanitizer_syscall_pre_ftruncate(...)
+#define __sanitizer_syscall_pre_ftruncate64(...)
+#define __sanitizer_syscall_pre_futex(...)
+#define __sanitizer_syscall_pre_futimesat(...)
+#define __sanitizer_syscall_pre_getcpu(...)
+#define __sanitizer_syscall_pre_getcwd(...)
+#define __sanitizer_syscall_pre_getegid(...)
+#define __sanitizer_syscall_pre_getegid32(...)
+#define __sanitizer_syscall_pre_geteuid(...)
+#define __sanitizer_syscall_pre_geteuid32(...)
+#define __sanitizer_syscall_pre_getgid(...)
+#define __sanitizer_syscall_pre_getgid32(...)
+#define __sanitizer_syscall_pre_getgroups(...)
+#define __sanitizer_syscall_pre_getgroups32(...)
+#define __sanitizer_syscall_pre_getitimer(...)
+#define __sanitizer_syscall_pre_get_kernel_syms(...)
+#define __sanitizer_syscall_pre_get_mempolicy(...)
+#define __sanitizer_syscall_pre_getpeername(...)
+#define __sanitizer_syscall_pre_getpgid(...)
+#define __sanitizer_syscall_pre_getpgrp(...)
+#define __sanitizer_syscall_pre_getpid(...)
+#define __sanitizer_syscall_pre_getpmsg(...)
+#define __sanitizer_syscall_pre_getppid(...)
+#define __sanitizer_syscall_pre_getpriority(...)
+#define __sanitizer_syscall_pre_getresgid(...)
+#define __sanitizer_syscall_pre_getresgid32(...)
+#define __sanitizer_syscall_pre_getresuid(...)
+#define __sanitizer_syscall_pre_getresuid32(...)
+#define __sanitizer_syscall_pre_getrlimit(...)
+#define __sanitizer_syscall_pre_get_robust_list(...)
+#define __sanitizer_syscall_pre_getrusage(...)
+#define __sanitizer_syscall_pre_getsid(...)
+#define __sanitizer_syscall_pre_getsockname(...)
+#define __sanitizer_syscall_pre_getsockopt(...)
+#define __sanitizer_syscall_pre_get_thread_area(...)
+#define __sanitizer_syscall_pre_gettid(...)
+#define __sanitizer_syscall_pre_gettimeofday(...)
+#define __sanitizer_syscall_pre_getuid(...)
+#define __sanitizer_syscall_pre_getuid32(...)
+#define __sanitizer_syscall_pre_getxattr(...)
+#define __sanitizer_syscall_pre_gtty(...)
+#define __sanitizer_syscall_pre_idle(...)
+#define __sanitizer_syscall_pre_init_module(...)
+#define __sanitizer_syscall_pre_inotify_add_watch(...)
+#define __sanitizer_syscall_pre_inotify_init(...)
+#define __sanitizer_syscall_pre_inotify_init1(...)
+#define __sanitizer_syscall_pre_inotify_rm_watch(...)
+#define __sanitizer_syscall_pre_io_cancel(...)
+#define __sanitizer_syscall_pre_ioctl(...)
+#define __sanitizer_syscall_pre_io_destroy(...)
+#define __sanitizer_syscall_pre_io_getevents(...)
+#define __sanitizer_syscall_pre_ioperm(...)
+#define __sanitizer_syscall_pre_iopl(...)
+#define __sanitizer_syscall_pre_ioprio_get(...)
+#define __sanitizer_syscall_pre_ioprio_set(...)
+#define __sanitizer_syscall_pre_io_setup(...)
+#define __sanitizer_syscall_pre_io_submit(...)
+#define __sanitizer_syscall_pre_ipc(...)
+#define __sanitizer_syscall_pre_kexec_load(...)
+#define __sanitizer_syscall_pre_keyctl(...)
+#define __sanitizer_syscall_pre_kill(...)
+#define __sanitizer_syscall_pre_lchown(...)
+#define __sanitizer_syscall_pre_lchown32(...)
+#define __sanitizer_syscall_pre_lgetxattr(...)
+#define __sanitizer_syscall_pre_link(...)
+#define __sanitizer_syscall_pre_linkat(...)
+#define __sanitizer_syscall_pre_listen(...)
+#define __sanitizer_syscall_pre_listxattr(...)
+#define __sanitizer_syscall_pre_llistxattr(...)
+#define __sanitizer_syscall_pre__llseek(...)
+#define __sanitizer_syscall_pre_lock(...)
+#define __sanitizer_syscall_pre_lookup_dcookie(...)
+#define __sanitizer_syscall_pre_lremovexattr(...)
+#define __sanitizer_syscall_pre_lseek(...)
+#define __sanitizer_syscall_pre_lsetxattr(...)
+#define __sanitizer_syscall_pre_lstat(...)
+#define __sanitizer_syscall_pre_lstat64(...)
+#define __sanitizer_syscall_pre_madvise(...)
+#define __sanitizer_syscall_pre_madvise1(...)
+#define __sanitizer_syscall_pre_mbind(...)
+#define __sanitizer_syscall_pre_migrate_pages(...)
+#define __sanitizer_syscall_pre_mincore(...)
+#define __sanitizer_syscall_pre_mkdir(...)
+#define __sanitizer_syscall_pre_mkdirat(...)
+#define __sanitizer_syscall_pre_mknod(...)
+#define __sanitizer_syscall_pre_mknodat(...)
+#define __sanitizer_syscall_pre_mlock(...)
+#define __sanitizer_syscall_pre_mlockall(...)
+#define __sanitizer_syscall_pre_mmap(...)
+#define __sanitizer_syscall_pre_mmap2(...)
+#define __sanitizer_syscall_pre_modify_ldt(...)
+#define __sanitizer_syscall_pre_mount(...)
+#define __sanitizer_syscall_pre_move_pages(...)
+#define __sanitizer_syscall_pre_mprotect(...)
+#define __sanitizer_syscall_pre_mpx(...)
+#define __sanitizer_syscall_pre_mq_getsetattr(...)
+#define __sanitizer_syscall_pre_mq_notify(...)
+#define __sanitizer_syscall_pre_mq_open(...)
+#define __sanitizer_syscall_pre_mq_timedreceive(...)
+#define __sanitizer_syscall_pre_mq_timedsend(...)
+#define __sanitizer_syscall_pre_mq_unlink(...)
+#define __sanitizer_syscall_pre_mremap(...)
+#define __sanitizer_syscall_pre_msgctl(...)
+#define __sanitizer_syscall_pre_msgget(...)
+#define __sanitizer_syscall_pre_msgrcv(...)
+#define __sanitizer_syscall_pre_msgsnd(...)
+#define __sanitizer_syscall_pre_msync(...)
+#define __sanitizer_syscall_pre_munlock(...)
+#define __sanitizer_syscall_pre_munlockall(...)
+#define __sanitizer_syscall_pre_munmap(...)
+#define __sanitizer_syscall_pre_name_to_handle_at(...)
+#define __sanitizer_syscall_pre_nanosleep(...)
+#define __sanitizer_syscall_pre_newfstatat(...)
+#define __sanitizer_syscall_pre__newselect(...)
+#define __sanitizer_syscall_pre_nfsservctl(...)
+#define __sanitizer_syscall_pre_nice(...)
+#define __sanitizer_syscall_pre_oldfstat(...)
+#define __sanitizer_syscall_pre_oldlstat(...)
+#define __sanitizer_syscall_pre_oldolduname(...)
+#define __sanitizer_syscall_pre_oldstat(...)
+#define __sanitizer_syscall_pre_olduname(...)
+#define __sanitizer_syscall_pre_open(...)
+#define __sanitizer_syscall_pre_openat(...)
+#define __sanitizer_syscall_pre_open_by_handle_at(...)
+#define __sanitizer_syscall_pre_pause(...)
+#define __sanitizer_syscall_pre_perf_event_open(...)
+#define __sanitizer_syscall_pre_personality(...)
+#define __sanitizer_syscall_pre_pipe(...)
+#define __sanitizer_syscall_pre_pipe2(...)
+#define __sanitizer_syscall_pre_pivot_root(...)
+#define __sanitizer_syscall_pre_poll(...)
+#define __sanitizer_syscall_pre_ppoll(...)
+#define __sanitizer_syscall_pre_prctl(...)
+#define __sanitizer_syscall_pre_pread64(...)
+#define __sanitizer_syscall_pre_preadv(...)
+#define __sanitizer_syscall_pre_prlimit64(...)
+#define __sanitizer_syscall_pre_process_vm_readv(...)
+#define __sanitizer_syscall_pre_process_vm_writev(...)
+#define __sanitizer_syscall_pre_prof(...)
+#define __sanitizer_syscall_pre_profil(...)
+#define __sanitizer_syscall_pre_pselect6(...)
+#define __sanitizer_syscall_pre_ptrace(...)
+#define __sanitizer_syscall_pre_putpmsg(...)
+#define __sanitizer_syscall_pre_pwrite64(...)
+#define __sanitizer_syscall_pre_pwritev(...)
+#define __sanitizer_syscall_pre_query_module(...)
+#define __sanitizer_syscall_pre_quotactl(...)
+#define __sanitizer_syscall_pre_readahead(...)
+#define __sanitizer_syscall_pre_readdir(...)
+#define __sanitizer_syscall_pre_readlink(...)
+#define __sanitizer_syscall_pre_readlinkat(...)
+#define __sanitizer_syscall_pre_readv(...)
+#define __sanitizer_syscall_pre_reboot(...)
+#define __sanitizer_syscall_pre_recvfrom(...)
+#define __sanitizer_syscall_pre_recvmmsg(...)
+#define __sanitizer_syscall_pre_remap_file_pages(...)
+#define __sanitizer_syscall_pre_removexattr(...)
+#define __sanitizer_syscall_pre_rename(...)
+#define __sanitizer_syscall_pre_renameat(...)
+#define __sanitizer_syscall_pre_request_key(...)
+#define __sanitizer_syscall_pre_restart_syscall(...)
+#define __sanitizer_syscall_pre_rmdir(...)
+#define __sanitizer_syscall_pre_rt_sigaction(...)
+#define __sanitizer_syscall_pre_rt_sigprocmask(...)
+#define __sanitizer_syscall_pre_rt_sigqueueinfo(...)
+#define __sanitizer_syscall_pre_rt_sigreturn(...)
+#define __sanitizer_syscall_pre_rt_sigsuspend(...)
+#define __sanitizer_syscall_pre_rt_sigtimedwait(...)
+#define __sanitizer_syscall_pre_rt_tgsigqueueinfo(...)
+#define __sanitizer_syscall_pre_sched_getaffinity(...)
+#define __sanitizer_syscall_pre_sched_getparam(...)
+#define __sanitizer_syscall_pre_sched_get_priority_max(...)
+#define __sanitizer_syscall_pre_sched_get_priority_min(...)
+#define __sanitizer_syscall_pre_sched_getscheduler(...)
+#define __sanitizer_syscall_pre_sched_rr_get_interval(...)
+#define __sanitizer_syscall_pre_sched_setaffinity(...)
+#define __sanitizer_syscall_pre_sched_setparam(...)
+#define __sanitizer_syscall_pre_sched_setscheduler(...)
+#define __sanitizer_syscall_pre_sched_yield(...)
+#define __sanitizer_syscall_pre_security(...)
+#define __sanitizer_syscall_pre_select(...)
+#define __sanitizer_syscall_pre_semctl(...)
+#define __sanitizer_syscall_pre_semget(...)
+#define __sanitizer_syscall_pre_semop(...)
+#define __sanitizer_syscall_pre_semtimedop(...)
+#define __sanitizer_syscall_pre_sendfile(...)
+#define __sanitizer_syscall_pre_sendfile64(...)
+#define __sanitizer_syscall_pre_sendmmsg(...)
+#define __sanitizer_syscall_pre_sendmsg(...)
+#define __sanitizer_syscall_pre_sendto(...)
+#define __sanitizer_syscall_pre_setdomainname(...)
+#define __sanitizer_syscall_pre_setfsgid(...)
+#define __sanitizer_syscall_pre_setfsgid32(...)
+#define __sanitizer_syscall_pre_setfsuid(...)
+#define __sanitizer_syscall_pre_setfsuid32(...)
+#define __sanitizer_syscall_pre_setgid(...)
+#define __sanitizer_syscall_pre_setgid32(...)
+#define __sanitizer_syscall_pre_setgroups(...)
+#define __sanitizer_syscall_pre_setgroups32(...)
+#define __sanitizer_syscall_pre_sethostname(...)
+#define __sanitizer_syscall_pre_setitimer(...)
+#define __sanitizer_syscall_pre_set_mempolicy(...)
+#define __sanitizer_syscall_pre_setns(...)
+#define __sanitizer_syscall_pre_setpgid(...)
+#define __sanitizer_syscall_pre_setpriority(...)
+#define __sanitizer_syscall_pre_setregid(...)
+#define __sanitizer_syscall_pre_setregid32(...)
+#define __sanitizer_syscall_pre_setresgid(...)
+#define __sanitizer_syscall_pre_setresgid32(...)
+#define __sanitizer_syscall_pre_setresuid(...)
+#define __sanitizer_syscall_pre_setresuid32(...)
+#define __sanitizer_syscall_pre_setreuid(...)
+#define __sanitizer_syscall_pre_setreuid32(...)
+#define __sanitizer_syscall_pre_setrlimit(...)
+#define __sanitizer_syscall_pre_set_robust_list(...)
+#define __sanitizer_syscall_pre_setsid(...)
+#define __sanitizer_syscall_pre_setsockopt(...)
+#define __sanitizer_syscall_pre_set_thread_area(...)
+#define __sanitizer_syscall_pre_set_tid_address(...)
+#define __sanitizer_syscall_pre_settimeofday(...)
+#define __sanitizer_syscall_pre_setuid(...)
+#define __sanitizer_syscall_pre_setuid32(...)
+#define __sanitizer_syscall_pre_setxattr(...)
+#define __sanitizer_syscall_pre_sgetmask(...)
+#define __sanitizer_syscall_pre_shmat(...)
+#define __sanitizer_syscall_pre_shmctl(...)
+#define __sanitizer_syscall_pre_shmdt(...)
+#define __sanitizer_syscall_pre_shmget(...)
+#define __sanitizer_syscall_pre_shutdown(...)
+#define __sanitizer_syscall_pre_sigaction(...)
+#define __sanitizer_syscall_pre_sigaltstack(...)
+#define __sanitizer_syscall_pre_signal(...)
+#define __sanitizer_syscall_pre_signalfd(...)
+#define __sanitizer_syscall_pre_signalfd4(...)
+#define __sanitizer_syscall_pre_sigpending(...)
+#define __sanitizer_syscall_pre_sigprocmask(...)
+#define __sanitizer_syscall_pre_sigreturn(...)
+#define __sanitizer_syscall_pre_sigsuspend(...)
+#define __sanitizer_syscall_pre_socket(...)
+#define __sanitizer_syscall_pre_socketcall(...)
+#define __sanitizer_syscall_pre_socketpair(...)
+#define __sanitizer_syscall_pre_splice(...)
+#define __sanitizer_syscall_pre_ssetmask(...)
+#define __sanitizer_syscall_pre_stat(...)
+#define __sanitizer_syscall_pre_stat64(...)
+#define __sanitizer_syscall_pre_statfs(...)
+#define __sanitizer_syscall_pre_statfs64(...)
+#define __sanitizer_syscall_pre_stime(...)
+#define __sanitizer_syscall_pre_stty(...)
+#define __sanitizer_syscall_pre_swapoff(...)
+#define __sanitizer_syscall_pre_swapon(...)
+#define __sanitizer_syscall_pre_symlink(...)
+#define __sanitizer_syscall_pre_symlinkat(...)
+#define __sanitizer_syscall_pre_sync(...)
+#define __sanitizer_syscall_pre_sync_file_range(...)
+#define __sanitizer_syscall_pre_syncfs(...)
+#define __sanitizer_syscall_pre__sysctl(...)
+#define __sanitizer_syscall_pre_sysfs(...)
+#define __sanitizer_syscall_pre_sysinfo(...)
+#define __sanitizer_syscall_pre_syslog(...)
+#define __sanitizer_syscall_pre_tee(...)
+#define __sanitizer_syscall_pre_tgkill(...)
+#define __sanitizer_syscall_pre_time(...)
+#define __sanitizer_syscall_pre_timer_create(...)
+#define __sanitizer_syscall_pre_timer_delete(...)
+#define __sanitizer_syscall_pre_timerfd_create(...)
+#define __sanitizer_syscall_pre_timerfd_gettime(...)
+#define __sanitizer_syscall_pre_timerfd_settime(...)
+#define __sanitizer_syscall_pre_timer_getoverrun(...)
+#define __sanitizer_syscall_pre_timer_gettime(...)
+#define __sanitizer_syscall_pre_timer_settime(...)
+#define __sanitizer_syscall_pre_times(...)
+#define __sanitizer_syscall_pre_tkill(...)
+#define __sanitizer_syscall_pre_truncate(...)
+#define __sanitizer_syscall_pre_truncate64(...)
+#define __sanitizer_syscall_pre_tuxcall(...)
+#define __sanitizer_syscall_pre_ugetrlimit(...)
+#define __sanitizer_syscall_pre_ulimit(...)
+#define __sanitizer_syscall_pre_umask(...)
+#define __sanitizer_syscall_pre_umount(...)
+#define __sanitizer_syscall_pre_umount2(...)
+#define __sanitizer_syscall_pre_uname(...)
+#define __sanitizer_syscall_pre_unlink(...)
+#define __sanitizer_syscall_pre_unlinkat(...)
+#define __sanitizer_syscall_pre_unshare(...)
+#define __sanitizer_syscall_pre_uselib(...)
+#define __sanitizer_syscall_pre_ustat(...)
+#define __sanitizer_syscall_pre_utime(...)
+#define __sanitizer_syscall_pre_utimensat(...)
+#define __sanitizer_syscall_pre_utimes(...)
+#define __sanitizer_syscall_pre_vfork(...)
+#define __sanitizer_syscall_pre_vhangup(...)
+#define __sanitizer_syscall_pre_vm86(...)
+#define __sanitizer_syscall_pre_vm86old(...)
+#define __sanitizer_syscall_pre_vmsplice(...)
+#define __sanitizer_syscall_pre_vserver(...)
+#define __sanitizer_syscall_pre_waitid(...)
+#define __sanitizer_syscall_pre_write(...)
+#define __sanitizer_syscall_pre_writev(...)
+
+#define __sanitizer_syscall_post_accept4(res, ...)
+#define __sanitizer_syscall_post_accept(res, ...)
+#define __sanitizer_syscall_post_access(res, ...)
+#define __sanitizer_syscall_post_acct(res, ...)
+#define __sanitizer_syscall_post_add_key(res, ...)
+#define __sanitizer_syscall_post_adjtimex(res, ...)
+#define __sanitizer_syscall_post_afs_syscall(res, ...)
+#define __sanitizer_syscall_post_alarm(res, ...)
+#define __sanitizer_syscall_post_arch_prctl(res, ...)
+#define __sanitizer_syscall_post_bdflush(res, ...)
+#define __sanitizer_syscall_post_bind(res, ...)
+#define __sanitizer_syscall_post_break(res, ...)
+#define __sanitizer_syscall_post_brk(res, ...)
+#define __sanitizer_syscall_post_capget(res, ...)
+#define __sanitizer_syscall_post_capset(res, ...)
+#define __sanitizer_syscall_post_chdir(res, ...)
+#define __sanitizer_syscall_post_chmod(res, ...)
+#define __sanitizer_syscall_post_chown32(res, ...)
+#define __sanitizer_syscall_post_chown(res, ...)
+#define __sanitizer_syscall_post_chroot(res, ...)
+#define __sanitizer_syscall_post_clock_adjtime(res, ...)
+#define __sanitizer_syscall_post_clock_nanosleep(res, ...)
+#define __sanitizer_syscall_post_clock_settime(res, ...)
+#define __sanitizer_syscall_post_clone(res, ...)
+#define __sanitizer_syscall_post_close(res, ...)
+#define __sanitizer_syscall_post_connect(res, ...)
+#define __sanitizer_syscall_post_create_module(res, ...)
+#define __sanitizer_syscall_post_creat(res, ...)
+#define __sanitizer_syscall_post_delete_module(res, ...)
+#define __sanitizer_syscall_post_dup2(res, ...)
+#define __sanitizer_syscall_post_dup3(res, ...)
+#define __sanitizer_syscall_post_dup(res, ...)
+#define __sanitizer_syscall_post_epoll_create1(res, ...)
+#define __sanitizer_syscall_post_epoll_create(res, ...)
+#define __sanitizer_syscall_post_epoll_ctl_old(res, ...)
+#define __sanitizer_syscall_post_epoll_ctl(res, ...)
+#define __sanitizer_syscall_post_epoll_pwait(res, ...)
+#define __sanitizer_syscall_post_epoll_wait_old(res, ...)
+#define __sanitizer_syscall_post_epoll_wait(res, ...)
+#define __sanitizer_syscall_post_eventfd2(res, ...)
+#define __sanitizer_syscall_post_eventfd(res, ...)
+#define __sanitizer_syscall_post_execve(res, ...)
+#define __sanitizer_syscall_post_exit_group(res, ...)
+#define __sanitizer_syscall_post_exit(res, ...)
+#define __sanitizer_syscall_post_faccessat(res, ...)
+#define __sanitizer_syscall_post_fadvise64_64(res, ...)
+#define __sanitizer_syscall_post_fadvise64(res, ...)
+#define __sanitizer_syscall_post_fallocate(res, ...)
+#define __sanitizer_syscall_post_fanotify_init(res, ...)
+#define __sanitizer_syscall_post_fanotify_mark(res, ...)
+#define __sanitizer_syscall_post_fchdir(res, ...)
+#define __sanitizer_syscall_post_fchmodat(res, ...)
+#define __sanitizer_syscall_post_fchmod(res, ...)
+#define __sanitizer_syscall_post_fchown32(res, ...)
+#define __sanitizer_syscall_post_fchownat(res, ...)
+#define __sanitizer_syscall_post_fchown(res, ...)
+#define __sanitizer_syscall_post_fcntl64(res, ...)
+#define __sanitizer_syscall_post_fcntl(res, ...)
+#define __sanitizer_syscall_post_fdatasync(res, ...)
+#define __sanitizer_syscall_post_fgetxattr(res, ...)
+#define __sanitizer_syscall_post_flistxattr(res, ...)
+#define __sanitizer_syscall_post_flock(res, ...)
+#define __sanitizer_syscall_post_fork(res, ...)
+#define __sanitizer_syscall_post_fremovexattr(res, ...)
+#define __sanitizer_syscall_post_fsetxattr(res, ...)
+#define __sanitizer_syscall_post_fstat64(res, ...)
+#define __sanitizer_syscall_post_fstatat64(res, ...)
+#define __sanitizer_syscall_post_fstatfs64(res, ...)
+#define __sanitizer_syscall_post_fstatfs(res, ...)
+#define __sanitizer_syscall_post_fstat(res, ...)
+#define __sanitizer_syscall_post_fsync(res, ...)
+#define __sanitizer_syscall_post_ftime(res, ...)
+#define __sanitizer_syscall_post_ftruncate64(res, ...)
+#define __sanitizer_syscall_post_ftruncate(res, ...)
+#define __sanitizer_syscall_post_futex(res, ...)
+#define __sanitizer_syscall_post_futimesat(res, ...)
+#define __sanitizer_syscall_post_getcpu(res, ...)
+#define __sanitizer_syscall_post_getcwd(res, ...)
+#define __sanitizer_syscall_post_getegid32(res, ...)
+#define __sanitizer_syscall_post_getegid(res, ...)
+#define __sanitizer_syscall_post_geteuid32(res, ...)
+#define __sanitizer_syscall_post_geteuid(res, ...)
+#define __sanitizer_syscall_post_getgid32(res, ...)
+#define __sanitizer_syscall_post_getgid(res, ...)
+#define __sanitizer_syscall_post_getgroups32(res, ...)
+#define __sanitizer_syscall_post_getgroups(res, ...)
+#define __sanitizer_syscall_post_getitimer(res, ...)
+#define __sanitizer_syscall_post_get_kernel_syms(res, ...)
+#define __sanitizer_syscall_post_get_mempolicy(res, ...)
+#define __sanitizer_syscall_post_getpeername(res, ...)
+#define __sanitizer_syscall_post_getpgid(res, ...)
+#define __sanitizer_syscall_post_getpgrp(res, ...)
+#define __sanitizer_syscall_post_getpid(res, ...)
+#define __sanitizer_syscall_post_getpmsg(res, ...)
+#define __sanitizer_syscall_post_getppid(res, ...)
+#define __sanitizer_syscall_post_getpriority(res, ...)
+#define __sanitizer_syscall_post_getresgid32(res, ...)
+#define __sanitizer_syscall_post_getresgid(res, ...)
+#define __sanitizer_syscall_post_getresuid32(res, ...)
+#define __sanitizer_syscall_post_getresuid(res, ...)
+#define __sanitizer_syscall_post_getrlimit(res, ...)
+#define __sanitizer_syscall_post_get_robust_list(res, ...)
+#define __sanitizer_syscall_post_getrusage(res, ...)
+#define __sanitizer_syscall_post_getsid(res, ...)
+#define __sanitizer_syscall_post_getsockname(res, ...)
+#define __sanitizer_syscall_post_getsockopt(res, ...)
+#define __sanitizer_syscall_post_get_thread_area(res, ...)
+#define __sanitizer_syscall_post_gettid(res, ...)
+#define __sanitizer_syscall_post_gettimeofday(res, ...)
+#define __sanitizer_syscall_post_getuid32(res, ...)
+#define __sanitizer_syscall_post_getuid(res, ...)
+#define __sanitizer_syscall_post_getxattr(res, ...)
+#define __sanitizer_syscall_post_gtty(res, ...)
+#define __sanitizer_syscall_post_idle(res, ...)
+#define __sanitizer_syscall_post_init_module(res, ...)
+#define __sanitizer_syscall_post_inotify_add_watch(res, ...)
+#define __sanitizer_syscall_post_inotify_init1(res, ...)
+#define __sanitizer_syscall_post_inotify_init(res, ...)
+#define __sanitizer_syscall_post_inotify_rm_watch(res, ...)
+#define __sanitizer_syscall_post_io_cancel(res, ...)
+#define __sanitizer_syscall_post_ioctl(res, ...)
+#define __sanitizer_syscall_post_io_destroy(res, ...)
+#define __sanitizer_syscall_post_io_getevents(res, ...)
+#define __sanitizer_syscall_post_ioperm(res, ...)
+#define __sanitizer_syscall_post_iopl(res, ...)
+#define __sanitizer_syscall_post_ioprio_get(res, ...)
+#define __sanitizer_syscall_post_ioprio_set(res, ...)
+#define __sanitizer_syscall_post_io_setup(res, ...)
+#define __sanitizer_syscall_post_io_submit(res, ...)
+#define __sanitizer_syscall_post_ipc(res, ...)
+#define __sanitizer_syscall_post_kexec_load(res, ...)
+#define __sanitizer_syscall_post_keyctl(res, ...)
+#define __sanitizer_syscall_post_kill(res, ...)
+#define __sanitizer_syscall_post_lchown32(res, ...)
+#define __sanitizer_syscall_post_lchown(res, ...)
+#define __sanitizer_syscall_post_lgetxattr(res, ...)
+#define __sanitizer_syscall_post_linkat(res, ...)
+#define __sanitizer_syscall_post_link(res, ...)
+#define __sanitizer_syscall_post_listen(res, ...)
+#define __sanitizer_syscall_post_listxattr(res, ...)
+#define __sanitizer_syscall_post_llistxattr(res, ...)
+#define __sanitizer_syscall_post__llseek(res, ...)
+#define __sanitizer_syscall_post_lock(res, ...)
+#define __sanitizer_syscall_post_lookup_dcookie(res, ...)
+#define __sanitizer_syscall_post_lremovexattr(res, ...)
+#define __sanitizer_syscall_post_lseek(res, ...)
+#define __sanitizer_syscall_post_lsetxattr(res, ...)
+#define __sanitizer_syscall_post_lstat64(res, ...)
+#define __sanitizer_syscall_post_lstat(res, ...)
+#define __sanitizer_syscall_post_madvise1(res, ...)
+#define __sanitizer_syscall_post_madvise(res, ...)
+#define __sanitizer_syscall_post_mbind(res, ...)
+#define __sanitizer_syscall_post_migrate_pages(res, ...)
+#define __sanitizer_syscall_post_mincore(res, ...)
+#define __sanitizer_syscall_post_mkdirat(res, ...)
+#define __sanitizer_syscall_post_mkdir(res, ...)
+#define __sanitizer_syscall_post_mknodat(res, ...)
+#define __sanitizer_syscall_post_mknod(res, ...)
+#define __sanitizer_syscall_post_mlockall(res, ...)
+#define __sanitizer_syscall_post_mlock(res, ...)
+#define __sanitizer_syscall_post_mmap2(res, ...)
+#define __sanitizer_syscall_post_mmap(res, ...)
+#define __sanitizer_syscall_post_modify_ldt(res, ...)
+#define __sanitizer_syscall_post_mount(res, ...)
+#define __sanitizer_syscall_post_move_pages(res, ...)
+#define __sanitizer_syscall_post_mprotect(res, ...)
+#define __sanitizer_syscall_post_mpx(res, ...)
+#define __sanitizer_syscall_post_mq_getsetattr(res, ...)
+#define __sanitizer_syscall_post_mq_notify(res, ...)
+#define __sanitizer_syscall_post_mq_open(res, ...)
+#define __sanitizer_syscall_post_mq_timedreceive(res, ...)
+#define __sanitizer_syscall_post_mq_timedsend(res, ...)
+#define __sanitizer_syscall_post_mq_unlink(res, ...)
+#define __sanitizer_syscall_post_mremap(res, ...)
+#define __sanitizer_syscall_post_msgctl(res, ...)
+#define __sanitizer_syscall_post_msgget(res, ...)
+#define __sanitizer_syscall_post_msgrcv(res, ...)
+#define __sanitizer_syscall_post_msgsnd(res, ...)
+#define __sanitizer_syscall_post_msync(res, ...)
+#define __sanitizer_syscall_post_munlockall(res, ...)
+#define __sanitizer_syscall_post_munlock(res, ...)
+#define __sanitizer_syscall_post_munmap(res, ...)
+#define __sanitizer_syscall_post_name_to_handle_at(res, ...)
+#define __sanitizer_syscall_post_nanosleep(res, ...)
+#define __sanitizer_syscall_post_newfstatat(res, ...)
+#define __sanitizer_syscall_post__newselect(res, ...)
+#define __sanitizer_syscall_post_nfsservctl(res, ...)
+#define __sanitizer_syscall_post_nice(res, ...)
+#define __sanitizer_syscall_post_oldfstat(res, ...)
+#define __sanitizer_syscall_post_oldlstat(res, ...)
+#define __sanitizer_syscall_post_oldolduname(res, ...)
+#define __sanitizer_syscall_post_oldstat(res, ...)
+#define __sanitizer_syscall_post_olduname(res, ...)
+#define __sanitizer_syscall_post_openat(res, ...)
+#define __sanitizer_syscall_post_open_by_handle_at(res, ...)
+#define __sanitizer_syscall_post_open(res, ...)
+#define __sanitizer_syscall_post_pause(res, ...)
+#define __sanitizer_syscall_post_perf_event_open(res, ...)
+#define __sanitizer_syscall_post_personality(res, ...)
+#define __sanitizer_syscall_post_pipe2(res, ...)
+#define __sanitizer_syscall_post_pipe(res, ...)
+#define __sanitizer_syscall_post_pivot_root(res, ...)
+#define __sanitizer_syscall_post_poll(res, ...)
+#define __sanitizer_syscall_post_ppoll(res, ...)
+#define __sanitizer_syscall_post_prctl(res, ...)
+#define __sanitizer_syscall_post_pread64(res, ...)
+#define __sanitizer_syscall_post_preadv(res, ...)
+#define __sanitizer_syscall_post_prlimit64(res, ...)
+#define __sanitizer_syscall_post_process_vm_readv(res, ...)
+#define __sanitizer_syscall_post_process_vm_writev(res, ...)
+#define __sanitizer_syscall_post_profil(res, ...)
+#define __sanitizer_syscall_post_prof(res, ...)
+#define __sanitizer_syscall_post_pselect6(res, ...)
+#define __sanitizer_syscall_post_ptrace(res, ...)
+#define __sanitizer_syscall_post_putpmsg(res, ...)
+#define __sanitizer_syscall_post_pwrite64(res, ...)
+#define __sanitizer_syscall_post_pwritev(res, ...)
+#define __sanitizer_syscall_post_query_module(res, ...)
+#define __sanitizer_syscall_post_quotactl(res, ...)
+#define __sanitizer_syscall_post_readahead(res, ...)
+#define __sanitizer_syscall_post_readdir(res, ...)
+#define __sanitizer_syscall_post_readlinkat(res, ...)
+#define __sanitizer_syscall_post_readlink(res, ...)
+#define __sanitizer_syscall_post_readv(res, ...)
+#define __sanitizer_syscall_post_reboot(res, ...)
+#define __sanitizer_syscall_post_recvfrom(res, ...)
+#define __sanitizer_syscall_post_recvmmsg(res, ...)
+#define __sanitizer_syscall_post_remap_file_pages(res, ...)
+#define __sanitizer_syscall_post_removexattr(res, ...)
+#define __sanitizer_syscall_post_renameat(res, ...)
+#define __sanitizer_syscall_post_rename(res, ...)
+#define __sanitizer_syscall_post_request_key(res, ...)
+#define __sanitizer_syscall_post_restart_syscall(res, ...)
+#define __sanitizer_syscall_post_rmdir(res, ...)
+#define __sanitizer_syscall_post_rt_sigaction(res, ...)
+#define __sanitizer_syscall_post_rt_sigprocmask(res, ...)
+#define __sanitizer_syscall_post_rt_sigqueueinfo(res, ...)
+#define __sanitizer_syscall_post_rt_sigreturn(res, ...)
+#define __sanitizer_syscall_post_rt_sigsuspend(res, ...)
+#define __sanitizer_syscall_post_rt_sigtimedwait(res, ...)
+#define __sanitizer_syscall_post_rt_tgsigqueueinfo(res, ...)
+#define __sanitizer_syscall_post_sched_getaffinity(res, ...)
+#define __sanitizer_syscall_post_sched_getparam(res, ...)
+#define __sanitizer_syscall_post_sched_get_priority_max(res, ...)
+#define __sanitizer_syscall_post_sched_get_priority_min(res, ...)
+#define __sanitizer_syscall_post_sched_getscheduler(res, ...)
+#define __sanitizer_syscall_post_sched_rr_get_interval(res, ...)
+#define __sanitizer_syscall_post_sched_setaffinity(res, ...)
+#define __sanitizer_syscall_post_sched_setparam(res, ...)
+#define __sanitizer_syscall_post_sched_setscheduler(res, ...)
+#define __sanitizer_syscall_post_sched_yield(res, ...)
+#define __sanitizer_syscall_post_security(res, ...)
+#define __sanitizer_syscall_post_select(res, ...)
+#define __sanitizer_syscall_post_semctl(res, ...)
+#define __sanitizer_syscall_post_semget(res, ...)
+#define __sanitizer_syscall_post_semop(res, ...)
+#define __sanitizer_syscall_post_semtimedop(res, ...)
+#define __sanitizer_syscall_post_sendfile64(res, ...)
+#define __sanitizer_syscall_post_sendfile(res, ...)
+#define __sanitizer_syscall_post_sendmmsg(res, ...)
+#define __sanitizer_syscall_post_sendmsg(res, ...)
+#define __sanitizer_syscall_post_sendto(res, ...)
+#define __sanitizer_syscall_post_setdomainname(res, ...)
+#define __sanitizer_syscall_post_setfsgid32(res, ...)
+#define __sanitizer_syscall_post_setfsgid(res, ...)
+#define __sanitizer_syscall_post_setfsuid32(res, ...)
+#define __sanitizer_syscall_post_setfsuid(res, ...)
+#define __sanitizer_syscall_post_setgid32(res, ...)
+#define __sanitizer_syscall_post_setgid(res, ...)
+#define __sanitizer_syscall_post_setgroups32(res, ...)
+#define __sanitizer_syscall_post_setgroups(res, ...)
+#define __sanitizer_syscall_post_sethostname(res, ...)
+#define __sanitizer_syscall_post_setitimer(res, ...)
+#define __sanitizer_syscall_post_set_mempolicy(res, ...)
+#define __sanitizer_syscall_post_setns(res, ...)
+#define __sanitizer_syscall_post_setpgid(res, ...)
+#define __sanitizer_syscall_post_setpriority(res, ...)
+#define __sanitizer_syscall_post_setregid32(res, ...)
+#define __sanitizer_syscall_post_setregid(res, ...)
+#define __sanitizer_syscall_post_setresgid32(res, ...)
+#define __sanitizer_syscall_post_setresgid(res, ...)
+#define __sanitizer_syscall_post_setresuid32(res, ...)
+#define __sanitizer_syscall_post_setresuid(res, ...)
+#define __sanitizer_syscall_post_setreuid32(res, ...)
+#define __sanitizer_syscall_post_setreuid(res, ...)
+#define __sanitizer_syscall_post_setrlimit(res, ...)
+#define __sanitizer_syscall_post_set_robust_list(res, ...)
+#define __sanitizer_syscall_post_setsid(res, ...)
+#define __sanitizer_syscall_post_setsockopt(res, ...)
+#define __sanitizer_syscall_post_set_thread_area(res, ...)
+#define __sanitizer_syscall_post_set_tid_address(res, ...)
+#define __sanitizer_syscall_post_settimeofday(res, ...)
+#define __sanitizer_syscall_post_setuid32(res, ...)
+#define __sanitizer_syscall_post_setuid(res, ...)
+#define __sanitizer_syscall_post_setxattr(res, ...)
+#define __sanitizer_syscall_post_sgetmask(res, ...)
+#define __sanitizer_syscall_post_shmat(res, ...)
+#define __sanitizer_syscall_post_shmctl(res, ...)
+#define __sanitizer_syscall_post_shmdt(res, ...)
+#define __sanitizer_syscall_post_shmget(res, ...)
+#define __sanitizer_syscall_post_shutdown(res, ...)
+#define __sanitizer_syscall_post_sigaction(res, ...)
+#define __sanitizer_syscall_post_sigaltstack(res, ...)
+#define __sanitizer_syscall_post_signalfd4(res, ...)
+#define __sanitizer_syscall_post_signalfd(res, ...)
+#define __sanitizer_syscall_post_signal(res, ...)
+#define __sanitizer_syscall_post_sigpending(res, ...)
+#define __sanitizer_syscall_post_sigprocmask(res, ...)
+#define __sanitizer_syscall_post_sigreturn(res, ...)
+#define __sanitizer_syscall_post_sigsuspend(res, ...)
+#define __sanitizer_syscall_post_socketcall(res, ...)
+#define __sanitizer_syscall_post_socketpair(res, ...)
+#define __sanitizer_syscall_post_socket(res, ...)
+#define __sanitizer_syscall_post_splice(res, ...)
+#define __sanitizer_syscall_post_ssetmask(res, ...)
+#define __sanitizer_syscall_post_stat64(res, ...)
+#define __sanitizer_syscall_post_statfs64(res, ...)
+#define __sanitizer_syscall_post_statfs(res, ...)
+#define __sanitizer_syscall_post_stat(res, ...)
+#define __sanitizer_syscall_post_stime(res, ...)
+#define __sanitizer_syscall_post_stty(res, ...)
+#define __sanitizer_syscall_post_swapoff(res, ...)
+#define __sanitizer_syscall_post_swapon(res, ...)
+#define __sanitizer_syscall_post_symlinkat(res, ...)
+#define __sanitizer_syscall_post_symlink(res, ...)
+#define __sanitizer_syscall_post_sync_file_range(res, ...)
+#define __sanitizer_syscall_post_syncfs(res, ...)
+#define __sanitizer_syscall_post_sync(res, ...)
+#define __sanitizer_syscall_post__sysctl(res, ...)
+#define __sanitizer_syscall_post_sysfs(res, ...)
+#define __sanitizer_syscall_post_sysinfo(res, ...)
+#define __sanitizer_syscall_post_syslog(res, ...)
+#define __sanitizer_syscall_post_tee(res, ...)
+#define __sanitizer_syscall_post_tgkill(res, ...)
+#define __sanitizer_syscall_post_timer_create(res, ...)
+#define __sanitizer_syscall_post_timer_delete(res, ...)
+#define __sanitizer_syscall_post_time(res, ...)
+#define __sanitizer_syscall_post_timerfd_create(res, ...)
+#define __sanitizer_syscall_post_timerfd_gettime(res, ...)
+#define __sanitizer_syscall_post_timerfd_settime(res, ...)
+#define __sanitizer_syscall_post_timer_getoverrun(res, ...)
+#define __sanitizer_syscall_post_timer_gettime(res, ...)
+#define __sanitizer_syscall_post_timer_settime(res, ...)
+#define __sanitizer_syscall_post_times(res, ...)
+#define __sanitizer_syscall_post_tkill(res, ...)
+#define __sanitizer_syscall_post_truncate64(res, ...)
+#define __sanitizer_syscall_post_truncate(res, ...)
+#define __sanitizer_syscall_post_tuxcall(res, ...)
+#define __sanitizer_syscall_post_ugetrlimit(res, ...)
+#define __sanitizer_syscall_post_ulimit(res, ...)
+#define __sanitizer_syscall_post_umask(res, ...)
+#define __sanitizer_syscall_post_umount2(res, ...)
+#define __sanitizer_syscall_post_umount(res, ...)
+#define __sanitizer_syscall_post_uname(res, ...)
+#define __sanitizer_syscall_post_unlinkat(res, ...)
+#define __sanitizer_syscall_post_unlink(res, ...)
+#define __sanitizer_syscall_post_unshare(res, ...)
+#define __sanitizer_syscall_post_uselib(res, ...)
+#define __sanitizer_syscall_post_ustat(res, ...)
+#define __sanitizer_syscall_post_utimensat(res, ...)
+#define __sanitizer_syscall_post_utime(res, ...)
+#define __sanitizer_syscall_post_utimes(res, ...)
+#define __sanitizer_syscall_post_vfork(res, ...)
+#define __sanitizer_syscall_post_vhangup(res, ...)
+#define __sanitizer_syscall_post_vm86old(res, ...)
+#define __sanitizer_syscall_post_vm86(res, ...)
+#define __sanitizer_syscall_post_vmsplice(res, ...)
+#define __sanitizer_syscall_post_vserver(res, ...)
+#define __sanitizer_syscall_post_waitid(res, ...)
+#define __sanitizer_syscall_post_write(res, ...)
+#define __sanitizer_syscall_post_writev(res, ...)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_LINUX_SYSCALL_HOOKS_H
diff --git a/include/sanitizer/lsan_interface.h b/include/sanitizer/lsan_interface.h
new file mode 100644
index 0000000..df256c0
--- /dev/null
+++ b/include/sanitizer/lsan_interface.h
@@ -0,0 +1,52 @@
+//===-- sanitizer/lsan_interface.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 LeakSanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LSAN_INTERFACE_H
+#define SANITIZER_LSAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  // Allocations made between calls to __lsan_disable() and __lsan_enable() will
+  // be treated as non-leaks. Disable/enable pairs may be nested.
+  void __lsan_disable();
+  void __lsan_enable();
+  // The heap object into which p points will be treated as a non-leak.
+  void __lsan_ignore_object(const void *p);
+  // The user may optionally provide this function to disallow leak checking
+  // for the program it is linked into (if the return value is non-zero). This
+  // function must be defined as returning a constant value; any behavior beyond
+  // that is unsupported.
+  int __lsan_is_turned_off();
+  // Calling this function makes LSan enter the leak checking phase immediately.
+  // Use this if normal end-of-process leak checking happens too late (e.g. if
+  // you have intentional memory leaks in your shutdown code). Calling this
+  // function overrides end-of-process leak checking; it must be called at
+  // most once per process. This function will terminate the process if there
+  // are memory leaks and the exit_code flag is non-zero.
+  void __lsan_do_leak_check();
+#ifdef __cplusplus
+}  // extern "C"
+
+namespace __lsan {
+class ScopedDisabler {
+ public:
+  ScopedDisabler() { __lsan_disable(); }
+  ~ScopedDisabler() { __lsan_enable(); }
+};
+}  // namespace __lsan
+#endif
+
+#endif  // SANITIZER_LSAN_INTERFACE_H
diff --git a/include/sanitizer/msan_interface.h b/include/sanitizer/msan_interface.h
index ceba661..e8427ae 100644
--- a/include/sanitizer/msan_interface.h
+++ b/include/sanitizer/msan_interface.h
@@ -27,10 +27,10 @@
 
 
   /* Set raw origin for the memory range. */
-  void __msan_set_origin(void *a, size_t size, uint32_t origin);
+  void __msan_set_origin(const void *a, size_t size, uint32_t origin);
 
   /* Get raw origin for an address. */
-  uint32_t __msan_get_origin(void *a);
+  uint32_t __msan_get_origin(const void *a);
 
   /* Returns non-zero if tracking origins. */
   int __msan_get_track_origins();
@@ -39,14 +39,14 @@
   uint32_t __msan_get_umr_origin();
 
   /* Make memory region fully initialized (without changing its contents). */
-  void __msan_unpoison(void *a, size_t size);
+  void __msan_unpoison(const void *a, size_t size);
 
   /* Make memory region fully uninitialized (without changing its contents). */
-  void __msan_poison(void *a, size_t size);
+  void __msan_poison(const void *a, size_t size);
 
   /* Make memory region partially uninitialized (without changing its contents).
    */
-  void __msan_partial_poison(void* data, void* shadow, size_t size);
+  void __msan_partial_poison(const void* data, void* shadow, size_t size);
 
   /* Returns the offset of the first (at least partially) poisoned byte in the
      memory range, or -1 if the whole range is good. */
@@ -63,6 +63,11 @@
      The last line will verify that a UMR happened. */
   void __msan_set_expect_umr(int expect_umr);
 
+  /* Change the value of keep_going flag. Non-zero value means don't terminate
+     program execution when an error is detected. This will not affect error in
+     modules that were compiled without the corresponding compiler flag. */
+  void __msan_set_keep_going(int keep_going);
+
   /* Print shadow and origin for the memory range to stdout in a human-readable
      format. */
   void __msan_print_shadow(const void *x, size_t size);
@@ -76,7 +81,58 @@
 
   /* Tell MSan about newly allocated memory (ex.: custom allocator).
      Memory will be marked uninitialized, with origin at the call site. */
-  void __msan_allocated_memory(void* data, size_t size);
+  void __msan_allocated_memory(const void* data, size_t size);
+
+  /* This function may be optionally provided by user and should return
+     a string containing Msan runtime options. See msan_flags.h for details. */
+  const char* __msan_default_options();
+
+
+  /***********************************/
+  /* Allocator statistics interface. */
+
+  /* Returns the estimated number of bytes that will be reserved by allocator
+     for request of "size" bytes. If Msan allocator can't allocate that much
+     memory, returns the maximal possible allocation size, otherwise returns
+     "size". */
+  size_t __msan_get_estimated_allocated_size(size_t size);
+
+  /* Returns true if p was returned by the Msan allocator and
+     is not yet freed. */
+  bool __msan_get_ownership(const void *p);
+
+  /* Returns the number of bytes reserved for the pointer p.
+     Requires (get_ownership(p) == true) or (p == 0). */
+  size_t __msan_get_allocated_size(const void *p);
+
+  /* Number of bytes, allocated and not yet freed by the application. */
+  size_t __msan_get_current_allocated_bytes();
+
+  /* Number of bytes, mmaped by msan allocator to fulfill allocation requests.
+     Generally, for request of X bytes, allocator can reserve and add to free
+     lists a large number of chunks of size X to use them for future requests.
+     All these chunks count toward the heap size. Currently, allocator never
+     releases memory to OS (instead, it just puts freed chunks to free
+     lists). */
+  size_t __msan_get_heap_size();
+
+  /* Number of bytes, mmaped by msan allocator, which can be used to fulfill
+     allocation requests. When a user program frees memory chunk, it can first
+     fall into quarantine and will count toward __msan_get_free_bytes()
+     later. */
+  size_t __msan_get_free_bytes();
+
+  /* Number of bytes in unmapped pages, that are released to OS. Currently,
+     always returns 0. */
+  size_t __msan_get_unmapped_bytes();
+
+  /* Malloc hooks that may be optionally provided by user.
+     __msan_malloc_hook(ptr, size) is called immediately after
+       allocation of "size" bytes, which returned "ptr".
+     __msan_free_hook(ptr) is called immediately before
+       deallocation of "ptr". */
+  void __msan_malloc_hook(void *ptr, size_t size);
+  void __msan_free_hook(void *ptr);
 
 #else  // __has_feature(memory_sanitizer)
 
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 2538a4d..a3bc372 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -7,6 +7,8 @@
   add_subdirectory(interception)
   add_subdirectory(sanitizer_common)
   if(NOT ANDROID)
+    add_subdirectory(lsan)
+    add_subdirectory(profile)
     add_subdirectory(ubsan)
   endif()
 endif()
@@ -17,8 +19,6 @@
   add_subdirectory(msandr)
 endif()
 
-# FIXME: Add support for the profile library.
-
 # The top-level lib directory contains a large amount of C code which provides
 # generic implementations of the core runtime library along with optimized
 # architecture-specific code in various subdirectories.
@@ -37,6 +37,8 @@
   ashlti3.c
   ashrdi3.c
   ashrti3.c
+  # FIXME: atomic.c may only be compiled if host compiler understands _Atomic
+  # atomic.c
   clear_cache.c
   clzdi2.c
   clzsi2.c
@@ -186,3 +188,13 @@
       CFLAGS "-std=c99")
   endif()
 endforeach()
+
+# Generate configs for running lit and unit tests.
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.common.configured.in
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.common.configured)
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.common.unit.configured.in
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.common.unit.configured)
+
diff --git a/lib/Makefile.mk b/lib/Makefile.mk
index 3068485..8054c35 100644
--- a/lib/Makefile.mk
+++ b/lib/Makefile.mk
@@ -21,14 +21,10 @@
 SubDirs += tsan
 SubDirs += msan
 SubDirs += ubsan
-
-# FIXME: We don't currently support building an atomic library, and as it must
-# be a separate library from the runtime library, we need to remove its source
-# code from the source files list.
-ExcludedSources := atomic.c
+SubDirs += lsan
 
 # Define the variables for this specific directory.
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(filter-out $(ExcludedSources),$(notdir $(file))))
+Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
 ObjNames := $(Sources:%.c=%.o)
 Implementation := Generic
 
diff --git a/lib/apple_versioning.c b/lib/apple_versioning.c
index e838d72..09f149f 100644
--- a/lib/apple_versioning.c
+++ b/lib/apple_versioning.c
@@ -13,6 +13,7 @@
 #if __APPLE__
   #if __arm__
     #define NOT_HERE_BEFORE_10_6(sym) 
+    #define NOT_HERE_IN_10_8_AND_EARLIER(sym) 
   #elif __ppc__
     #define NOT_HERE_BEFORE_10_6(sym) \
         extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); \
@@ -27,6 +28,13 @@
             __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
         extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
             __attribute__((visibility("default"))) const char sym##_tmp5 = 0; 
+    #define NOT_HERE_IN_10_8_AND_EARLIER(sym) \
+         extern const char sym##_tmp8 __asm("$ld$hide$os10.8$_" #sym ); \
+            __attribute__((visibility("default"))) const char sym##_tmp8 = 0; \
+        extern const char sym##_tmp7 __asm("$ld$hide$os10.7$_" #sym ); \
+            __attribute__((visibility("default"))) const char sym##_tmp7 = 0; \
+        extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \
+            __attribute__((visibility("default"))) const char sym##_tmp6 = 0; 
   #endif /* __ppc__ */
 
 
@@ -143,6 +151,56 @@
 NOT_HERE_BEFORE_10_6(__trampoline_setup)
 #endif /* __ppc__ */
 
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_8)
+
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_1)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_2)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_4)
+NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_8)
+
+
 #if __arm__ && __DYNAMIC__
    #define NOT_HERE_UNTIL_AFTER_4_3(sym) \
         extern const char sym##_tmp1 __asm("$ld$hide$os3.0$_" #sym ); \
diff --git a/lib/arm/divmodsi4.S b/lib/arm/divmodsi4.S
index cec39a7..d31e510 100644
--- a/lib/arm/divmodsi4.S
+++ b/lib/arm/divmodsi4.S
@@ -24,6 +24,18 @@
 .syntax unified
 .align 3
 DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
+#if __ARM_ARCH_7S__
+	tst     r1, r1
+	beq     LOCAL_LABEL(divzero)
+	mov 	r3, r0
+	sdiv	r0, r3, r1
+	mls 	r1, r0, r1, r3
+	str 	r1, [r2]
+	bx  	lr
+LOCAL_LABEL(divzero):
+	mov     r0, #0
+	bx      lr
+#else
     ESTABLISH_FRAME
 //  Set aside the sign of the quotient and modulus, and the address for the
 //  modulus.
@@ -45,3 +57,4 @@
     sub     r1,     r1, r5, asr #31
     str     r1,    [r6]
     CLEAR_FRAME_AND_RETURN
+#endif
diff --git a/lib/arm/modsi3.S b/lib/arm/modsi3.S
index a4cd2ee..0459501 100644
--- a/lib/arm/modsi3.S
+++ b/lib/arm/modsi3.S
@@ -23,6 +23,16 @@
 .syntax unified
 .align 3
 DEFINE_COMPILERRT_FUNCTION(__modsi3)
+#if __ARM_ARCH_7S__
+	tst     r1, r1
+	beq     LOCAL_LABEL(divzero)
+	sdiv	r2, r0, r1
+	mls 	r0, r2, r1, r0
+	bx      lr
+LOCAL_LABEL(divzero):
+	mov     r0, #0
+	bx      lr
+#else
     ESTABLISH_FRAME
     //  Set aside the sign of the dividend.
     mov     r4,     r0
@@ -37,3 +47,4 @@
     eor     r0,     r0, r4, asr #31
     sub     r0,     r0, r4, asr #31
     CLEAR_FRAME_AND_RETURN
+#endif
diff --git a/lib/arm/udivmodsi4.S b/lib/arm/udivmodsi4.S
index d164a75..9956cd4 100644
--- a/lib/arm/udivmodsi4.S
+++ b/lib/arm/udivmodsi4.S
@@ -31,6 +31,18 @@
 .syntax unified
 .align 3
 DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
+#if __ARM_ARCH_7S__
+	tst     r1, r1
+	beq     LOCAL_LABEL(divzero)
+	mov 	r3, r0
+	udiv	r0, r3, r1
+	mls 	r1, r0, r1, r3
+	str 	r1, [r2]
+	bx  	lr
+LOCAL_LABEL(divzero):
+	mov     r0, #0
+	bx      lr
+#else
 //  We use a simple digit by digit algorithm; before we get into the actual 
 //  divide loop, we must calculate the left-shift amount necessary to align
 //  the MSB of the divisor with that of the dividend (If this shift is
@@ -78,3 +90,4 @@
     str     a,     [r2]
     mov     r0,     q
     CLEAR_FRAME_AND_RETURN
+#endif
diff --git a/lib/arm/umodsi3.S b/lib/arm/umodsi3.S
index 3a2ab2b..328e705 100644
--- a/lib/arm/umodsi3.S
+++ b/lib/arm/umodsi3.S
@@ -23,6 +23,16 @@
 .syntax unified
 .align 3
 DEFINE_COMPILERRT_FUNCTION(__umodsi3)
+#if __ARM_ARCH_7S__
+	tst     r1, r1
+	beq     LOCAL_LABEL(divzero)
+	udiv	r2, r0, r1
+	mls     r0, r2, r1, r0
+	bx      lr
+LOCAL_LABEL(divzero):
+	mov     r0, #0
+	bx      lr
+#else
 //  We use a simple digit by digit algorithm; before we get into the actual 
 //  divide loop, we must calculate the left-shift amount necessary to align
 //  the MSB of the divisor with that of the dividend.
@@ -56,3 +66,4 @@
     subs    r,      a,  b
     movhs   a,      r
     bx      lr
+#endif
diff --git a/lib/asan/Android.mk b/lib/asan/Android.mk
index c743a2c..62fdd17 100644
--- a/lib/asan/Android.mk
+++ b/lib/asan/Android.mk
@@ -24,7 +24,6 @@
 ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
 
 asan_rtl_files := \
-	asan_allocator.cc	\
 	asan_allocator2.cc	\
 	asan_fake_stack.cc \
 	asan_globals.cc	\
@@ -42,25 +41,30 @@
 	asan_stack.cc	\
 	asan_stats.cc	\
 	asan_thread.cc	\
-	asan_thread_registry.cc \
 	asan_win.cc \
 	../interception/interception_linux.cc \
 	../sanitizer_common/sanitizer_allocator.cc \
 	../sanitizer_common/sanitizer_common.cc \
+	../sanitizer_common/sanitizer_common_libcdep.cc \
 	../sanitizer_common/sanitizer_flags.cc \
 	../sanitizer_common/sanitizer_libc.cc \
 	../sanitizer_common/sanitizer_linux.cc \
+	../sanitizer_common/sanitizer_linux_libcdep.cc \
 	../sanitizer_common/sanitizer_mac.cc \
 	../sanitizer_common/sanitizer_posix.cc \
+	../sanitizer_common/sanitizer_posix_libcdep.cc \
 	../sanitizer_common/sanitizer_platform_limits_posix.cc \
 	../sanitizer_common/sanitizer_printf.cc \
 	../sanitizer_common/sanitizer_stackdepot.cc \
 	../sanitizer_common/sanitizer_stacktrace.cc \
-	../sanitizer_common/sanitizer_symbolizer.cc \
 	../sanitizer_common/sanitizer_symbolizer_itanium.cc \
+	../sanitizer_common/sanitizer_symbolizer_libcdep.cc \
 	../sanitizer_common/sanitizer_symbolizer_linux.cc \
+	../sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc \
 	../sanitizer_common/sanitizer_symbolizer_mac.cc \
+	../sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc \
 	../sanitizer_common/sanitizer_symbolizer_win.cc \
+	../sanitizer_common/sanitizer_thread_registry.cc \
 	../sanitizer_common/sanitizer_win.cc \
 
 asan_rtl_cflags := \
@@ -71,6 +75,7 @@
 	-DASAN_HAS_EXCEPTIONS=$(ASAN_HAS_EXCEPTIONS) \
 	-DASAN_FLEXIBLE_MAPPING_AND_OFFSET=$(ASAN_FLEXIBLE_MAPPING_AND_OFFSET) \
 	-Wno-covered-switch-default \
+	-Wno-non-virtual-dtor \
 	-Wno-sign-compare \
 	-Wno-unused-parameter \
 	-D__WORDSIZE=32
@@ -90,6 +95,7 @@
 	-DASAN_HAS_EXCEPTIONS=$(ASAN_HAS_EXCEPTIONS) \
 	-DASAN_HAS_BLACKLIST=1 \
 	-Wno-covered-switch-default \
+	-Wno-non-virtual-dtor \
 	-Wno-sign-compare \
 	-Wno-unused-parameter \
 	-D__WORDSIZE=32
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index 3e3505e..064ba1f 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -1,7 +1,6 @@
 # Build for the AddressSanitizer runtime support library.
 
 set(ASAN_SOURCES
-  asan_allocator.cc
   asan_allocator2.cc
   asan_fake_stack.cc
   asan_globals.cc
@@ -20,13 +19,10 @@
   asan_stack.cc
   asan_stats.cc
   asan_thread.cc
-  asan_thread_registry.cc
-  asan_win.cc
-  )
+  asan_win.cc)
 
 set(ASAN_DYLIB_SOURCES
-  ${ASAN_SOURCES}
-  )
+  ${ASAN_SOURCES})
 
 include_directories(..)
 
@@ -50,7 +46,7 @@
 
 # Architectures supported by ASan.
 filter_available_targets(ASAN_SUPPORTED_ARCH
-  x86_64 i386 powerpc64 powerpc)
+  x86_64 i386 powerpc64)
 
 set(ASAN_RUNTIME_LIBRARIES)
 if(APPLE)
@@ -60,6 +56,7 @@
     SOURCES ${ASAN_DYLIB_SOURCES}
             $<TARGET_OBJECTS:RTInterception.osx>
             $<TARGET_OBJECTS:RTSanitizerCommon.osx>
+            $<TARGET_OBJECTS:RTLSanCommon.osx>
     CFLAGS ${ASAN_CFLAGS}
     DEFS ${ASAN_COMMON_DEFINITIONS}
     # Dynamic lookup is needed because shadow scale and offset are
@@ -86,12 +83,17 @@
       SOURCES ${ASAN_SOURCES}
               $<TARGET_OBJECTS:RTInterception.${arch}>
               $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+              $<TARGET_OBJECTS:RTLSanCommon.${arch}>
       CFLAGS ${ASAN_CFLAGS}
-      DEFS ${ASAN_COMMON_DEFINITIONS})
+      DEFS ${ASAN_COMMON_DEFINITIONS}
+      SYMS asan.syms)
     list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch})
   endforeach()
 endif()
 
+add_compiler_rt_resource_file(asan_blacklist asan_blacklist.txt)
+
 if(LLVM_INCLUDE_TESTS)
   add_subdirectory(tests)
 endif()
diff --git a/lib/asan/asan.syms b/lib/asan/asan.syms
new file mode 100644
index 0000000..fce3673
--- /dev/null
+++ b/lib/asan/asan.syms
@@ -0,0 +1,5 @@
+{
+  __asan_*;
+  __sanitizer_syscall_pre_*;
+  __sanitizer_syscall_post_*;
+};
diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc
deleted file mode 100644
index 47b00bb..0000000
--- a/lib/asan/asan_allocator.cc
+++ /dev/null
@@ -1,813 +0,0 @@
-//===-- asan_allocator.cc -------------------------------------------------===//
-//
-//                     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.
-//
-// Implementation of ASan's memory allocator.
-// Evey piece of memory (AsanChunk) allocated by the allocator
-// has a left redzone of REDZONE bytes and
-// a right redzone such that the end of the chunk is aligned by REDZONE
-// (i.e. the right redzone is between 0 and REDZONE-1).
-// The left redzone is always poisoned.
-// The right redzone is poisoned on malloc, the body is poisoned on free.
-// Once freed, a chunk is moved to a quarantine (fifo list).
-// After quarantine, a chunk is returned to freelists.
-//
-// The left redzone contains ASan's internal data and the stack trace of
-// the malloc call.
-// Once freed, the body of the chunk contains the stack trace of the free call.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_allocator.h"
-
-#if ASAN_ALLOCATOR_VERSION == 1
-#include "asan_interceptors.h"
-#include "asan_internal.h"
-#include "asan_mapping.h"
-#include "asan_stats.h"
-#include "asan_report.h"
-#include "asan_thread.h"
-#include "asan_thread_registry.h"
-#include "sanitizer_common/sanitizer_allocator.h"
-#include "sanitizer_common/sanitizer_atomic.h"
-#include "sanitizer_common/sanitizer_mutex.h"
-
-namespace __asan {
-
-#define REDZONE ((uptr)(flags()->redzone))
-static const uptr kMinAllocSize = REDZONE * 2;
-static const u64 kMaxAvailableRam = 128ULL << 30;  // 128G
-static const uptr kMaxThreadLocalQuarantine = 1 << 20;  // 1M
-
-static const uptr kMinMmapSize = (ASAN_LOW_MEMORY) ? 4UL << 17 : 4UL << 20;
-static const uptr kMaxSizeForThreadLocalFreeList =
-    (ASAN_LOW_MEMORY) ? 1 << 15 : 1 << 17;
-
-// Size classes less than kMallocSizeClassStep are powers of two.
-// All other size classes are multiples of kMallocSizeClassStep.
-static const uptr kMallocSizeClassStepLog = 26;
-static const uptr kMallocSizeClassStep = 1UL << kMallocSizeClassStepLog;
-
-static const uptr kMaxAllowedMallocSize =
-    (SANITIZER_WORDSIZE == 32) ? 3UL << 30 : 8UL << 30;
-
-static inline uptr SizeClassToSize(u8 size_class) {
-  CHECK(size_class < kNumberOfSizeClasses);
-  if (size_class <= kMallocSizeClassStepLog) {
-    return 1UL << size_class;
-  } else {
-    return (size_class - kMallocSizeClassStepLog) * kMallocSizeClassStep;
-  }
-}
-
-static inline u8 SizeToSizeClass(uptr size) {
-  u8 res = 0;
-  if (size <= kMallocSizeClassStep) {
-    uptr rounded = RoundUpToPowerOfTwo(size);
-    res = Log2(rounded);
-  } else {
-    res = ((size + kMallocSizeClassStep - 1) / kMallocSizeClassStep)
-        + kMallocSizeClassStepLog;
-  }
-  CHECK(res < kNumberOfSizeClasses);
-  CHECK(size <= SizeClassToSize(res));
-  return res;
-}
-
-// Given REDZONE bytes, we need to mark first size bytes
-// as addressable and the rest REDZONE-size bytes as unaddressable.
-static void PoisonHeapPartialRightRedzone(uptr mem, uptr size) {
-  CHECK(size <= REDZONE);
-  CHECK(IsAligned(mem, REDZONE));
-  CHECK(IsPowerOfTwo(SHADOW_GRANULARITY));
-  CHECK(IsPowerOfTwo(REDZONE));
-  CHECK(REDZONE >= SHADOW_GRANULARITY);
-  PoisonShadowPartialRightRedzone(mem, size, REDZONE,
-                                  kAsanHeapRightRedzoneMagic);
-}
-
-static u8 *MmapNewPagesAndPoisonShadow(uptr size) {
-  CHECK(IsAligned(size, GetPageSizeCached()));
-  u8 *res = (u8*)MmapOrDie(size, __FUNCTION__);
-  PoisonShadow((uptr)res, size, kAsanHeapLeftRedzoneMagic);
-  if (flags()->debug) {
-    Printf("ASAN_MMAP: [%p, %p)\n", res, res + size);
-  }
-  return res;
-}
-
-// Every chunk of memory allocated by this allocator can be in one of 3 states:
-// CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated.
-// CHUNK_ALLOCATED: the chunk is allocated and not yet freed.
-// CHUNK_QUARANTINE: the chunk was freed and put into quarantine zone.
-//
-// The pseudo state CHUNK_MEMALIGN is used to mark that the address is not
-// the beginning of a AsanChunk (in which the actual chunk resides at
-// this - this->used_size).
-//
-// The magic numbers for the enum values are taken randomly.
-enum {
-  CHUNK_AVAILABLE  = 0x57,
-  CHUNK_ALLOCATED  = 0x32,
-  CHUNK_QUARANTINE = 0x19,
-  CHUNK_MEMALIGN   = 0xDC
-};
-
-struct ChunkBase {
-  // First 8 bytes.
-  uptr  chunk_state : 8;
-  uptr  alloc_tid   : 24;
-  uptr  size_class  : 8;
-  uptr  free_tid    : 24;
-
-  // Second 8 bytes.
-  uptr alignment_log : 8;
-  uptr alloc_type    : 2;
-  uptr used_size : FIRST_32_SECOND_64(32, 54);  // Size requested by the user.
-
-  // This field may overlap with the user area and thus should not
-  // be used while the chunk is in CHUNK_ALLOCATED state.
-  AsanChunk *next;
-
-  // Typically the beginning of the user-accessible memory is 'this'+REDZONE
-  // and is also aligned by REDZONE. However, if the memory is allocated
-  // by memalign, the alignment might be higher and the user-accessible memory
-  // starts at the first properly aligned address after 'this'.
-  uptr Beg() { return RoundUpTo((uptr)this + 1, 1 << alignment_log); }
-  uptr Size() { return SizeClassToSize(size_class); }
-  u8 SizeClass() { return size_class; }
-};
-
-struct AsanChunk: public ChunkBase {
-  u32 *compressed_alloc_stack() {
-    return (u32*)((uptr)this + sizeof(ChunkBase));
-  }
-  u32 *compressed_free_stack() {
-    return (u32*)((uptr)this + Max((uptr)REDZONE, (uptr)sizeof(ChunkBase)));
-  }
-
-  // The left redzone after the ChunkBase is given to the alloc stack trace.
-  uptr compressed_alloc_stack_size() {
-    if (REDZONE < sizeof(ChunkBase)) return 0;
-    return (REDZONE - sizeof(ChunkBase)) / sizeof(u32);
-  }
-  uptr compressed_free_stack_size() {
-    if (REDZONE < sizeof(ChunkBase)) return 0;
-    return (REDZONE) / sizeof(u32);
-  }
-};
-
-uptr AsanChunkView::Beg() { return chunk_->Beg(); }
-uptr AsanChunkView::End() { return Beg() + UsedSize(); }
-uptr AsanChunkView::UsedSize() { return chunk_->used_size; }
-uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
-uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
-
-void AsanChunkView::GetAllocStack(StackTrace *stack) {
-  StackTrace::UncompressStack(stack, chunk_->compressed_alloc_stack(),
-                              chunk_->compressed_alloc_stack_size());
-}
-
-void AsanChunkView::GetFreeStack(StackTrace *stack) {
-  StackTrace::UncompressStack(stack, chunk_->compressed_free_stack(),
-                              chunk_->compressed_free_stack_size());
-}
-
-static AsanChunk *PtrToChunk(uptr ptr) {
-  AsanChunk *m = (AsanChunk*)(ptr - REDZONE);
-  if (m->chunk_state == CHUNK_MEMALIGN) {
-    m = (AsanChunk*)((uptr)m - m->used_size);
-  }
-  return m;
-}
-
-void AsanChunkFifoList::PushList(AsanChunkFifoList *q) {
-  CHECK(q->size() > 0);
-  size_ += q->size();
-  append_back(q);
-  q->clear();
-}
-
-void AsanChunkFifoList::Push(AsanChunk *n) {
-  push_back(n);
-  size_ += n->Size();
-}
-
-// Interesting performance observation: this function takes up to 15% of overal
-// allocator time. That's because *first_ has been evicted from cache long time
-// ago. Not sure if we can or want to do anything with this.
-AsanChunk *AsanChunkFifoList::Pop() {
-  CHECK(first_);
-  AsanChunk *res = front();
-  size_ -= res->Size();
-  pop_front();
-  return res;
-}
-
-// All pages we ever allocated.
-struct PageGroup {
-  uptr beg;
-  uptr end;
-  uptr size_of_chunk;
-  uptr last_chunk;
-  bool InRange(uptr addr) {
-    return addr >= beg && addr < end;
-  }
-};
-
-class MallocInfo {
- public:
-  explicit MallocInfo(LinkerInitialized x) : mu_(x) { }
-
-  AsanChunk *AllocateChunks(u8 size_class, uptr n_chunks) {
-    AsanChunk *m = 0;
-    AsanChunk **fl = &free_lists_[size_class];
-    {
-      BlockingMutexLock lock(&mu_);
-      for (uptr i = 0; i < n_chunks; i++) {
-        if (!(*fl)) {
-          *fl = GetNewChunks(size_class);
-        }
-        AsanChunk *t = *fl;
-        *fl = t->next;
-        t->next = m;
-        CHECK(t->chunk_state == CHUNK_AVAILABLE);
-        m = t;
-      }
-    }
-    return m;
-  }
-
-  void SwallowThreadLocalMallocStorage(AsanThreadLocalMallocStorage *x,
-                                       bool eat_free_lists) {
-    CHECK(flags()->quarantine_size > 0);
-    BlockingMutexLock lock(&mu_);
-    AsanChunkFifoList *q = &x->quarantine_;
-    if (q->size() > 0) {
-      quarantine_.PushList(q);
-      while (quarantine_.size() > (uptr)flags()->quarantine_size) {
-        QuarantinePop();
-      }
-    }
-    if (eat_free_lists) {
-      for (uptr size_class = 0; size_class < kNumberOfSizeClasses;
-           size_class++) {
-        AsanChunk *m = x->free_lists_[size_class];
-        while (m) {
-          AsanChunk *t = m->next;
-          m->next = free_lists_[size_class];
-          free_lists_[size_class] = m;
-          m = t;
-        }
-        x->free_lists_[size_class] = 0;
-      }
-    }
-  }
-
-  void BypassThreadLocalQuarantine(AsanChunk *chunk) {
-    BlockingMutexLock lock(&mu_);
-    quarantine_.Push(chunk);
-  }
-
-  AsanChunk *FindChunkByAddr(uptr addr) {
-    BlockingMutexLock lock(&mu_);
-    return FindChunkByAddrUnlocked(addr);
-  }
-
-  uptr AllocationSize(uptr ptr) {
-    if (!ptr) return 0;
-    BlockingMutexLock lock(&mu_);
-
-    // Make sure this is our chunk and |ptr| actually points to the beginning
-    // of the allocated memory.
-    AsanChunk *m = FindChunkByAddrUnlocked(ptr);
-    if (!m || m->Beg() != ptr) return 0;
-
-    if (m->chunk_state == CHUNK_ALLOCATED) {
-      return m->used_size;
-    } else {
-      return 0;
-    }
-  }
-
-  void ForceLock() {
-    mu_.Lock();
-  }
-
-  void ForceUnlock() {
-    mu_.Unlock();
-  }
-
-  void PrintStatus() {
-    BlockingMutexLock lock(&mu_);
-    uptr malloced = 0;
-
-    Printf(" MallocInfo: in quarantine: %zu malloced: %zu; ",
-           quarantine_.size() >> 20, malloced >> 20);
-    for (uptr j = 1; j < kNumberOfSizeClasses; j++) {
-      AsanChunk *i = free_lists_[j];
-      if (!i) continue;
-      uptr t = 0;
-      for (; i; i = i->next) {
-        t += i->Size();
-      }
-      Printf("%zu:%zu ", j, t >> 20);
-    }
-    Printf("\n");
-  }
-
-  PageGroup *FindPageGroup(uptr addr) {
-    BlockingMutexLock lock(&mu_);
-    return FindPageGroupUnlocked(addr);
-  }
-
- private:
-  PageGroup *FindPageGroupUnlocked(uptr addr) {
-    int n = atomic_load(&n_page_groups_, memory_order_relaxed);
-    // If the page groups are not sorted yet, sort them.
-    if (n_sorted_page_groups_ < n) {
-      SortArray((uptr*)page_groups_, n);
-      n_sorted_page_groups_ = n;
-    }
-    // Binary search over the page groups.
-    int beg = 0, end = n;
-    while (beg < end) {
-      int med = (beg + end) / 2;
-      uptr g = (uptr)page_groups_[med];
-      if (addr > g) {
-        // 'g' points to the end of the group, so 'addr'
-        // may not belong to page_groups_[med] or any previous group.
-        beg = med + 1;
-      } else {
-        // 'addr' may belong to page_groups_[med] or a previous group.
-        end = med;
-      }
-    }
-    if (beg >= n)
-      return 0;
-    PageGroup *g = page_groups_[beg];
-    CHECK(g);
-    if (g->InRange(addr))
-      return g;
-    return 0;
-  }
-
-  // We have an address between two chunks, and we want to report just one.
-  AsanChunk *ChooseChunk(uptr addr,
-                         AsanChunk *left_chunk, AsanChunk *right_chunk) {
-    // Prefer an allocated chunk or a chunk from quarantine.
-    if (left_chunk->chunk_state == CHUNK_AVAILABLE &&
-        right_chunk->chunk_state != CHUNK_AVAILABLE)
-      return right_chunk;
-    if (right_chunk->chunk_state == CHUNK_AVAILABLE &&
-        left_chunk->chunk_state != CHUNK_AVAILABLE)
-      return left_chunk;
-    // Choose based on offset.
-    sptr l_offset = 0, r_offset = 0;
-    CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
-    CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
-    if (l_offset < r_offset)
-      return left_chunk;
-    return right_chunk;
-  }
-
-  AsanChunk *FindChunkByAddrUnlocked(uptr addr) {
-    PageGroup *g = FindPageGroupUnlocked(addr);
-    if (!g) return 0;
-    CHECK(g->size_of_chunk);
-    uptr offset_from_beg = addr - g->beg;
-    uptr this_chunk_addr = g->beg +
-        (offset_from_beg / g->size_of_chunk) * g->size_of_chunk;
-    CHECK(g->InRange(this_chunk_addr));
-    AsanChunk *m = (AsanChunk*)this_chunk_addr;
-    CHECK(m->chunk_state == CHUNK_ALLOCATED ||
-          m->chunk_state == CHUNK_AVAILABLE ||
-          m->chunk_state == CHUNK_QUARANTINE);
-    sptr offset = 0;
-    AsanChunkView m_view(m);
-    if (m_view.AddrIsInside(addr, 1, &offset))
-      return m;
-
-    if (m_view.AddrIsAtRight(addr, 1, &offset)) {
-      if (this_chunk_addr == g->last_chunk)  // rightmost chunk
-        return m;
-      uptr right_chunk_addr = this_chunk_addr + g->size_of_chunk;
-      CHECK(g->InRange(right_chunk_addr));
-      return ChooseChunk(addr, m, (AsanChunk*)right_chunk_addr);
-    } else {
-      CHECK(m_view.AddrIsAtLeft(addr, 1, &offset));
-      if (this_chunk_addr == g->beg)  // leftmost chunk
-        return m;
-      uptr left_chunk_addr = this_chunk_addr - g->size_of_chunk;
-      CHECK(g->InRange(left_chunk_addr));
-      return ChooseChunk(addr, (AsanChunk*)left_chunk_addr, m);
-    }
-  }
-
-  void QuarantinePop() {
-    CHECK(quarantine_.size() > 0);
-    AsanChunk *m = quarantine_.Pop();
-    CHECK(m);
-    // if (F_v >= 2) Printf("MallocInfo::pop %p\n", m);
-
-    CHECK(m->chunk_state == CHUNK_QUARANTINE);
-    m->chunk_state = CHUNK_AVAILABLE;
-    PoisonShadow((uptr)m, m->Size(), kAsanHeapLeftRedzoneMagic);
-    CHECK(m->alloc_tid >= 0);
-    CHECK(m->free_tid >= 0);
-
-    uptr size_class = m->SizeClass();
-    m->next = free_lists_[size_class];
-    free_lists_[size_class] = m;
-
-    // Statistics.
-    AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
-    thread_stats.real_frees++;
-    thread_stats.really_freed += m->used_size;
-    thread_stats.really_freed_redzones += m->Size() - m->used_size;
-    thread_stats.really_freed_by_size[m->SizeClass()]++;
-  }
-
-  // Get a list of newly allocated chunks.
-  AsanChunk *GetNewChunks(u8 size_class) {
-    uptr size = SizeClassToSize(size_class);
-    CHECK(IsPowerOfTwo(kMinMmapSize));
-    CHECK(size < kMinMmapSize || (size % kMinMmapSize) == 0);
-    uptr mmap_size = Max(size, kMinMmapSize);
-    uptr n_chunks = mmap_size / size;
-    CHECK(n_chunks * size == mmap_size);
-    uptr PageSize = GetPageSizeCached();
-    if (size < PageSize) {
-      // Size is small, just poison the last chunk.
-      n_chunks--;
-    } else {
-      // Size is large, allocate an extra page at right and poison it.
-      mmap_size += PageSize;
-    }
-    CHECK(n_chunks > 0);
-    u8 *mem = MmapNewPagesAndPoisonShadow(mmap_size);
-
-    // Statistics.
-    AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
-    thread_stats.mmaps++;
-    thread_stats.mmaped += mmap_size;
-    thread_stats.mmaped_by_size[size_class] += n_chunks;
-
-    AsanChunk *res = 0;
-    for (uptr i = 0; i < n_chunks; i++) {
-      AsanChunk *m = (AsanChunk*)(mem + i * size);
-      m->chunk_state = CHUNK_AVAILABLE;
-      m->size_class = size_class;
-      m->next = res;
-      res = m;
-    }
-    PageGroup *pg = (PageGroup*)(mem + n_chunks * size);
-    // This memory is already poisoned, no need to poison it again.
-    pg->beg = (uptr)mem;
-    pg->end = pg->beg + mmap_size;
-    pg->size_of_chunk = size;
-    pg->last_chunk = (uptr)(mem + size * (n_chunks - 1));
-    int idx = atomic_fetch_add(&n_page_groups_, 1, memory_order_relaxed);
-    CHECK(idx < (int)ARRAY_SIZE(page_groups_));
-    page_groups_[idx] = pg;
-    return res;
-  }
-
-  AsanChunk *free_lists_[kNumberOfSizeClasses];
-  AsanChunkFifoList quarantine_;
-  BlockingMutex mu_;
-
-  PageGroup *page_groups_[kMaxAvailableRam / kMinMmapSize];
-  atomic_uint32_t n_page_groups_;
-  int n_sorted_page_groups_;
-};
-
-static MallocInfo malloc_info(LINKER_INITIALIZED);
-
-void AsanThreadLocalMallocStorage::CommitBack() {
-  malloc_info.SwallowThreadLocalMallocStorage(this, true);
-}
-
-AsanChunkView FindHeapChunkByAddress(uptr address) {
-  return AsanChunkView(malloc_info.FindChunkByAddr(address));
-}
-
-static u8 *Allocate(uptr alignment, uptr size, StackTrace *stack,
-                    AllocType alloc_type) {
-  __asan_init();
-  CHECK(stack);
-  if (size == 0) {
-    size = 1;  // TODO(kcc): do something smarter
-  }
-  CHECK(IsPowerOfTwo(alignment));
-  uptr rounded_size = RoundUpTo(size, REDZONE);
-  uptr needed_size = rounded_size + REDZONE;
-  if (alignment > REDZONE) {
-    needed_size += alignment;
-  }
-  CHECK(IsAligned(needed_size, REDZONE));
-  if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
-    Report("WARNING: AddressSanitizer failed to allocate %p bytes\n",
-           (void*)size);
-    return 0;
-  }
-
-  u8 size_class = SizeToSizeClass(needed_size);
-  uptr size_to_allocate = SizeClassToSize(size_class);
-  CHECK(size_to_allocate >= kMinAllocSize);
-  CHECK(size_to_allocate >= needed_size);
-  CHECK(IsAligned(size_to_allocate, REDZONE));
-
-  if (flags()->verbosity >= 3) {
-    Printf("Allocate align: %zu size: %zu class: %u real: %zu\n",
-         alignment, size, size_class, size_to_allocate);
-  }
-
-  AsanThread *t = asanThreadRegistry().GetCurrent();
-  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
-  // Statistics
-  thread_stats.mallocs++;
-  thread_stats.malloced += size;
-  thread_stats.malloced_redzones += size_to_allocate - size;
-  thread_stats.malloced_by_size[size_class]++;
-
-  AsanChunk *m = 0;
-  if (!t || size_to_allocate >= kMaxSizeForThreadLocalFreeList) {
-    // get directly from global storage.
-    m = malloc_info.AllocateChunks(size_class, 1);
-    thread_stats.malloc_large++;
-  } else {
-    // get from the thread-local storage.
-    AsanChunk **fl = &t->malloc_storage().free_lists_[size_class];
-    if (!*fl) {
-      uptr n_new_chunks = kMaxSizeForThreadLocalFreeList / size_to_allocate;
-      *fl = malloc_info.AllocateChunks(size_class, n_new_chunks);
-      thread_stats.malloc_small_slow++;
-    }
-    m = *fl;
-    *fl = (*fl)->next;
-  }
-  CHECK(m);
-  CHECK(m->chunk_state == CHUNK_AVAILABLE);
-  m->chunk_state = CHUNK_ALLOCATED;
-  m->alloc_type = alloc_type;
-  m->next = 0;
-  CHECK(m->Size() == size_to_allocate);
-  uptr addr = (uptr)m + REDZONE;
-  CHECK(addr <= (uptr)m->compressed_free_stack());
-
-  if (alignment > REDZONE && (addr & (alignment - 1))) {
-    addr = RoundUpTo(addr, alignment);
-    CHECK((addr & (alignment - 1)) == 0);
-    AsanChunk *p = (AsanChunk*)(addr - REDZONE);
-    p->chunk_state = CHUNK_MEMALIGN;
-    p->used_size = (uptr)p - (uptr)m;
-    m->alignment_log = Log2(alignment);
-    CHECK(m->Beg() == addr);
-  } else {
-    m->alignment_log = Log2(REDZONE);
-  }
-  CHECK(m == PtrToChunk(addr));
-  m->used_size = size;
-  CHECK(m->Beg() == addr);
-  m->alloc_tid = t ? t->tid() : 0;
-  m->free_tid   = kInvalidTid;
-  StackTrace::CompressStack(stack, m->compressed_alloc_stack(),
-                                m->compressed_alloc_stack_size());
-  PoisonShadow(addr, rounded_size, 0);
-  if (size < rounded_size) {
-    PoisonHeapPartialRightRedzone(addr + rounded_size - REDZONE,
-                                  size & (REDZONE - 1));
-  }
-  if (size <= (uptr)(flags()->max_malloc_fill_size)) {
-    REAL(memset)((void*)addr, 0, rounded_size);
-  }
-  return (u8*)addr;
-}
-
-static void Deallocate(u8 *ptr, StackTrace *stack, AllocType alloc_type) {
-  if (!ptr) return;
-  CHECK(stack);
-
-  if (flags()->debug) {
-    CHECK(malloc_info.FindPageGroup((uptr)ptr));
-  }
-
-  // Printf("Deallocate %p\n", ptr);
-  AsanChunk *m = PtrToChunk((uptr)ptr);
-
-  // Flip the chunk_state atomically to avoid race on double-free.
-  u8 old_chunk_state = atomic_exchange((atomic_uint8_t*)m, CHUNK_QUARANTINE,
-                                       memory_order_acq_rel);
-
-  if (old_chunk_state == CHUNK_QUARANTINE) {
-    ReportDoubleFree((uptr)ptr, stack);
-  } else if (old_chunk_state != CHUNK_ALLOCATED) {
-    ReportFreeNotMalloced((uptr)ptr, stack);
-  }
-  CHECK(old_chunk_state == CHUNK_ALLOCATED);
-  if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
-    ReportAllocTypeMismatch((uptr)ptr, stack,
-                            (AllocType)m->alloc_type, (AllocType)alloc_type);
-  // With REDZONE==16 m->next is in the user area, otherwise it should be 0.
-  CHECK(REDZONE <= 16 || !m->next);
-  CHECK(m->free_tid == kInvalidTid);
-  CHECK(m->alloc_tid >= 0);
-  AsanThread *t = asanThreadRegistry().GetCurrent();
-  m->free_tid = t ? t->tid() : 0;
-  StackTrace::CompressStack(stack, m->compressed_free_stack(),
-                                m->compressed_free_stack_size());
-  uptr rounded_size = RoundUpTo(m->used_size, REDZONE);
-  PoisonShadow((uptr)ptr, rounded_size, kAsanHeapFreeMagic);
-
-  // Statistics.
-  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
-  thread_stats.frees++;
-  thread_stats.freed += m->used_size;
-  thread_stats.freed_by_size[m->SizeClass()]++;
-
-  CHECK(m->chunk_state == CHUNK_QUARANTINE);
-
-  if (t) {
-    AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
-    ms->quarantine_.Push(m);
-
-    if (ms->quarantine_.size() > kMaxThreadLocalQuarantine) {
-      malloc_info.SwallowThreadLocalMallocStorage(ms, false);
-    }
-  } else {
-    malloc_info.BypassThreadLocalQuarantine(m);
-  }
-}
-
-static u8 *Reallocate(u8 *old_ptr, uptr new_size,
-                           StackTrace *stack) {
-  CHECK(old_ptr && new_size);
-
-  // Statistics.
-  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
-  thread_stats.reallocs++;
-  thread_stats.realloced += new_size;
-
-  AsanChunk *m = PtrToChunk((uptr)old_ptr);
-  CHECK(m->chunk_state == CHUNK_ALLOCATED);
-  uptr old_size = m->used_size;
-  uptr memcpy_size = Min(new_size, old_size);
-  u8 *new_ptr = Allocate(0, new_size, stack, FROM_MALLOC);
-  if (new_ptr) {
-    CHECK(REAL(memcpy) != 0);
-    REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
-    Deallocate(old_ptr, stack, FROM_MALLOC);
-  }
-  return new_ptr;
-}
-
-}  // namespace __asan
-
-#if !SANITIZER_SUPPORTS_WEAK_HOOKS
-// Provide default (no-op) implementation of malloc hooks.
-extern "C" {
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
-void __asan_malloc_hook(void *ptr, uptr size) {
-  (void)ptr;
-  (void)size;
-}
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
-void __asan_free_hook(void *ptr) {
-  (void)ptr;
-}
-}  // extern "C"
-#endif
-
-namespace __asan {
-
-void InitializeAllocator() { }
-
-void PrintInternalAllocatorStats() {
-}
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
-                    AllocType alloc_type) {
-  void *ptr = (void*)Allocate(alignment, size, stack, alloc_type);
-  ASAN_MALLOC_HOOK(ptr, size);
-  return ptr;
-}
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
-  ASAN_FREE_HOOK(ptr);
-  Deallocate((u8*)ptr, stack, alloc_type);
-}
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void *asan_malloc(uptr size, StackTrace *stack) {
-  void *ptr = (void*)Allocate(0, size, stack, FROM_MALLOC);
-  ASAN_MALLOC_HOOK(ptr, size);
-  return ptr;
-}
-
-void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
-  if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
-  void *ptr = (void*)Allocate(0, nmemb * size, stack, FROM_MALLOC);
-  if (ptr)
-    REAL(memset)(ptr, 0, nmemb * size);
-  ASAN_MALLOC_HOOK(ptr, size);
-  return ptr;
-}
-
-void *asan_realloc(void *p, uptr size, StackTrace *stack) {
-  if (p == 0) {
-    void *ptr = (void*)Allocate(0, size, stack, FROM_MALLOC);
-    ASAN_MALLOC_HOOK(ptr, size);
-    return ptr;
-  } else if (size == 0) {
-    ASAN_FREE_HOOK(p);
-    Deallocate((u8*)p, stack, FROM_MALLOC);
-    return 0;
-  }
-  return Reallocate((u8*)p, size, stack);
-}
-
-void *asan_valloc(uptr size, StackTrace *stack) {
-  void *ptr = (void*)Allocate(GetPageSizeCached(), size, stack, FROM_MALLOC);
-  ASAN_MALLOC_HOOK(ptr, size);
-  return ptr;
-}
-
-void *asan_pvalloc(uptr size, StackTrace *stack) {
-  uptr PageSize = GetPageSizeCached();
-  size = RoundUpTo(size, PageSize);
-  if (size == 0) {
-    // pvalloc(0) should allocate one page.
-    size = PageSize;
-  }
-  void *ptr = (void*)Allocate(PageSize, size, stack, FROM_MALLOC);
-  ASAN_MALLOC_HOOK(ptr, size);
-  return ptr;
-}
-
-int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
-                          StackTrace *stack) {
-  void *ptr = Allocate(alignment, size, stack, FROM_MALLOC);
-  CHECK(IsAligned((uptr)ptr, alignment));
-  ASAN_MALLOC_HOOK(ptr, size);
-  *memptr = ptr;
-  return 0;
-}
-
-uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) {
-  CHECK(stack);
-  if (ptr == 0) return 0;
-  uptr usable_size = malloc_info.AllocationSize((uptr)ptr);
-  if (flags()->check_malloc_usable_size && (usable_size == 0)) {
-    ReportMallocUsableSizeNotOwned((uptr)ptr, stack);
-  }
-  return usable_size;
-}
-
-uptr asan_mz_size(const void *ptr) {
-  return malloc_info.AllocationSize((uptr)ptr);
-}
-
-void asan_mz_force_lock() {
-  malloc_info.ForceLock();
-}
-
-void asan_mz_force_unlock() {
-  malloc_info.ForceUnlock();
-}
-
-}  // namespace __asan
-
-// ---------------------- Interface ---------------- {{{1
-using namespace __asan;  // NOLINT
-
-// ASan allocator doesn't reserve extra bytes, so normally we would
-// just return "size".
-uptr __asan_get_estimated_allocated_size(uptr size) {
-  if (size == 0) return 1;
-  return Min(size, kMaxAllowedMallocSize);
-}
-
-bool __asan_get_ownership(const void *p) {
-  return malloc_info.AllocationSize((uptr)p) > 0;
-}
-
-uptr __asan_get_allocated_size(const void *p) {
-  if (p == 0) return 0;
-  uptr allocated_size = malloc_info.AllocationSize((uptr)p);
-  // Die if p is not malloced or if it is already freed.
-  if (allocated_size == 0) {
-    GET_STACK_TRACE_FATAL_HERE;
-    ReportAsanGetAllocatedSizeNotOwned((uptr)p, &stack);
-  }
-  return allocated_size;
-}
-#endif  // ASAN_ALLOCATOR_VERSION
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h
index 38477c0..f817ce3 100644
--- a/lib/asan/asan_allocator.h
+++ b/lib/asan/asan_allocator.h
@@ -9,7 +9,7 @@
 //
 // This file is a part of AddressSanitizer, an address sanity checker.
 //
-// ASan-private header for asan_allocator.cc.
+// ASan-private header for asan_allocator2.cc.
 //===----------------------------------------------------------------------===//
 
 #ifndef ASAN_ALLOCATOR_H
@@ -19,14 +19,6 @@
 #include "asan_interceptors.h"
 #include "sanitizer_common/sanitizer_list.h"
 
-// We are in the process of transitioning from the old allocator (version 1)
-// to a new one (version 2). The change is quite intrusive so both allocators
-// will co-exist in the source base for a while. The actual allocator is chosen
-// at build time by redefining this macro.
-#ifndef ASAN_ALLOCATOR_VERSION
-#define ASAN_ALLOCATOR_VERSION 2
-#endif  // ASAN_ALLOCATOR_VERSION
-
 namespace __asan {
 
 enum AllocType {
@@ -99,109 +91,17 @@
 
 struct AsanThreadLocalMallocStorage {
   explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
-#if ASAN_ALLOCATOR_VERSION == 1
-      : quarantine_(x)
-#endif
       { }
   AsanThreadLocalMallocStorage() {
     CHECK(REAL(memset));
     REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
   }
 
-#if ASAN_ALLOCATOR_VERSION == 1
-  AsanChunkFifoList quarantine_;
-  AsanChunk *free_lists_[kNumberOfSizeClasses];
-#else
   uptr quarantine_cache[16];
   uptr allocator2_cache[96 * (512 * 8 + 16)];  // Opaque.
-#endif
   void CommitBack();
 };
 
-// Fake stack frame contains local variables of one function.
-// This struct should fit into a stack redzone (32 bytes).
-struct FakeFrame {
-  uptr magic;  // Modified by the instrumented code.
-  uptr descr;  // Modified by the instrumented code.
-  FakeFrame *next;
-  u64 real_stack     : 48;
-  u64 size_minus_one : 16;
-};
-
-struct FakeFrameFifo {
- public:
-  void FifoPush(FakeFrame *node);
-  FakeFrame *FifoPop();
- private:
-  FakeFrame *first_, *last_;
-};
-
-class FakeFrameLifo {
- public:
-  void LifoPush(FakeFrame *node) {
-    node->next = top_;
-    top_ = node;
-  }
-  void LifoPop() {
-    CHECK(top_);
-    top_ = top_->next;
-  }
-  FakeFrame *top() { return top_; }
- private:
-  FakeFrame *top_;
-};
-
-// For each thread we create a fake stack and place stack objects on this fake
-// stack instead of the real stack. The fake stack is not really a stack but
-// a fast malloc-like allocator so that when a function exits the fake stack
-// is not poped but remains there for quite some time until gets used again.
-// So, we poison the objects on the fake stack when function returns.
-// It helps us find use-after-return bugs.
-// We can not rely on __asan_stack_free being called on every function exit,
-// so we maintain a lifo list of all current fake frames and update it on every
-// call to __asan_stack_malloc.
-class FakeStack {
- public:
-  FakeStack();
-  explicit FakeStack(LinkerInitialized) {}
-  void Init(uptr stack_size);
-  void StopUsingFakeStack() { alive_ = false; }
-  void Cleanup();
-  uptr AllocateStack(uptr size, uptr real_stack);
-  static void OnFree(uptr ptr, uptr size, uptr real_stack);
-  // Return the bottom of the maped region.
-  uptr AddrIsInFakeStack(uptr addr);
-  bool StackSize() { return stack_size_; }
-
- private:
-  static const uptr kMinStackFrameSizeLog = 9;  // Min frame is 512B.
-  static const uptr kMaxStackFrameSizeLog = 16;  // Max stack frame is 64K.
-  static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
-  static const uptr kNumberOfSizeClasses =
-      kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
-
-  bool AddrIsInSizeClass(uptr addr, uptr size_class);
-
-  // Each size class should be large enough to hold all frames.
-  uptr ClassMmapSize(uptr size_class);
-
-  uptr ClassSize(uptr size_class) {
-    return 1UL << (size_class + kMinStackFrameSizeLog);
-  }
-
-  void DeallocateFrame(FakeFrame *fake_frame);
-
-  uptr ComputeSizeClass(uptr alloc_size);
-  void AllocateOneSizeClass(uptr size_class);
-
-  uptr stack_size_;
-  bool   alive_;
-
-  uptr allocated_size_classes_[kNumberOfSizeClasses];
-  FakeFrameFifo size_classes_[kNumberOfSizeClasses];
-  FakeFrameLifo call_stack_;
-};
-
 void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
                     AllocType alloc_type);
 void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type);
diff --git a/lib/asan/asan_allocator2.cc b/lib/asan/asan_allocator2.cc
index 3288f28..63d6ada 100644
--- a/lib/asan/asan_allocator2.cc
+++ b/lib/asan/asan_allocator2.cc
@@ -13,20 +13,20 @@
 // This variant uses the allocator from sanitizer_common, i.e. the one shared
 // with ThreadSanitizer and MemorySanitizer.
 //
-// Status: under development, not enabled by default yet.
 //===----------------------------------------------------------------------===//
 #include "asan_allocator.h"
-#if ASAN_ALLOCATOR_VERSION == 2
 
 #include "asan_mapping.h"
+#include "asan_poisoning.h"
 #include "asan_report.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
 #include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_list.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_quarantine.h"
+#include "lsan/lsan_common.h"
 
 namespace __asan {
 
@@ -34,7 +34,7 @@
   void OnMap(uptr p, uptr size) const {
     PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
     // Statistics.
-    AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+    AsanStats &thread_stats = GetCurrentThreadStats();
     thread_stats.mmaps++;
     thread_stats.mmaped += size;
   }
@@ -49,7 +49,7 @@
     uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
     FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
     // Statistics.
-    AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+    AsanStats &thread_stats = GetCurrentThreadStats();
     thread_stats.munmaps++;
     thread_stats.munmaped += size;
   }
@@ -58,18 +58,23 @@
 #if SANITIZER_WORDSIZE == 64
 #if defined(__powerpc64__)
 const uptr kAllocatorSpace =  0xa0000000000ULL;
+const uptr kAllocatorSize  =  0x20000000000ULL;  // 2T.
 #else
 const uptr kAllocatorSpace = 0x600000000000ULL;
-#endif
 const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
+#endif
 typedef DefaultSizeClassMap SizeClassMap;
 typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
     SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
 #elif SANITIZER_WORDSIZE == 32
 static const u64 kAddressSpaceSize = 1ULL << 32;
 typedef CompactSizeClassMap SizeClassMap;
+static const uptr kRegionSizeLog = 20;
+static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
 typedef SizeClassAllocator32<0, kAddressSpaceSize, 16,
-  SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
+  SizeClassMap, kRegionSizeLog,
+  FlatByteMap<kFlatByteMapSize>,
+  AsanMapUnmapCallback> PrimaryAllocator;
 #endif
 
 typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
@@ -141,14 +146,15 @@
 // ChunkBase consists of ChunkHeader and other bytes that overlap with user
 // memory.
 
-// If a memory chunk is allocated by memalign and we had to increase the
-// allocation size to achieve the proper alignment, then we store this magic
+// If the left redzone is greater than the ChunkHeader size we store a magic
 // value in the first uptr word of the memory block and store the address of
 // ChunkBase in the next uptr.
-// M B ? ? ? L L L L L L  H H U U U U U U
-//   M -- magic value kMemalignMagic
+// M B L L L L L L L L L  H H U U U U U U
+//   |                    ^
+//   ---------------------|
+//   M -- magic value kAllocBegMagic
 //   B -- address of ChunkHeader pointing to the first 'H'
-static const uptr kMemalignMagic = 0xCC6E96B9;
+static const uptr kAllocBegMagic = 0xCC6E96B9;
 
 struct ChunkHeader {
   // 1-st 8 bytes.
@@ -159,6 +165,7 @@
   u32 from_memalign     : 1;
   u32 alloc_type        : 2;
   u32 rz_log            : 3;
+  u32 lsan_tag          : 2;
   // 2-nd 8 bytes
   // This field is used for small sizes. For large sizes it is equal to
   // SizeClassMap::kMaxSize and the actual size is stored in the
@@ -169,7 +176,6 @@
 
 struct ChunkBase : ChunkHeader {
   // Header2, intersects with user memory.
-  AsanChunk *next;
   u32 free_context_id;
 };
 
@@ -190,7 +196,8 @@
       return allocator.GetBlockBegin(reinterpret_cast<void *>(this));
     return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
   }
-  // We store the alloc/free stack traces in the chunk itself.
+  // If we don't use stack depot, we store the alloc/free stack traces
+  // in the chunk itself.
   u32 *AllocStackBeg() {
     return (u32*)(Beg() - RZLog2Size(rz_log));
   }
@@ -206,6 +213,9 @@
     uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
     return (available - kChunkHeader2Size) / sizeof(u32);
   }
+  bool AddrIsInside(uptr addr) {
+    return (addr >= Beg()) && (addr < Beg() + UsedSize());
+  }
 };
 
 uptr AsanChunkView::Beg() { return chunk_->Beg(); }
@@ -259,22 +269,25 @@
   }
 
   void Recycle(AsanChunk *m) {
-    CHECK(m->chunk_state == CHUNK_QUARANTINE);
-    m->chunk_state = CHUNK_AVAILABLE;
+    CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
+    atomic_store((atomic_uint8_t*)m, CHUNK_AVAILABLE, memory_order_relaxed);
     CHECK_NE(m->alloc_tid, kInvalidTid);
     CHECK_NE(m->free_tid, kInvalidTid);
     PoisonShadow(m->Beg(),
                  RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
                  kAsanHeapLeftRedzoneMagic);
     void *p = reinterpret_cast<void *>(m->AllocBeg());
-    if (m->from_memalign) {
-      uptr *memalign_magic = reinterpret_cast<uptr *>(p);
-      CHECK_EQ(memalign_magic[0], kMemalignMagic);
-      CHECK_EQ(memalign_magic[1], reinterpret_cast<uptr>(m));
+    if (p != m) {
+      uptr *alloc_magic = reinterpret_cast<uptr *>(p);
+      CHECK_EQ(alloc_magic[0], kAllocBegMagic);
+      // Clear the magic value, as allocator internals may overwrite the
+      // contents of deallocated chunk, confusing GetAsanChunk lookup.
+      alloc_magic[0] = 0;
+      CHECK_EQ(alloc_magic[1], reinterpret_cast<uptr>(m));
     }
 
     // Statistics.
-    AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+    AsanStats &thread_stats = GetCurrentThreadStats();
     thread_stats.real_frees++;
     thread_stats.really_freed += m->UsedSize();
 
@@ -298,9 +311,10 @@
 }
 
 static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
-                      AllocType alloc_type) {
+                      AllocType alloc_type, bool can_fill) {
   if (!asan_inited)
     __asan_init();
+  Flags &fl = *flags();
   CHECK(stack);
   const uptr min_alignment = SHADOW_GRANULARITY;
   if (alignment < min_alignment)
@@ -316,9 +330,7 @@
   CHECK(IsPowerOfTwo(alignment));
   uptr rz_log = ComputeRZLog(size);
   uptr rz_size = RZLog2Size(rz_log);
-  uptr rounded_size = RoundUpTo(size, alignment);
-  if (rounded_size < kChunkHeader2Size)
-    rounded_size = kChunkHeader2Size;
+  uptr rounded_size = RoundUpTo(Max(size, kChunkHeader2Size), alignment);
   uptr needed_size = rounded_size + rz_size;
   if (alignment > min_alignment)
     needed_size += alignment;
@@ -336,7 +348,7 @@
     return 0;
   }
 
-  AsanThread *t = asanThreadRegistry().GetCurrent();
+  AsanThread *t = GetCurrentThread();
   void *allocated;
   if (t) {
     AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
@@ -347,8 +359,6 @@
     allocated = allocator.Allocate(cache, needed_size, 8, false);
   }
   uptr alloc_beg = reinterpret_cast<uptr>(allocated);
-  // Clear the first allocated word (an old kMemalignMagic may still be there).
-  reinterpret_cast<uptr *>(alloc_beg)[0] = 0;
   uptr alloc_end = alloc_beg + needed_size;
   uptr beg_plus_redzone = alloc_beg + rz_size;
   uptr user_beg = beg_plus_redzone;
@@ -358,7 +368,6 @@
   CHECK_LE(user_end, alloc_end);
   uptr chunk_beg = user_beg - kChunkHeaderSize;
   AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
-  m->chunk_state = CHUNK_ALLOCATED;
   m->alloc_type = alloc_type;
   m->rz_log = rz_log;
   u32 alloc_tid = t ? t->tid() : 0;
@@ -366,11 +375,10 @@
   CHECK_EQ(alloc_tid, m->alloc_tid);  // Does alloc_tid fit into the bitfield?
   m->free_tid = kInvalidTid;
   m->from_memalign = user_beg != beg_plus_redzone;
-  if (m->from_memalign) {
-    CHECK_LE(beg_plus_redzone + 2 * sizeof(uptr), user_beg);
-    uptr *memalign_magic = reinterpret_cast<uptr *>(alloc_beg);
-    memalign_magic[0] = kMemalignMagic;
-    memalign_magic[1] = chunk_beg;
+  if (alloc_beg != chunk_beg) {
+    CHECK_LE(alloc_beg+ 2 * sizeof(uptr), chunk_beg);
+    reinterpret_cast<uptr *>(alloc_beg)[0] = kAllocBegMagic;
+    reinterpret_cast<uptr *>(alloc_beg)[1] = chunk_beg;
   }
   if (using_primary_allocator) {
     CHECK(size);
@@ -384,7 +392,7 @@
     meta[1] = chunk_beg;
   }
 
-  if (flags()->use_stack_depot) {
+  if (fl.use_stack_depot) {
     m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
   } else {
     m->alloc_context_id = 0;
@@ -396,12 +404,12 @@
   if (size_rounded_down_to_granularity)
     PoisonShadow(user_beg, size_rounded_down_to_granularity, 0);
   // Deal with the end of the region if size is not aligned to granularity.
-  if (size != size_rounded_down_to_granularity && flags()->poison_heap) {
+  if (size != size_rounded_down_to_granularity && fl.poison_heap) {
     u8 *shadow = (u8*)MemToShadow(user_beg + size_rounded_down_to_granularity);
     *shadow = size & (SHADOW_GRANULARITY - 1);
   }
 
-  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+  AsanStats &thread_stats = GetCurrentThreadStats();
   thread_stats.mallocs++;
   thread_stats.malloced += size;
   thread_stats.malloced_redzones += needed_size - size;
@@ -411,26 +419,43 @@
     thread_stats.malloc_large++;
 
   void *res = reinterpret_cast<void *>(user_beg);
+  if (can_fill && fl.max_malloc_fill_size) {
+    uptr fill_size = Min(size, (uptr)fl.max_malloc_fill_size);
+    REAL(memset)(res, fl.malloc_fill_byte, fill_size);
+  }
+#if CAN_SANITIZE_LEAKS
+  m->lsan_tag = __lsan::DisabledInThisThread() ? __lsan::kIgnored
+                                               : __lsan::kDirectlyLeaked;
+#endif
+  // Must be the last mutation of metadata in this function.
+  atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release);
   ASAN_MALLOC_HOOK(res, size);
   return res;
 }
 
-static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
-  uptr p = reinterpret_cast<uptr>(ptr);
-  if (p == 0) return;
-  ASAN_FREE_HOOK(ptr);
-  uptr chunk_beg = p - kChunkHeaderSize;
-  AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
-
-  // Flip the chunk_state atomically to avoid race on double-free.
-  u8 old_chunk_state = atomic_exchange((atomic_uint8_t*)m, CHUNK_QUARANTINE,
-                                       memory_order_relaxed);
-
-  if (old_chunk_state == CHUNK_QUARANTINE)
+static void ReportInvalidFree(void *ptr, u8 chunk_state, StackTrace *stack) {
+  if (chunk_state == CHUNK_QUARANTINE)
     ReportDoubleFree((uptr)ptr, stack);
-  else if (old_chunk_state != CHUNK_ALLOCATED)
+  else
     ReportFreeNotMalloced((uptr)ptr, stack);
-  CHECK(old_chunk_state == CHUNK_ALLOCATED);
+}
+
+static void AtomicallySetQuarantineFlag(AsanChunk *m,
+                                        void *ptr, StackTrace *stack) {
+  u8 old_chunk_state = CHUNK_ALLOCATED;
+  // Flip the chunk_state atomically to avoid race on double-free.
+  if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
+                                      CHUNK_QUARANTINE, memory_order_acquire))
+    ReportInvalidFree(ptr, old_chunk_state, stack);
+  CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
+}
+
+// Expects the chunk to already be marked as quarantined by using
+// AtomicallySetQuarantineFlag.
+static void QuarantineChunk(AsanChunk *m, void *ptr,
+                            StackTrace *stack, AllocType alloc_type) {
+  CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
+
   if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
     ReportAllocTypeMismatch((uptr)ptr, stack,
                             (AllocType)m->alloc_type, (AllocType)alloc_type);
@@ -438,7 +463,7 @@
   CHECK_GE(m->alloc_tid, 0);
   if (SANITIZER_WORDSIZE == 64)  // On 32-bits this resides in user area.
     CHECK_EQ(m->free_tid, kInvalidTid);
-  AsanThread *t = asanThreadRegistry().GetCurrent();
+  AsanThread *t = GetCurrentThread();
   m->free_tid = t ? t->tid() : 0;
   if (flags()->use_stack_depot) {
     m->free_context_id = StackDepotPut(stack->trace, stack->size);
@@ -446,13 +471,12 @@
     m->free_context_id = 0;
     StackTrace::CompressStack(stack, m->FreeStackBeg(), m->FreeStackSize());
   }
-  CHECK(m->chunk_state == CHUNK_QUARANTINE);
   // Poison the region.
   PoisonShadow(m->Beg(),
                RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
                kAsanHeapFreeMagic);
 
-  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+  AsanStats &thread_stats = GetCurrentThreadStats();
   thread_stats.frees++;
   thread_stats.freed += m->UsedSize();
 
@@ -470,57 +494,67 @@
   }
 }
 
+static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
+  uptr p = reinterpret_cast<uptr>(ptr);
+  if (p == 0) return;
+
+  uptr chunk_beg = p - kChunkHeaderSize;
+  AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+  ASAN_FREE_HOOK(ptr);
+  // Must mark the chunk as quarantined before any changes to its metadata.
+  AtomicallySetQuarantineFlag(m, ptr, stack);
+  QuarantineChunk(m, ptr, stack, alloc_type);
+}
+
 static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
   CHECK(old_ptr && new_size);
   uptr p = reinterpret_cast<uptr>(old_ptr);
   uptr chunk_beg = p - kChunkHeaderSize;
   AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
 
-  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+  AsanStats &thread_stats = GetCurrentThreadStats();
   thread_stats.reallocs++;
   thread_stats.realloced += new_size;
 
-  CHECK(m->chunk_state == CHUNK_ALLOCATED);
-  uptr old_size = m->UsedSize();
-  uptr memcpy_size = Min(new_size, old_size);
-  void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC);
+  void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true);
   if (new_ptr) {
+    u8 chunk_state = m->chunk_state;
+    if (chunk_state != CHUNK_ALLOCATED)
+      ReportInvalidFree(old_ptr, chunk_state, stack);
     CHECK_NE(REAL(memcpy), (void*)0);
+    uptr memcpy_size = Min(new_size, m->UsedSize());
+    // If realloc() races with free(), we may start copying freed memory.
+    // However, we will report racy double-free later anyway.
     REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
     Deallocate(old_ptr, stack, FROM_MALLOC);
   }
   return new_ptr;
 }
 
-static AsanChunk *GetAsanChunkByAddr(uptr p) {
-  void *ptr = reinterpret_cast<void *>(p);
-  uptr alloc_beg = reinterpret_cast<uptr>(allocator.GetBlockBegin(ptr));
+// Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
+static AsanChunk *GetAsanChunk(void *alloc_beg) {
   if (!alloc_beg) return 0;
-  uptr *memalign_magic = reinterpret_cast<uptr *>(alloc_beg);
-  if (memalign_magic[0] == kMemalignMagic) {
-    AsanChunk *m = reinterpret_cast<AsanChunk *>(memalign_magic[1]);
-    CHECK(m->from_memalign);
-    return m;
-  }
-  if (!allocator.FromPrimary(ptr)) {
-    uptr *meta = reinterpret_cast<uptr *>(
-        allocator.GetMetaData(reinterpret_cast<void *>(alloc_beg)));
+  if (!allocator.FromPrimary(alloc_beg)) {
+    uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(alloc_beg));
     AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]);
     return m;
   }
-  uptr actual_size = allocator.GetActuallyAllocatedSize(ptr);
-  CHECK_LE(actual_size, SizeClassMap::kMaxSize);
-  // We know the actually allocted size, but we don't know the redzone size.
-  // Just try all possible redzone sizes.
-  for (u32 rz_log = 0; rz_log < 8; rz_log++) {
-    u32 rz_size = RZLog2Size(rz_log);
-    uptr max_possible_size = actual_size - rz_size;
-    if (ComputeRZLog(max_possible_size) != rz_log)
-      continue;
-    return reinterpret_cast<AsanChunk *>(
-        alloc_beg + rz_size - kChunkHeaderSize);
-  }
-  return 0;
+  uptr *alloc_magic = reinterpret_cast<uptr *>(alloc_beg);
+  if (alloc_magic[0] == kAllocBegMagic)
+    return reinterpret_cast<AsanChunk *>(alloc_magic[1]);
+  return reinterpret_cast<AsanChunk *>(alloc_beg);
+}
+
+static AsanChunk *GetAsanChunkByAddr(uptr p) {
+  void *alloc_beg = allocator.GetBlockBegin(reinterpret_cast<void *>(p));
+  return GetAsanChunk(alloc_beg);
+}
+
+// Allocator must be locked when this function is called.
+static AsanChunk *GetAsanChunkByAddrFastLocked(uptr p) {
+  void *alloc_beg =
+      allocator.GetBlockBeginFastLocked(reinterpret_cast<void *>(p));
+  return GetAsanChunk(alloc_beg);
 }
 
 static uptr AllocationSize(uptr p) {
@@ -588,7 +622,7 @@
 SANITIZER_INTERFACE_ATTRIBUTE
 void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
                     AllocType alloc_type) {
-  return Allocate(size, alignment, stack, alloc_type);
+  return Allocate(size, alignment, stack, alloc_type, true);
 }
 
 SANITIZER_INTERFACE_ATTRIBUTE
@@ -598,12 +632,12 @@
 
 SANITIZER_INTERFACE_ATTRIBUTE
 void *asan_malloc(uptr size, StackTrace *stack) {
-  return Allocate(size, 8, stack, FROM_MALLOC);
+  return Allocate(size, 8, stack, FROM_MALLOC, true);
 }
 
 void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
   if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
-  void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC);
+  void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
   // If the memory comes from the secondary allocator no need to clear it
   // as it comes directly from mmap.
   if (ptr && allocator.FromPrimary(ptr))
@@ -613,7 +647,7 @@
 
 void *asan_realloc(void *p, uptr size, StackTrace *stack) {
   if (p == 0)
-    return Allocate(size, 8, stack, FROM_MALLOC);
+    return Allocate(size, 8, stack, FROM_MALLOC, true);
   if (size == 0) {
     Deallocate(p, stack, FROM_MALLOC);
     return 0;
@@ -622,7 +656,7 @@
 }
 
 void *asan_valloc(uptr size, StackTrace *stack) {
-  return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC);
+  return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
 }
 
 void *asan_pvalloc(uptr size, StackTrace *stack) {
@@ -632,17 +666,18 @@
     // pvalloc(0) should allocate one page.
     size = PageSize;
   }
-  return Allocate(size, PageSize, stack, FROM_MALLOC);
+  return Allocate(size, PageSize, stack, FROM_MALLOC, true);
 }
 
 int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
                         StackTrace *stack) {
-  void *ptr = Allocate(size, alignment, stack, FROM_MALLOC);
+  void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true);
   CHECK(IsAligned((uptr)ptr, alignment));
   *memptr = ptr;
   return 0;
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
 uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) {
   CHECK(stack);
   if (ptr == 0) return 0;
@@ -668,6 +703,86 @@
 
 }  // namespace __asan
 
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+void LockAllocator() {
+  __asan::allocator.ForceLock();
+}
+
+void UnlockAllocator() {
+  __asan::allocator.ForceUnlock();
+}
+
+void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
+  *begin = (uptr)&__asan::allocator;
+  *end = *begin + sizeof(__asan::allocator);
+}
+
+uptr PointsIntoChunk(void* p) {
+  uptr addr = reinterpret_cast<uptr>(p);
+  __asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr);
+  if (!m) return 0;
+  uptr chunk = m->Beg();
+  if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr))
+    return chunk;
+  return 0;
+}
+
+uptr GetUserBegin(uptr chunk) {
+  __asan::AsanChunk *m =
+      __asan::GetAsanChunkByAddrFastLocked(chunk);
+  CHECK(m);
+  return m->Beg();
+}
+
+LsanMetadata::LsanMetadata(uptr chunk) {
+  metadata_ = reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize);
+}
+
+bool LsanMetadata::allocated() const {
+  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+  return m->chunk_state == __asan::CHUNK_ALLOCATED;
+}
+
+ChunkTag LsanMetadata::tag() const {
+  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+  return static_cast<ChunkTag>(m->lsan_tag);
+}
+
+void LsanMetadata::set_tag(ChunkTag value) {
+  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+  m->lsan_tag = value;
+}
+
+uptr LsanMetadata::requested_size() const {
+  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+  return m->UsedSize();
+}
+
+u32 LsanMetadata::stack_trace_id() const {
+  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
+  return m->alloc_context_id;
+}
+
+void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+  __asan::allocator.ForEachChunk(callback, arg);
+}
+
+IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+  uptr addr = reinterpret_cast<uptr>(p);
+  __asan::AsanChunk *m = __asan::GetAsanChunkByAddr(addr);
+  if (!m) return kIgnoreObjectInvalid;
+  if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr)) {
+    if (m->lsan_tag == kIgnored)
+      return kIgnoreObjectAlreadyIgnored;
+    m->lsan_tag = __lsan::kIgnored;
+    return kIgnoreObjectSuccess;
+  } else {
+    return kIgnoreObjectInvalid;
+  }
+}
+}  // namespace __lsan
+
 // ---------------------- Interface ---------------- {{{1
 using namespace __asan;  // NOLINT
 
@@ -708,6 +823,3 @@
 }
 }  // extern "C"
 #endif
-
-
-#endif  // ASAN_ALLOCATOR_VERSION
diff --git a/lib/asan/asan_blacklist.txt b/lib/asan/asan_blacklist.txt
new file mode 100644
index 0000000..63b3c31
--- /dev/null
+++ b/lib/asan/asan_blacklist.txt
@@ -0,0 +1,10 @@
+# Blacklist for AddressSanitizer. Turns off instrumentation of particular
+# functions or sources. Use with care. You may set location of blacklist
+# at compile-time using -fsanitize-blacklist=<path> flag.
+
+# Example usage:
+# fun:*bad_function_name*
+# src:file_with_tricky_code.cc
+# global:*global_with_bad_access_or_initialization*
+# global:*global_with_initialization_issues*=init
+# type:*Namespace::ClassName*=init
diff --git a/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc
index 2cede36..1540971 100644
--- a/lib/asan/asan_fake_stack.cc
+++ b/lib/asan/asan_fake_stack.cc
@@ -12,16 +12,11 @@
 // FakeStack is used to detect use-after-return bugs.
 //===----------------------------------------------------------------------===//
 #include "asan_allocator.h"
+#include "asan_poisoning.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
 
 namespace __asan {
 
-FakeStack::FakeStack() {
-  CHECK(REAL(memset) != 0);
-  REAL(memset)(this, 0, sizeof(*this));
-}
-
 bool FakeStack::AddrIsInSizeClass(uptr addr, uptr size_class) {
   uptr mem = allocated_size_classes_[size_class];
   uptr size = ClassMmapSize(size_class);
@@ -30,24 +25,26 @@
 }
 
 uptr FakeStack::AddrIsInFakeStack(uptr addr) {
-  for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
-    if (AddrIsInSizeClass(addr, i)) return allocated_size_classes_[i];
+  for (uptr size_class = 0; size_class < kNumberOfSizeClasses; size_class++) {
+    if (!AddrIsInSizeClass(addr, size_class)) continue;
+    uptr size_class_first_ptr = allocated_size_classes_[size_class];
+    uptr size = ClassSize(size_class);
+    CHECK_LE(size_class_first_ptr, addr);
+    CHECK_GT(size_class_first_ptr + ClassMmapSize(size_class), addr);
+    return size_class_first_ptr + ((addr - size_class_first_ptr) / size) * size;
   }
   return 0;
 }
 
 // We may want to compute this during compilation.
-inline uptr FakeStack::ComputeSizeClass(uptr alloc_size) {
+ALWAYS_INLINE uptr FakeStack::ComputeSizeClass(uptr alloc_size) {
   uptr rounded_size = RoundUpToPowerOfTwo(alloc_size);
   uptr log = Log2(rounded_size);
-  CHECK(alloc_size <= (1UL << log));
-  if (!(alloc_size > (1UL << (log-1)))) {
-    Printf("alloc_size %zu log %zu\n", alloc_size, log);
-  }
-  CHECK(alloc_size > (1UL << (log-1)));
+  CHECK_LE(alloc_size, (1UL << log));
+  CHECK_GT(alloc_size, (1UL << (log-1)));
   uptr res = log < kMinStackFrameSizeLog ? 0 : log - kMinStackFrameSizeLog;
-  CHECK(res < kNumberOfSizeClasses);
-  CHECK(ClassSize(res) >= rounded_size);
+  CHECK_LT(res, kNumberOfSizeClasses);
+  CHECK_GE(ClassSize(res), rounded_size);
   return res;
 }
 
@@ -95,7 +92,10 @@
 }
 
 uptr FakeStack::ClassMmapSize(uptr size_class) {
-  return RoundUpToPowerOfTwo(stack_size_);
+  // Limit allocation size to ClassSize * MaxDepth when running with unlimited
+  // stack.
+  return RoundUpTo(Min(ClassSize(size_class) * kMaxRecursionDepth, stack_size_),
+                   GetPageSizeCached());
 }
 
 void FakeStack::AllocateOneSizeClass(uptr size_class) {
@@ -103,7 +103,7 @@
   uptr new_mem = (uptr)MmapOrDie(
       ClassMmapSize(size_class), __FUNCTION__);
   // Printf("T%d new_mem[%zu]: %p-%p mmap %zu\n",
-  //       asanThreadRegistry().GetCurrent()->tid(),
+  //       GetCurrentThread()->tid(),
   //       size_class, new_mem, new_mem + ClassMmapSize(size_class),
   //       ClassMmapSize(size_class));
   uptr i;
@@ -115,7 +115,7 @@
   allocated_size_classes_[size_class] = new_mem;
 }
 
-uptr FakeStack::AllocateStack(uptr size, uptr real_stack) {
+ALWAYS_INLINE uptr FakeStack::AllocateStack(uptr size, uptr real_stack) {
   if (!alive_) return real_stack;
   CHECK(size <= kMaxStackMallocSize && size > 1);
   uptr size_class = ComputeSizeClass(size);
@@ -137,9 +137,9 @@
   return ptr;
 }
 
-void FakeStack::DeallocateFrame(FakeFrame *fake_frame) {
+ALWAYS_INLINE void FakeStack::DeallocateFrame(FakeFrame *fake_frame) {
   CHECK(alive_);
-  uptr size = fake_frame->size_minus_one + 1;
+  uptr size = static_cast<uptr>(fake_frame->size_minus_one + 1);
   uptr size_class = ComputeSizeClass(size);
   CHECK(allocated_size_classes_[size_class]);
   uptr ptr = (uptr)fake_frame;
@@ -148,11 +148,11 @@
   size_classes_[size_class].FifoPush(fake_frame);
 }
 
-void FakeStack::OnFree(uptr ptr, uptr size, uptr real_stack) {
+ALWAYS_INLINE void FakeStack::OnFree(uptr ptr, uptr size, uptr real_stack) {
   FakeFrame *fake_frame = (FakeFrame*)ptr;
-  CHECK(fake_frame->magic = kRetiredStackFrameMagic);
-  CHECK(fake_frame->descr != 0);
-  CHECK(fake_frame->size_minus_one == size - 1);
+  CHECK_EQ(fake_frame->magic, kRetiredStackFrameMagic);
+  CHECK_NE(fake_frame->descr, 0);
+  CHECK_EQ(fake_frame->size_minus_one, size - 1);
   PoisonShadow(ptr, size, kAsanStackAfterReturnMagic);
 }
 
@@ -163,12 +163,13 @@
 
 uptr __asan_stack_malloc(uptr size, uptr real_stack) {
   if (!flags()->use_fake_stack) return real_stack;
-  AsanThread *t = asanThreadRegistry().GetCurrent();
+  AsanThread *t = GetCurrentThread();
   if (!t) {
     // TSD is gone, use the real stack.
     return real_stack;
   }
-  uptr ptr = t->fake_stack().AllocateStack(size, real_stack);
+  t->LazyInitFakeStack();
+  uptr ptr = t->fake_stack()->AllocateStack(size, real_stack);
   // Printf("__asan_stack_malloc %p %zu %p\n", ptr, size, real_stack);
   return ptr;
 }
diff --git a/lib/asan/asan_fake_stack.h b/lib/asan/asan_fake_stack.h
new file mode 100644
index 0000000..6a5e5f6
--- /dev/null
+++ b/lib/asan/asan_fake_stack.h
@@ -0,0 +1,117 @@
+//===-- asan_fake_stack.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.
+//
+// ASan-private header for asan_fake_stack.cc
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_FAKE_STACK_H
+#define ASAN_FAKE_STACK_H
+
+namespace __asan {
+
+// Fake stack frame contains local variables of one function.
+struct FakeFrame {
+  uptr magic;  // Modified by the instrumented code.
+  uptr descr;  // Modified by the instrumented code.
+  uptr pc;     // Modified by the instrumented code.
+  u64 real_stack     : 48;
+  u64 size_minus_one : 16;
+  // End of the first 32 bytes.
+  // The rest should not be used when the frame is active.
+  FakeFrame *next;
+};
+
+struct FakeFrameFifo {
+ public:
+  void FifoPush(FakeFrame *node);
+  FakeFrame *FifoPop();
+ private:
+  FakeFrame *first_, *last_;
+};
+
+template<uptr kMaxNumberOfFrames>
+class FakeFrameLifo {
+ public:
+  explicit FakeFrameLifo(LinkerInitialized) {}
+  FakeFrameLifo() : n_frames_(0) {}
+  void LifoPush(FakeFrame *node) {
+    CHECK_LT(n_frames_, kMaxNumberOfFrames);
+    frames_[n_frames_++] = node;
+  }
+  void LifoPop() {
+    CHECK(n_frames_);
+    n_frames_--;
+  }
+  FakeFrame *top() {
+    if (n_frames_ == 0)
+      return 0;
+    return frames_[n_frames_ - 1];
+  }
+ private:
+  uptr n_frames_;
+  FakeFrame *frames_[kMaxNumberOfFrames];
+};
+
+// For each thread we create a fake stack and place stack objects on this fake
+// stack instead of the real stack. The fake stack is not really a stack but
+// a fast malloc-like allocator so that when a function exits the fake stack
+// is not poped but remains there for quite some time until gets used again.
+// So, we poison the objects on the fake stack when function returns.
+// It helps us find use-after-return bugs.
+// We can not rely on __asan_stack_free being called on every function exit,
+// so we maintain a lifo list of all current fake frames and update it on every
+// call to __asan_stack_malloc.
+class FakeStack {
+ public:
+  void Init(uptr stack_size);
+  void StopUsingFakeStack() { alive_ = false; }
+  void Cleanup();
+  uptr AllocateStack(uptr size, uptr real_stack);
+  static void OnFree(uptr ptr, uptr size, uptr real_stack);
+  // Return the bottom of the maped region.
+  uptr AddrIsInFakeStack(uptr addr);
+  uptr StackSize() const { return stack_size_; }
+
+ private:
+  static const uptr kMinStackFrameSizeLog = 9;  // Min frame is 512B.
+  static const uptr kMaxStackFrameSizeLog = 16;  // Max stack frame is 64K.
+  static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
+  static const uptr kNumberOfSizeClasses =
+      kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
+  static const uptr kMaxRecursionDepth = 15000;
+
+  bool AddrIsInSizeClass(uptr addr, uptr size_class);
+
+  // Each size class should be large enough to hold all frames.
+  uptr ClassMmapSize(uptr size_class);
+
+  uptr ClassSize(uptr size_class) {
+    return 1UL << (size_class + kMinStackFrameSizeLog);
+  }
+
+  void DeallocateFrame(FakeFrame *fake_frame);
+
+  uptr ComputeSizeClass(uptr alloc_size);
+  void AllocateOneSizeClass(uptr size_class);
+
+  uptr stack_size_;
+  bool   alive_;
+
+  uptr allocated_size_classes_[kNumberOfSizeClasses];
+  FakeFrameFifo size_classes_[kNumberOfSizeClasses];
+  FakeFrameLifo<kMaxRecursionDepth> call_stack_;
+};
+
+COMPILER_CHECK(sizeof(FakeStack) <= (1 << 17));
+
+}  // namespace __asan
+
+#endif  // ASAN_FAKE_STACK_H
diff --git a/lib/asan/asan_flags.h b/lib/asan/asan_flags.h
index 377354a..b83a147 100644
--- a/lib/asan/asan_flags.h
+++ b/lib/asan/asan_flags.h
@@ -32,8 +32,6 @@
   // Lower value may reduce memory usage but increase the chance of
   // false negatives.
   int  quarantine_size;
-  // If set, uses in-process symbolizer from common sanitizer runtime.
-  bool symbolize;
   // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
   int  verbosity;
   // Size (in bytes) of redzones around heap objects.
@@ -47,8 +45,6 @@
   int  report_globals;
   // If set, attempts to catch initialization order issues.
   bool check_initialization_order;
-  // Max number of stack frames kept for each allocation/deallocation.
-  int  malloc_context_size;
   // If set, uses custom wrappers and replacements for libc string functions
   // to find more errors.
   bool replace_str;
@@ -56,11 +52,11 @@
   bool replace_intrin;
   // Used on Mac only.
   bool mac_ignore_invalid_free;
-  // ASan allocator flag. See asan_allocator.cc.
+  // ASan allocator flag.
   bool use_fake_stack;
-  // ASan allocator flag. Sets the maximal size of allocation request
-  // that would return memory filled with zero bytes.
-  int  max_malloc_fill_size;
+  // ASan allocator flag. max_malloc_fill_size is the maximal amount of bytes
+  // that will be filled with malloc_fill_byte on malloc.
+  int max_malloc_fill_size, malloc_fill_byte;
   // Override exit status if something was reported.
   int  exitcode;
   // If set, user may manually mark memory regions as poisoned or unpoisoned.
@@ -71,6 +67,8 @@
   int  sleep_before_dying;
   // If set, registers ASan custom segv handler.
   bool handle_segv;
+  // If set, allows user register segv handler even if ASan registers one.
+  bool allow_user_segv_handler;
   // If set, uses alternate stack for signal handling.
   bool use_sigaltstack;
   // Allow the users to work around the bug in Nvidia drivers prior to 295.*.
@@ -91,18 +89,10 @@
   // Allow the tool to re-exec the program. This may interfere badly with the
   // debugger.
   bool allow_reexec;
-  // Strips this prefix from file paths in error reports.
-  const char *strip_path_prefix;
   // If set, prints not only thread creation stacks for threads in error report,
   // but also thread creation stacks for threads that created those threads,
   // etc. up to main thread.
   bool print_full_thread_history;
-  // ASan will write logs to "log_path.pid" instead of stderr.
-  const char *log_path;
-  // Use fast (frame-pointer-based) unwinder on fatal errors (if available).
-  bool fast_unwind_on_fatal;
-  // Use fast (frame-pointer-based) unwinder on malloc/free (if available).
-  bool fast_unwind_on_malloc;
   // Poison (or not) the heap memory on [de]allocation. Zero value is useful
   // for benchmarking the allocator or instrumentator.
   bool poison_heap;
@@ -113,9 +103,15 @@
   // If true, assume that memcmp(p1, p2, n) always reads n bytes before
   // comparing p1 and p2.
   bool strict_memcmp;
+  // If true, assume that dynamic initializers can never access globals from
+  // other modules, even if the latter are already initialized.
+  bool strict_init_order;
 };
 
-Flags *flags();
+extern Flags asan_flags_dont_use_directly;
+inline Flags *flags() {
+  return &asan_flags_dont_use_directly;
+}
 void InitializeFlags(Flags *f, const char *env);
 
 }  // namespace __asan
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
index 3101f16..3c3d620 100644
--- a/lib/asan/asan_globals.cc
+++ b/lib/asan/asan_globals.cc
@@ -14,11 +14,14 @@
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_mapping.h"
+#include "asan_poisoning.h"
 #include "asan_report.h"
 #include "asan_stack.h"
 #include "asan_stats.h"
 #include "asan_thread.h"
+#include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
 
 namespace __asan {
 
@@ -32,15 +35,26 @@
 static BlockingMutex mu_for_globals(LINKER_INITIALIZED);
 static LowLevelAllocator allocator_for_globals;
 static ListOfGlobals *list_of_all_globals;
-static ListOfGlobals *list_of_dynamic_init_globals;
 
-void PoisonRedZones(const Global &g)  {
+static const int kDynamicInitGlobalsInitialCapacity = 512;
+struct DynInitGlobal {
+  Global g;
+  bool initialized;
+};
+typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
+// Lazy-initialized and never deleted.
+static VectorOfGlobals *dynamic_init_globals;
+
+ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
+  FastPoisonShadow(g->beg, g->size_with_redzone, value);
+}
+
+ALWAYS_INLINE void PoisonRedZones(const Global &g) {
   uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
-  PoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
-               kAsanGlobalRedzoneMagic);
+  FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
+                   kAsanGlobalRedzoneMagic);
   if (g.size != aligned_size) {
-    // partial right redzone
-    PoisonShadowPartialRightRedzone(
+    FastPoisonShadowPartialRightRedzone(
         g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
         g.size % SHADOW_GRANULARITY,
         SHADOW_GRANULARITY,
@@ -48,6 +62,12 @@
   }
 }
 
+static void ReportGlobal(const Global &g, const char *prefix) {
+  Report("%s Global: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
+         prefix, (void*)g.beg, g.size, g.size_with_redzone, g.name,
+         g.module_name, g.has_dynamic_init);
+}
+
 bool DescribeAddressIfGlobal(uptr addr, uptr size) {
   if (!flags()->report_globals) return false;
   BlockingMutexLock lock(&mu_for_globals);
@@ -55,8 +75,7 @@
   for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
     const Global &g = *l->g;
     if (flags()->report_globals >= 2)
-      Report("Search Global: beg=%p size=%zu name=%s\n",
-             (void*)g.beg, g.size, (char*)g.name);
+      ReportGlobal(g, "Search");
     res |= DescribeAddressRelativeToGlobal(addr, size, g);
   }
   return res;
@@ -68,24 +87,26 @@
 static void RegisterGlobal(const Global *g) {
   CHECK(asan_inited);
   if (flags()->report_globals >= 2)
-    Report("Added Global: beg=%p size=%zu/%zu name=%s dyn.init=%zu\n",
-           (void*)g->beg, g->size, g->size_with_redzone, g->name,
-           g->has_dynamic_init);
+    ReportGlobal(*g, "Added");
   CHECK(flags()->report_globals);
   CHECK(AddrIsInMem(g->beg));
   CHECK(AddrIsAlignedByGranularity(g->beg));
   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
-  PoisonRedZones(*g);
+  if (flags()->poison_heap)
+    PoisonRedZones(*g);
   ListOfGlobals *l =
       (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
   l->g = g;
   l->next = list_of_all_globals;
   list_of_all_globals = l;
   if (g->has_dynamic_init) {
-    l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
-    l->g = g;
-    l->next = list_of_dynamic_init_globals;
-    list_of_dynamic_init_globals = l;
+    if (dynamic_init_globals == 0) {
+      void *mem = allocator_for_globals.Allocate(sizeof(VectorOfGlobals));
+      dynamic_init_globals = new(mem)
+          VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
+    }
+    DynInitGlobal dyn_global = { *g, false };
+    dynamic_init_globals->push_back(dyn_global);
   }
 }
 
@@ -95,34 +116,26 @@
   CHECK(AddrIsInMem(g->beg));
   CHECK(AddrIsAlignedByGranularity(g->beg));
   CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
-  PoisonShadow(g->beg, g->size_with_redzone, 0);
+  if (flags()->poison_heap)
+    PoisonShadowForGlobal(g, 0);
   // We unpoison the shadow memory for the global but we do not remove it from
   // the list because that would require O(n^2) time with the current list
   // implementation. It might not be worth doing anyway.
 }
 
-// Poison all shadow memory for a single global.
-static void PoisonGlobalAndRedzones(const Global *g) {
-  CHECK(asan_inited);
-  CHECK(flags()->check_initialization_order);
-  CHECK(AddrIsInMem(g->beg));
-  CHECK(AddrIsAlignedByGranularity(g->beg));
-  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
-  if (flags()->report_globals >= 3)
-    Printf("DynInitPoison  : %s\n", g->name);
-  PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic);
-}
-
-static void UnpoisonGlobal(const Global *g) {
-  CHECK(asan_inited);
-  CHECK(flags()->check_initialization_order);
-  CHECK(AddrIsInMem(g->beg));
-  CHECK(AddrIsAlignedByGranularity(g->beg));
-  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
-  if (flags()->report_globals >= 3)
-    Printf("DynInitUnpoison: %s\n", g->name);
-  PoisonShadow(g->beg, g->size_with_redzone, 0);
-  PoisonRedZones(*g);
+void StopInitOrderChecking() {
+  BlockingMutexLock lock(&mu_for_globals);
+  if (!flags()->check_initialization_order || !dynamic_init_globals)
+    return;
+  flags()->check_initialization_order = false;
+  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
+    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
+    const Global *g = &dyn_g.g;
+    // Unpoison the whole global.
+    PoisonShadowForGlobal(g, 0);
+    // Poison redzones back.
+    PoisonRedZones(*g);
+  }
 }
 
 }  // namespace __asan
@@ -153,31 +166,47 @@
 // when all dynamically initialized globals are unpoisoned.  This method
 // poisons all global variables not defined in this TU, so that a dynamic
 // initializer can only touch global variables in the same TU.
-void __asan_before_dynamic_init(uptr first_addr, uptr last_addr) {
-  if (!flags()->check_initialization_order) return;
-  CHECK(list_of_dynamic_init_globals);
+void __asan_before_dynamic_init(const char *module_name) {
+  if (!flags()->check_initialization_order ||
+      !flags()->poison_heap)
+    return;
+  bool strict_init_order = flags()->strict_init_order;
+  CHECK(dynamic_init_globals);
+  CHECK(module_name);
+  CHECK(asan_inited);
   BlockingMutexLock lock(&mu_for_globals);
-  bool from_current_tu = false;
-  // The list looks like:
-  // a => ... => b => last_addr => ... => first_addr => c => ...
-  // The globals of the current TU reside between last_addr and first_addr.
-  for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) {
-    if (l->g->beg == last_addr)
-      from_current_tu = true;
-    if (!from_current_tu)
-      PoisonGlobalAndRedzones(l->g);
-    if (l->g->beg == first_addr)
-      from_current_tu = false;
+  if (flags()->report_globals >= 3)
+    Printf("DynInitPoison module: %s\n", module_name);
+  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
+    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
+    const Global *g = &dyn_g.g;
+    if (dyn_g.initialized)
+      continue;
+    if (g->module_name != module_name)
+      PoisonShadowForGlobal(g, kAsanInitializationOrderMagic);
+    else if (!strict_init_order)
+      dyn_g.initialized = true;
   }
-  CHECK(!from_current_tu);
 }
 
 // This method runs immediately after dynamic initialization in each TU, when
 // all dynamically initialized globals except for those defined in the current
 // TU are poisoned.  It simply unpoisons all dynamically initialized globals.
 void __asan_after_dynamic_init() {
-  if (!flags()->check_initialization_order) return;
+  if (!flags()->check_initialization_order ||
+      !flags()->poison_heap)
+    return;
+  CHECK(asan_inited);
   BlockingMutexLock lock(&mu_for_globals);
-  for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next)
-    UnpoisonGlobal(l->g);
+  // FIXME: Optionally report that we're unpoisoning globals from a module.
+  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
+    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
+    const Global *g = &dyn_g.g;
+    if (!dyn_g.initialized) {
+      // Unpoison the whole global.
+      PoisonShadowForGlobal(g, 0);
+      // Poison redzones back.
+      PoisonRedZones(*g);
+    }
+  }
 }
diff --git a/lib/asan/asan_intercepted_functions.h b/lib/asan/asan_intercepted_functions.h
index 1f872c9..842781c 100644
--- a/lib/asan/asan_intercepted_functions.h
+++ b/lib/asan/asan_intercepted_functions.h
@@ -25,11 +25,10 @@
 
 // Use macro to describe if specific function should be
 // intercepted on a given platform.
-#if !defined(_WIN32)
+#if !SANITIZER_WINDOWS
 # define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
 # define ASAN_INTERCEPT__LONGJMP 1
 # define ASAN_INTERCEPT_STRDUP 1
-# define ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP 1
 # define ASAN_INTERCEPT_INDEX 1
 # define ASAN_INTERCEPT_PTHREAD_CREATE 1
 # define ASAN_INTERCEPT_MLOCKX 1
@@ -37,49 +36,54 @@
 # define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
 # define ASAN_INTERCEPT__LONGJMP 0
 # define ASAN_INTERCEPT_STRDUP 0
-# define ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP 0
 # define ASAN_INTERCEPT_INDEX 0
 # define ASAN_INTERCEPT_PTHREAD_CREATE 0
 # define ASAN_INTERCEPT_MLOCKX 0
 #endif
 
-#if defined(__linux__)
+#if SANITIZER_LINUX
 # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
 #else
 # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
 #endif
 
-#if !defined(__APPLE__)
+#if !SANITIZER_MAC
 # define ASAN_INTERCEPT_STRNLEN 1
 #else
 # define ASAN_INTERCEPT_STRNLEN 0
 #endif
 
-#if defined(__linux__) && !defined(ANDROID)
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
 # define ASAN_INTERCEPT_SWAPCONTEXT 1
 #else
 # define ASAN_INTERCEPT_SWAPCONTEXT 0
 #endif
 
-#if !defined(ANDROID) && !defined(_WIN32)
+#if !SANITIZER_ANDROID && !SANITIZER_WINDOWS
 # define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
 #else
 # define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
 #endif
 
-#if !defined(_WIN32)
+#if !SANITIZER_WINDOWS
 # define ASAN_INTERCEPT_SIGLONGJMP 1
 #else
 # define ASAN_INTERCEPT_SIGLONGJMP 0
 #endif
 
-#if ASAN_HAS_EXCEPTIONS && !defined(_WIN32)
+#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS
 # define ASAN_INTERCEPT___CXA_THROW 1
 #else
 # define ASAN_INTERCEPT___CXA_THROW 0
 #endif
 
-# if defined(_WIN32)
+#if !SANITIZER_WINDOWS
+# define ASAN_INTERCEPT___CXA_ATEXIT 1
+#else
+# define ASAN_INTERCEPT___CXA_ATEXIT 0
+#endif
+
+# if SANITIZER_WINDOWS
 extern "C" {
 // Windows threads.
 __declspec(dllimport)
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index b1efe74..10b3778 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -17,10 +17,10 @@
 #include "asan_intercepted_functions.h"
 #include "asan_internal.h"
 #include "asan_mapping.h"
+#include "asan_poisoning.h"
 #include "asan_report.h"
 #include "asan_stack.h"
 #include "asan_stats.h"
-#include "asan_thread_registry.h"
 #include "interception/interception.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
@@ -53,7 +53,7 @@
   } while (0)
 
 #define ASAN_READ_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, false)
-#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true);
+#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true)
 
 // Behavior of functions like "memcpy" or "strcpy" is undefined
 // if memory intervals overlap. We report error in this case.
@@ -89,9 +89,9 @@
 }
 
 void SetThreadName(const char *name) {
-  AsanThread *t = asanThreadRegistry().GetCurrent();
+  AsanThread *t = GetCurrentThread();
   if (t)
-    t->summary()->set_name(name);
+    asanThreadRegistry().SetThreadName(t->tid(), name);
 }
 
 }  // namespace __asan
@@ -99,40 +99,75 @@
 // ---------------------- Wrappers ---------------- {{{1
 using namespace __asan;  // NOLINT
 
+DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
+DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
+
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
+  do {                                                \
+  } while (false)
 #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
   ASAN_WRITE_RANGE(ptr, size)
 #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) ASAN_READ_RANGE(ptr, size)
-#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
-  do {                                           \
-    ctx = 0;                                     \
-    (void)ctx;                                   \
-    ENSURE_ASAN_INITED();                        \
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...)              \
+  do {                                                        \
+    if (asan_init_is_running) return REAL(func)(__VA_ARGS__); \
+    ctx = 0;                                                  \
+    (void) ctx;                                               \
+    ENSURE_ASAN_INITED();                                     \
   } while (false)
-#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) do { } while (false)
-#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) do { } while (false)
+#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
+  do {                                         \
+  } while (false)
+#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
+  do {                                         \
+  } while (false)
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+  do {                                                      \
+  } while (false)
 #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
 #include "sanitizer_common/sanitizer_common_interceptors.inc"
 
+#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(p, s)
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
+  do {                                       \
+  } while (false)
+#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
+  do {                                        \
+  } while (false)
+#include "sanitizer_common/sanitizer_common_syscalls.inc"
+
 static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
   AsanThread *t = (AsanThread*)arg;
-  asanThreadRegistry().SetCurrent(t);
-  return t->ThreadStart();
+  SetCurrentThread(t);
+  return t->ThreadStart(GetTid());
 }
 
 #if ASAN_INTERCEPT_PTHREAD_CREATE
+extern "C" int pthread_attr_getdetachstate(void *attr, int *v);
+
 INTERCEPTOR(int, pthread_create, void *thread,
     void *attr, void *(*start_routine)(void*), void *arg) {
+  EnsureMainThreadIDIsCorrect();
+  // Strict init-order checking in thread-hostile.
+  if (flags()->strict_init_order)
+    StopInitOrderChecking();
   GET_STACK_TRACE_THREAD;
-  u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
-  AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
-  asanThreadRegistry().RegisterThread(t);
+  int detached = 0;
+  if (attr != 0)
+    pthread_attr_getdetachstate(attr, &detached);
+
+  u32 current_tid = GetCurrentTidOrInvalid();
+  AsanThread *t = AsanThread::Create(start_routine, arg);
+  CreateThreadContextArgs args = { t, &stack };
+  asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
   return REAL(pthread_create)(thread, attr, asan_thread_start, t);
 }
 #endif  // ASAN_INTERCEPT_PTHREAD_CREATE
 
 #if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
 INTERCEPTOR(void*, signal, int signum, void *handler) {
-  if (!AsanInterceptsSignal(signum)) {
+  if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
     return REAL(signal)(signum, handler);
   }
   return 0;
@@ -140,15 +175,15 @@
 
 INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
                             struct sigaction *oldact) {
-  if (!AsanInterceptsSignal(signum)) {
+  if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
     return REAL(sigaction)(signum, act, oldact);
   }
   return 0;
 }
-#elif ASAN_POSIX
+#elif SANITIZER_POSIX
 // We need to have defined REAL(sigaction) on posix systems.
 DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
-    struct sigaction *oldact);
+    struct sigaction *oldact)
 #endif  // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
 
 #if ASAN_INTERCEPT_SWAPCONTEXT
@@ -218,13 +253,15 @@
 // Since asan maps 16T of RAM, mlock is completely unfriendly to asan.
 // All functions return 0 (success).
 static void MlockIsUnsupported() {
-  static bool printed = 0;
+  static bool printed = false;
   if (printed) return;
   printed = true;
-  Printf("INFO: AddressSanitizer ignores mlock/mlockall/munlock/munlockall\n");
+  if (flags()->verbosity > 0) {
+    Printf("INFO: AddressSanitizer ignores "
+           "mlock/mlockall/munlock/munlockall\n");
+  }
 }
 
-extern "C" {
 INTERCEPTOR(int, mlock, const void *addr, uptr len) {
   MlockIsUnsupported();
   return 0;
@@ -244,18 +281,11 @@
   MlockIsUnsupported();
   return 0;
 }
-}  // extern "C"
 
 static inline int CharCmp(unsigned char c1, unsigned char c2) {
   return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
 }
 
-static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
-  int c1_low = ToLower(c1);
-  int c2_low = ToLower(c2);
-  return c1_low - c2_low;
-}
-
 INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
   if (!asan_inited) return internal_memcmp(a1, a2, size);
   ENSURE_ASAN_INITED();
@@ -355,11 +385,11 @@
 INTERCEPTOR(char*, index, const char *string, int c)
   ALIAS(WRAPPER_NAME(strchr));
 # else
-#  if defined(__APPLE__)
+#  if SANITIZER_MAC
 DECLARE_REAL(char*, index, const char *string, int c)
 OVERRIDE_FUNCTION(index, strchr);
 #  else
-DEFINE_REAL(char*, index, const char *string, int c);
+DEFINE_REAL(char*, index, const char *string, int c)
 #  endif
 # endif
 #endif  // ASAN_INTERCEPT_INDEX
@@ -402,26 +432,8 @@
   return REAL(strncat)(to, from, size);
 }
 
-INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
-  if (!asan_inited) return internal_strcmp(s1, s2);
-  if (asan_init_is_running) {
-    return REAL(strcmp)(s1, s2);
-  }
-  ENSURE_ASAN_INITED();
-  unsigned char c1, c2;
-  uptr i;
-  for (i = 0; ; i++) {
-    c1 = (unsigned char)s1[i];
-    c2 = (unsigned char)s2[i];
-    if (c1 != c2 || c1 == '\0') break;
-  }
-  ASAN_READ_RANGE(s1, i + 1);
-  ASAN_READ_RANGE(s2, i + 1);
-  return CharCmp(c1, c2);
-}
-
 INTERCEPTOR(char*, strcpy, char *to, const char *from) {  // NOLINT
-#if defined(__APPLE__)
+#if SANITIZER_MAC
   if (!asan_inited) return REAL(strcpy)(to, from);  // NOLINT
 #endif
   // strcpy is called from malloc_default_purgeable_zone()
@@ -441,21 +453,16 @@
 
 #if ASAN_INTERCEPT_STRDUP
 INTERCEPTOR(char*, strdup, const char *s) {
-#if defined(__APPLE__)
-  // FIXME: because internal_strdup() uses InternalAlloc(), which currently
-  // just calls malloc() on Mac, we can't use internal_strdup() with the
-  // dynamic runtime. We can remove the call to REAL(strdup) once InternalAlloc
-  // starts using mmap() instead.
-  // See also http://code.google.com/p/address-sanitizer/issues/detail?id=123.
-  if (!asan_inited) return REAL(strdup)(s);
-#endif
   if (!asan_inited) return internal_strdup(s);
   ENSURE_ASAN_INITED();
+  uptr length = REAL(strlen)(s);
   if (flags()->replace_str) {
-    uptr length = REAL(strlen)(s);
     ASAN_READ_RANGE(s, length + 1);
   }
-  return REAL(strdup)(s);
+  GET_STACK_TRACE_MALLOC;
+  void *new_mem = asan_malloc(length + 1, &stack);
+  REAL(memcpy)(new_mem, s, length + 1);
+  return reinterpret_cast<char*>(new_mem);
 }
 #endif
 
@@ -474,56 +481,6 @@
   return length;
 }
 
-#if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
-INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
-  ENSURE_ASAN_INITED();
-  unsigned char c1, c2;
-  uptr i;
-  for (i = 0; ; i++) {
-    c1 = (unsigned char)s1[i];
-    c2 = (unsigned char)s2[i];
-    if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
-  }
-  ASAN_READ_RANGE(s1, i + 1);
-  ASAN_READ_RANGE(s2, i + 1);
-  return CharCaseCmp(c1, c2);
-}
-
-INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, uptr n) {
-  ENSURE_ASAN_INITED();
-  unsigned char c1 = 0, c2 = 0;
-  uptr i;
-  for (i = 0; i < n; i++) {
-    c1 = (unsigned char)s1[i];
-    c2 = (unsigned char)s2[i];
-    if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
-  }
-  ASAN_READ_RANGE(s1, Min(i + 1, n));
-  ASAN_READ_RANGE(s2, Min(i + 1, n));
-  return CharCaseCmp(c1, c2);
-}
-#endif  // ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
-
-INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
-  if (!asan_inited) return internal_strncmp(s1, s2, size);
-  // strncmp is called from malloc_default_purgeable_zone()
-  // in __asan::ReplaceSystemAlloc() on Mac.
-  if (asan_init_is_running) {
-    return REAL(strncmp)(s1, s2, size);
-  }
-  ENSURE_ASAN_INITED();
-  unsigned char c1 = 0, c2 = 0;
-  uptr i;
-  for (i = 0; i < size; i++) {
-    c1 = (unsigned char)s1[i];
-    c2 = (unsigned char)s2[i];
-    if (c1 != c2 || c1 == '\0') break;
-  }
-  ASAN_READ_RANGE(s1, Min(i + 1, size));
-  ASAN_READ_RANGE(s2, Min(i + 1, size));
-  return CharCmp(c1, c2);
-}
-
 INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
   ENSURE_ASAN_INITED();
   if (flags()->replace_str) {
@@ -551,7 +508,7 @@
 }
 
 static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
-  CHECK(endptr != 0);
+  CHECK(endptr);
   if (nptr == *endptr) {
     // No digits were found at strtol call, we need to find out the last
     // symbol accessed by strtoll on our own.
@@ -582,7 +539,7 @@
 }
 
 INTERCEPTOR(int, atoi, const char *nptr) {
-#if defined(__APPLE__)
+#if SANITIZER_MAC
   if (!asan_inited) return REAL(atoi)(nptr);
 #endif
   ENSURE_ASAN_INITED();
@@ -601,7 +558,7 @@
 }
 
 INTERCEPTOR(long, atol, const char *nptr) {  // NOLINT
-#if defined(__APPLE__)
+#if SANITIZER_MAC
   if (!asan_inited) return REAL(atol)(nptr);
 #endif
   ENSURE_ASAN_INITED();
@@ -650,22 +607,47 @@
 }
 #endif  // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
 
+static void AtCxaAtexit(void *unused) {
+  (void)unused;
+  StopInitOrderChecking();
+}
+
+#if ASAN_INTERCEPT___CXA_ATEXIT
+INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
+            void *dso_handle) {
+  ENSURE_ASAN_INITED();
+  int res = REAL(__cxa_atexit)(func, arg, dso_handle);
+  REAL(__cxa_atexit)(AtCxaAtexit, 0, 0);
+  return res;
+}
+#endif  // ASAN_INTERCEPT___CXA_ATEXIT
+
+#if !SANITIZER_MAC
 #define ASAN_INTERCEPT_FUNC(name) do { \
       if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \
         Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
     } while (0)
+#else
+// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
+#define ASAN_INTERCEPT_FUNC(name)
+#endif  // SANITIZER_MAC
 
-#if defined(_WIN32)
+#if SANITIZER_WINDOWS
 INTERCEPTOR_WINAPI(DWORD, CreateThread,
                    void* security, uptr stack_size,
                    DWORD (__stdcall *start_routine)(void*), void* arg,
-                   DWORD flags, void* tid) {
+                   DWORD thr_flags, void* tid) {
+  // Strict init-order checking in thread-hostile.
+  if (flags()->strict_init_order)
+    StopInitOrderChecking();
   GET_STACK_TRACE_THREAD;
-  u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
-  AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
-  asanThreadRegistry().RegisterThread(t);
+  u32 current_tid = GetCurrentTidOrInvalid();
+  AsanThread *t = AsanThread::Create(start_routine, arg);
+  CreateThreadContextArgs args = { t, &stack };
+  bool detached = false;  // FIXME: how can we determine it on Windows?
+  asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
   return REAL(CreateThread)(security, stack_size,
-                            asan_thread_start, t, flags, tid);
+                            asan_thread_start, t, thr_flags, tid);
 }
 
 namespace __asan {
@@ -682,9 +664,6 @@
   static bool was_called_once;
   CHECK(was_called_once == false);
   was_called_once = true;
-#if defined(__APPLE__)
-  return;
-#else
   SANITIZER_COMMON_INTERCEPTORS_INIT;
 
   // Intercept mem* functions.
@@ -698,16 +677,10 @@
   // Intercept str* functions.
   ASAN_INTERCEPT_FUNC(strcat);  // NOLINT
   ASAN_INTERCEPT_FUNC(strchr);
-  ASAN_INTERCEPT_FUNC(strcmp);
   ASAN_INTERCEPT_FUNC(strcpy);  // NOLINT
   ASAN_INTERCEPT_FUNC(strlen);
   ASAN_INTERCEPT_FUNC(strncat);
-  ASAN_INTERCEPT_FUNC(strncmp);
   ASAN_INTERCEPT_FUNC(strncpy);
-#if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
-  ASAN_INTERCEPT_FUNC(strcasecmp);
-  ASAN_INTERCEPT_FUNC(strncasecmp);
-#endif
 #if ASAN_INTERCEPT_STRDUP
   ASAN_INTERCEPT_FUNC(strdup);
 #endif
@@ -760,15 +733,19 @@
   ASAN_INTERCEPT_FUNC(pthread_create);
 #endif
 
+  // Intercept atexit function.
+#if ASAN_INTERCEPT___CXA_ATEXIT
+  ASAN_INTERCEPT_FUNC(__cxa_atexit);
+#endif
+
   // Some Windows-specific interceptors.
-#if defined(_WIN32)
+#if SANITIZER_WINDOWS
   InitializeWindowsInterceptors();
 #endif
 
   if (flags()->verbosity > 0) {
     Report("AddressSanitizer: libc interceptors initialized\n");
   }
-#endif  // __APPLE__
 }
 
 }  // namespace __asan
diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h
index 8288d0c..24f7625 100644
--- a/lib/asan/asan_interface_internal.h
+++ b/lib/asan/asan_interface_internal.h
@@ -25,8 +25,13 @@
   // Everytime the asan ABI changes we also change the version number in this
   // name. Objects build with incompatible asan ABI version
   // will not link with run-time.
-  void __asan_init_v2() SANITIZER_INTERFACE_ATTRIBUTE;
-  #define __asan_init __asan_init_v2
+  // Changes between ABI versions:
+  // v1=>v2: added 'module_name' to __asan_global
+  // v2=>v3: stack frame description (created by the compiler)
+  //         contains the function PC as the 3-rd field (see
+  //         DescribeAddressIfStack).
+  void __asan_init_v3() SANITIZER_INTERFACE_ATTRIBUTE;
+  #define __asan_init __asan_init_v3
 
   // This structure describes an instrumented global variable.
   struct __asan_global {
@@ -34,7 +39,8 @@
     uptr size;               // The original size of the global.
     uptr size_with_redzone;  // The size with the redzone.
     const char *name;        // Name as a C string.
-    const char *module_name; // Module name as a C string.
+    const char *module_name; // Module name as a C string. This pointer is a
+                             // unique identifier of a module.
     uptr has_dynamic_init;   // Non-zero if the global has dynamic initializer.
   };
 
@@ -46,9 +52,8 @@
       SANITIZER_INTERFACE_ATTRIBUTE;
 
   // These two functions should be called before and after dynamic initializers
-  // run, respectively.  They should be called with parameters describing all
-  // dynamically initialized globals defined in the calling TU.
-  void __asan_before_dynamic_init(uptr first_addr, uptr last_addr)
+  // of a single module run, respectively.
+  void __asan_before_dynamic_init(const char *module_name)
       SANITIZER_INTERFACE_ATTRIBUTE;
   void __asan_after_dynamic_init()
       SANITIZER_INTERFACE_ATTRIBUTE;
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 1edd8a7..7a4d744 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -21,39 +21,8 @@
 #include "sanitizer_common/sanitizer_stacktrace.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
-#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
-# error "This operating system is not supported by AddressSanitizer"
-#endif
-
 #define ASAN_DEFAULT_FAILURE_EXITCODE 1
 
-#if defined(__linux__)
-# define ASAN_LINUX   1
-#else
-# define ASAN_LINUX   0
-#endif
-
-#if defined(__APPLE__)
-# define ASAN_MAC     1
-#else
-# define ASAN_MAC     0
-#endif
-
-#if defined(_WIN32)
-# define ASAN_WINDOWS 1
-#else
-# define ASAN_WINDOWS 0
-#endif
-
-#if defined(__ANDROID__) || defined(ANDROID)
-# define ASAN_ANDROID 1
-#else
-# define ASAN_ANDROID 0
-#endif
-
-
-#define ASAN_POSIX (ASAN_LINUX || ASAN_MAC)
-
 #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
 # error "The AddressSanitizer run-time should not be"
         " instrumented by AddressSanitizer"
@@ -63,7 +32,7 @@
 
 // If set, asan will install its own SEGV signal handler.
 #ifndef ASAN_NEEDS_SEGV
-# if ASAN_ANDROID == 1
+# if SANITIZER_ANDROID == 1
 #  define ASAN_NEEDS_SEGV 0
 # else
 #  define ASAN_NEEDS_SEGV 1
@@ -92,7 +61,7 @@
 #endif
 
 #ifndef ASAN_USE_PREINIT_ARRAY
-# define ASAN_USE_PREINIT_ARRAY (ASAN_LINUX && !ASAN_ANDROID)
+# define ASAN_USE_PREINIT_ARRAY (SANITIZER_LINUX && !SANITIZER_ANDROID)
 #endif
 
 // All internal functions in asan reside inside the __asan namespace
@@ -123,6 +92,7 @@
 void InstallSignalHandlers();
 void ReadContextStack(void *context, uptr *stack, uptr *ssize);
 void AsanPlatformThreadInit();
+void StopInitOrderChecking();
 
 // Wrapper for TLS/TSD.
 void AsanTSDInit(void (*destructor)(void *tsd));
@@ -131,24 +101,14 @@
 
 void AppendToErrorMessageBuffer(const char *buffer);
 
-// asan_poisoning.cc
-// Poisons the shadow memory for "size" bytes starting from "addr".
-void PoisonShadow(uptr addr, uptr size, u8 value);
-// Poisons the shadow memory for "redzone_size" bytes starting from
-// "addr + size".
-void PoisonShadowPartialRightRedzone(uptr addr,
-                                     uptr size,
-                                     uptr redzone_size,
-                                     u8 value);
-
 // Platfrom-specific options.
-#ifdef __APPLE__
+#if SANITIZER_MAC
 bool PlatformHasDifferentMemcpyAndMemmove();
 # define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
     (PlatformHasDifferentMemcpyAndMemmove())
 #else
 # define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true
-#endif  // __APPLE__
+#endif  // SANITIZER_MAC
 
 // Add convenient macro for interface functions that may be represented as
 // weak hooks.
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 845493d..2aea32a 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -11,12 +11,13 @@
 //
 // Linux-specific details.
 //===----------------------------------------------------------------------===//
-#ifdef __linux__
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
 
@@ -31,7 +32,7 @@
 #include <unistd.h>
 #include <unwind.h>
 
-#if !ASAN_ANDROID
+#if !SANITIZER_ANDROID
 // FIXME: where to get ucontext on Android?
 #include <sys/ucontext.h>
 #endif
@@ -50,7 +51,7 @@
 }
 
 void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
-#if ASAN_ANDROID
+#if SANITIZER_ANDROID
   *pc = *sp = *bp = 0;
 #elif defined(__arm__)
   ucontext_t *ucontext = (ucontext_t*)context;
@@ -88,6 +89,11 @@
   stk_ptr = (uptr *) *sp;
   *bp = stk_ptr[15];
 # endif
+# elif defined(__mips__)
+  ucontext_t *ucontext = (ucontext_t*)context;
+  *pc = ucontext->uc_mcontext.gregs[31];
+  *bp = ucontext->uc_mcontext.gregs[30];
+  *sp = ucontext->uc_mcontext.gregs[29];
 #else
 # error "Unsupported arch"
 #endif
@@ -101,25 +107,7 @@
   // Nothing here for now.
 }
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
-#if defined(__arm__) || \
-    defined(__powerpc__) || defined(__powerpc64__) || \
-    defined(__sparc__)
-  fast = false;
-#endif
-  if (!fast)
-    return stack->SlowUnwindStack(pc, max_s);
-  stack->size = 0;
-  stack->trace[0] = pc;
-  if (max_s > 1) {
-    stack->max_size = max_s;
-    if (!asan_inited) return;
-    if (AsanThread *t = asanThreadRegistry().GetCurrent())
-      stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom());
-  }
-}
-
-#if !ASAN_ANDROID
+#if !SANITIZER_ANDROID
 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
   ucontext_t *ucp = (ucontext_t*)context;
   *stack = (uptr)ucp->uc_stack.ss_sp;
@@ -133,4 +121,4 @@
 
 }  // namespace __asan
 
-#endif  // __linux__
+#endif  // SANITIZER_LINUX
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index 0f51a06..9200837 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -12,7 +12,8 @@
 // Mac-specific details.
 //===----------------------------------------------------------------------===//
 
-#ifdef __APPLE__
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
 
 #include "asan_interceptors.h"
 #include "asan_internal.h"
@@ -20,7 +21,7 @@
 #include "asan_mapping.h"
 #include "asan_stack.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
+#include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
 #include <crt_externs.h>  // for _NSGetArgv
@@ -52,15 +53,17 @@
 # endif  // SANITIZER_WORDSIZE
 }
 
-int GetMacosVersion() {
+MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
+
+MacosVersion GetMacosVersionInternal() {
   int mib[2] = { CTL_KERN, KERN_OSRELEASE };
   char version[100];
   uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
   for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
   // Get the version length.
-  CHECK(sysctl(mib, 2, 0, &len, 0, 0) != -1);
-  CHECK(len < maxlen);
-  CHECK(sysctl(mib, 2, version, &len, 0, 0) != -1);
+  CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
+  CHECK_LT(len, maxlen);
+  CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
   switch (version[0]) {
     case '9': return MACOS_VERSION_LEOPARD;
     case '1': {
@@ -68,6 +71,7 @@
         case '0': return MACOS_VERSION_SNOW_LEOPARD;
         case '1': return MACOS_VERSION_LION;
         case '2': return MACOS_VERSION_MOUNTAIN_LION;
+        case '3': return MACOS_VERSION_MAVERICKS;
         default: return MACOS_VERSION_UNKNOWN;
       }
     }
@@ -75,6 +79,18 @@
   }
 }
 
+MacosVersion GetMacosVersion() {
+  atomic_uint32_t *cache =
+      reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
+  MacosVersion result =
+      static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
+  if (result == MACOS_VERSION_UNINITIALIZED) {
+    result = GetMacosVersionInternal();
+    atomic_store(cache, result, memory_order_release);
+  }
+  return result;
+}
+
 bool PlatformHasDifferentMemcpyAndMemmove() {
   // On OS X 10.7 memcpy() and memmove() are both resolved
   // into memmove$VARIANT$sse42.
@@ -229,18 +245,6 @@
 void AsanPlatformThreadInit() {
 }
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
-  (void)fast;
-  stack->size = 0;
-  stack->trace[0] = pc;
-  if ((max_s) > 1) {
-    stack->max_size = max_s;
-    if (!asan_inited) return;
-    if (AsanThread *t = asanThreadRegistry().GetCurrent())
-      stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom());
-  }
-}
-
 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
   UNIMPLEMENTED();
 }
@@ -288,14 +292,16 @@
   u32 parent_tid;
 } asan_block_context_t;
 
-static ALWAYS_INLINE
+ALWAYS_INLINE
 void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
-  AsanThread *t = asanThreadRegistry().GetCurrent();
+  AsanThread *t = GetCurrentThread();
   if (!t) {
-    t = AsanThread::Create(parent_tid, 0, 0, stack);
-    asanThreadRegistry().RegisterThread(t);
+    t = AsanThread::Create(0, 0);
+    CreateThreadContextArgs args = { t, stack };
+    asanThreadRegistry().CreateThread(*(uptr*)t, true, parent_tid, &args);
     t->Init();
-    asanThreadRegistry().SetCurrent(t);
+    asanThreadRegistry().StartThread(t->tid(), 0, 0);
+    SetCurrentThread(t);
   }
 }
 
@@ -329,7 +335,7 @@
       (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
   asan_ctxt->block = ctxt;
   asan_ctxt->func = func;
-  asan_ctxt->parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
+  asan_ctxt->parent_tid = GetCurrentTidOrInvalid();
   return asan_ctxt;
 }
 
@@ -395,7 +401,7 @@
 
 #define GET_ASAN_BLOCK(work) \
   void (^asan_block)(void);  \
-  int parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); \
+  int parent_tid = GetCurrentTidOrInvalid(); \
   asan_block = ^(void) { \
     GET_STACK_TRACE_THREAD; \
     asan_register_worker_thread(parent_tid, &stack); \
@@ -433,4 +439,4 @@
 }
 #endif
 
-#endif  // __APPLE__
+#endif  // SANITIZER_MAC
diff --git a/lib/asan/asan_mac.h b/lib/asan/asan_mac.h
index be91386..827b8b0 100644
--- a/lib/asan/asan_mac.h
+++ b/lib/asan/asan_mac.h
@@ -36,12 +36,14 @@
 #endif
 } CFRuntimeBase;
 
-enum {
-  MACOS_VERSION_UNKNOWN = 0,
+enum MacosVersion {
+  MACOS_VERSION_UNINITIALIZED = 0,
+  MACOS_VERSION_UNKNOWN,
   MACOS_VERSION_LEOPARD,
   MACOS_VERSION_SNOW_LEOPARD,
   MACOS_VERSION_LION,
-  MACOS_VERSION_MOUNTAIN_LION
+  MACOS_VERSION_MOUNTAIN_LION,
+  MACOS_VERSION_MAVERICKS
 };
 
 // Used by asan_malloc_mac.cc and asan_mac.cc
@@ -49,7 +51,7 @@
 
 namespace __asan {
 
-int GetMacosVersion();
+MacosVersion GetMacosVersion();
 void MaybeReplaceCFAllocator();
 
 }  // namespace __asan
diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc
index c30c5db..20e636b 100644
--- a/lib/asan/asan_malloc_linux.cc
+++ b/lib/asan/asan_malloc_linux.cc
@@ -13,15 +13,16 @@
 // We simply define functions like malloc, free, realloc, etc.
 // They will replace the corresponding libc functions automagically.
 //===----------------------------------------------------------------------===//
-#ifdef __linux__
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "asan_allocator.h"
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_stack.h"
-#include "asan_thread_registry.h"
 
-#if ASAN_ANDROID
+#if SANITIZER_ANDROID
 DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
 DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
 DECLARE_REAL_AND_INTERCEPTOR(void*, calloc, uptr nmemb, uptr size)
@@ -146,4 +147,4 @@
   __asan_print_accumulated_stats();
 }
 
-#endif  // __linux__
+#endif  // SANITIZER_LINUX
diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index b8ec90e..f9f08f0 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/lib/asan/asan_malloc_mac.cc
@@ -12,12 +12,14 @@
 // Mac-specific malloc interception.
 //===----------------------------------------------------------------------===//
 
-#ifdef __APPLE__
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
 
 #include <AvailabilityMacros.h>
 #include <CoreFoundation/CFBase.h>
 #include <dlfcn.h>
 #include <malloc/malloc.h>
+#include <sys/mman.h>
 
 #include "asan_allocator.h"
 #include "asan_interceptors.h"
@@ -26,7 +28,6 @@
 #include "asan_report.h"
 #include "asan_stack.h"
 #include "asan_stats.h"
-#include "asan_thread_registry.h"
 
 // Similar code is used in Google Perftools,
 // http://code.google.com/p/google-perftools.
@@ -42,10 +43,19 @@
                              vm_size_t start_size, unsigned zone_flags) {
   if (!asan_inited) __asan_init();
   GET_STACK_TRACE_MALLOC;
+  uptr page_size = GetPageSizeCached();
+  uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size);
   malloc_zone_t *new_zone =
-      (malloc_zone_t*)asan_malloc(sizeof(asan_zone), &stack);
+      (malloc_zone_t*)asan_memalign(page_size, allocated_size,
+                                    &stack, FROM_MALLOC);
   internal_memcpy(new_zone, &asan_zone, sizeof(asan_zone));
   new_zone->zone_name = NULL;  // The name will be changed anyway.
+  if (GetMacosVersion() >= MACOS_VERSION_LION) {
+    // Prevent the client app from overwriting the zone contents.
+    // Library functions that need to modify the zone will set PROT_WRITE on it.
+    // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
+    mprotect(new_zone, allocated_size, PROT_READ);
+  }
   return new_zone;
 }
 
@@ -284,7 +294,7 @@
 
 void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
   AsanMallocStats malloc_stats;
-  asanThreadRegistry().FillMallocStatistics(&malloc_stats);
+  FillMallocStatistics(&malloc_stats);
   CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats));
   internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
 }
@@ -346,4 +356,4 @@
 }
 }  // namespace __asan
 
-#endif  // __APPLE__
+#endif  // SANITIZER_MAC
diff --git a/lib/asan/asan_malloc_win.cc b/lib/asan/asan_malloc_win.cc
index 9fcfea5..31fb777 100644
--- a/lib/asan/asan_malloc_win.cc
+++ b/lib/asan/asan_malloc_win.cc
@@ -11,7 +11,9 @@
 //
 // Windows-specific malloc interception.
 //===----------------------------------------------------------------------===//
-#ifdef _WIN32
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS
 
 #include "asan_allocator.h"
 #include "asan_interceptors.h"
diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h
index 161ab65..acbed46 100644
--- a/lib/asan/asan_mapping.h
+++ b/lib/asan/asan_mapping.h
@@ -49,6 +49,13 @@
 // || `[0x24000000, 0x27ffffff]` || ShadowGap  ||
 // || `[0x20000000, 0x23ffffff]` || LowShadow  ||
 // || `[0x00000000, 0x1fffffff]` || LowMem     ||
+//
+// Default Linux/MIPS mapping:
+// || `[0x2aaa8000, 0xffffffff]` || HighMem    ||
+// || `[0x0fffd000, 0x2aaa7fff]` || HighShadow ||
+// || `[0x0bffd000, 0x0fffcfff]` || ShadowGap  ||
+// || `[0x0aaa8000, 0x0bffcfff]` || LowShadow  ||
+// || `[0x00000000, 0x0aaa7fff]` || LowMem     ||
 
 #if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
 extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale;
@@ -56,18 +63,22 @@
 # define SHADOW_SCALE (__asan_mapping_scale)
 # define SHADOW_OFFSET (__asan_mapping_offset)
 #else
-# if ASAN_ANDROID
+# if SANITIZER_ANDROID
 #  define SHADOW_SCALE (3)
 #  define SHADOW_OFFSET (0)
 # else
 #  define SHADOW_SCALE (3)
 #  if SANITIZER_WORDSIZE == 32
-#   define SHADOW_OFFSET (1 << 29)
+#   if defined(__mips__)
+#     define SHADOW_OFFSET 0x0aaa8000
+#   else
+#     define SHADOW_OFFSET (1 << 29)
+#   endif
 #  else
 #   if defined(__powerpc64__)
 #    define SHADOW_OFFSET (1ULL << 41)
 #   else
-#    if ASAN_MAC
+#    if SANITIZER_MAC
 #     define SHADOW_OFFSET (1ULL << 44)
 #    else
 #     define SHADOW_OFFSET 0x7fff8000ULL
diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc
index 40aa31c..d5eb6ec 100644
--- a/lib/asan/asan_new_delete.cc
+++ b/lib/asan/asan_new_delete.cc
@@ -29,7 +29,7 @@
 
 // On Android new() goes through malloc interceptors.
 // See also https://code.google.com/p/address-sanitizer/issues/detail?id=131.
-#if !ASAN_ANDROID
+#if !SANITIZER_ANDROID
 
 // Fake std::nothrow_t to avoid including <new>.
 namespace std {
@@ -47,7 +47,7 @@
 // delete.
 // To make sure that C++ allocation/deallocation operators are overridden on
 // OS X we need to intercept them using their mangled names.
-#if !defined(__APPLE__)
+#if !SANITIZER_MAC
 INTERCEPTOR_ATTRIBUTE
 void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
 INTERCEPTOR_ATTRIBUTE
@@ -59,7 +59,7 @@
 void *operator new[](size_t size, std::nothrow_t const&)
 { OPERATOR_NEW_BODY(FROM_NEW_BR); }
 
-#else  // __APPLE__
+#else  // SANITIZER_MAC
 INTERCEPTOR(void *, _Znwm, size_t size) {
   OPERATOR_NEW_BODY(FROM_NEW);
 }
@@ -78,7 +78,7 @@
   GET_STACK_TRACE_FREE;\
   asan_free(ptr, &stack, type);
 
-#if !defined(__APPLE__)
+#if !SANITIZER_MAC
 INTERCEPTOR_ATTRIBUTE
 void operator delete(void *ptr) { OPERATOR_DELETE_BODY(FROM_NEW); }
 INTERCEPTOR_ATTRIBUTE
@@ -90,7 +90,7 @@
 void operator delete[](void *ptr, std::nothrow_t const&)
 { OPERATOR_DELETE_BODY(FROM_NEW_BR); }
 
-#else  // __APPLE__
+#else  // SANITIZER_MAC
 INTERCEPTOR(void, _ZdlPv, void *ptr) {
   OPERATOR_DELETE_BODY(FROM_NEW);
 }
diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc
index b8b3aec..5930953 100644
--- a/lib/asan/asan_poisoning.cc
+++ b/lib/asan/asan_poisoning.cc
@@ -12,9 +12,7 @@
 // Shadow memory poisoning by ASan RTL and by user application.
 //===----------------------------------------------------------------------===//
 
-#include "asan_interceptors.h"
-#include "asan_internal.h"
-#include "asan_mapping.h"
+#include "asan_poisoning.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
 namespace __asan {
@@ -22,11 +20,11 @@
 void PoisonShadow(uptr addr, uptr size, u8 value) {
   if (!flags()->poison_heap) return;
   CHECK(AddrIsAlignedByGranularity(addr));
+  CHECK(AddrIsInMem(addr));
   CHECK(AddrIsAlignedByGranularity(addr + size));
-  uptr shadow_beg = MemToShadow(addr);
-  uptr shadow_end = MemToShadow(addr + size - SHADOW_GRANULARITY) + 1;
-  CHECK(REAL(memset) != 0);
-  REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+  CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY));
+  CHECK(REAL(memset));
+  FastPoisonShadow(addr, size, value);
 }
 
 void PoisonShadowPartialRightRedzone(uptr addr,
@@ -35,20 +33,10 @@
                                      u8 value) {
   if (!flags()->poison_heap) return;
   CHECK(AddrIsAlignedByGranularity(addr));
-  u8 *shadow = (u8*)MemToShadow(addr);
-  for (uptr i = 0; i < redzone_size;
-       i += SHADOW_GRANULARITY, shadow++) {
-    if (i + SHADOW_GRANULARITY <= size) {
-      *shadow = 0;  // fully addressable
-    } else if (i >= size) {
-      *shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value;  // unaddressable
-    } else {
-      *shadow = size - i;  // first size-i bytes are addressable
-    }
-  }
+  CHECK(AddrIsInMem(addr));
+  FastPoisonShadowPartialRightRedzone(addr, size, redzone_size, value);
 }
 
-
 struct ShadowSegmentEndpoint {
   u8 *chunk;
   s8 offset;  // in [0, SHADOW_GRANULARITY)
@@ -181,6 +169,55 @@
   return 0;
 }
 
+#define CHECK_SMALL_REGION(p, size, isWrite)                  \
+  do {                                                        \
+    uptr __p = reinterpret_cast<uptr>(p);                     \
+    uptr __size = size;                                       \
+    if (UNLIKELY(__asan::AddressIsPoisoned(__p) ||            \
+        __asan::AddressIsPoisoned(__p + __size - 1))) {       \
+      GET_CURRENT_PC_BP_SP;                                   \
+      uptr __bad = __asan_region_is_poisoned(__p, __size);    \
+      __asan_report_error(pc, bp, sp, __bad, isWrite, __size);\
+    }                                                         \
+  } while (false);                                            \
+
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+u16 __sanitizer_unaligned_load16(const uu16 *p) {
+  CHECK_SMALL_REGION(p, sizeof(*p), false);
+  return *p;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+u32 __sanitizer_unaligned_load32(const uu32 *p) {
+  CHECK_SMALL_REGION(p, sizeof(*p), false);
+  return *p;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+u64 __sanitizer_unaligned_load64(const uu64 *p) {
+  CHECK_SMALL_REGION(p, sizeof(*p), false);
+  return *p;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
+  CHECK_SMALL_REGION(p, sizeof(*p), true);
+  *p = x;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
+  CHECK_SMALL_REGION(p, sizeof(*p), true);
+  *p = x;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
+  CHECK_SMALL_REGION(p, sizeof(*p), true);
+  *p = x;
+}
+
 // This is a simplified version of __asan_(un)poison_memory_region, which
 // assumes that left border of region to be poisoned is properly aligned.
 static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
diff --git a/lib/asan/asan_poisoning.h b/lib/asan/asan_poisoning.h
new file mode 100644
index 0000000..bb886dd
--- /dev/null
+++ b/lib/asan/asan_poisoning.h
@@ -0,0 +1,59 @@
+//===-- asan_poisoning.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.
+//
+// Shadow memory poisoning by ASan RTL and by user application.
+//===----------------------------------------------------------------------===//
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+
+namespace __asan {
+
+// Poisons the shadow memory for "size" bytes starting from "addr".
+void PoisonShadow(uptr addr, uptr size, u8 value);
+
+// Poisons the shadow memory for "redzone_size" bytes starting from
+// "addr + size".
+void PoisonShadowPartialRightRedzone(uptr addr,
+                                     uptr size,
+                                     uptr redzone_size,
+                                     u8 value);
+
+// Fast versions of PoisonShadow and PoisonShadowPartialRightRedzone that
+// assume that memory addresses are properly aligned. Use in
+// performance-critical code with care.
+ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
+                                    u8 value) {
+  DCHECK(flags()->poison_heap);
+  uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
+  uptr shadow_end = MEM_TO_SHADOW(
+      aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1;
+  REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+}
+
+ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
+    uptr aligned_addr, uptr size, uptr redzone_size, u8 value) {
+  DCHECK(flags()->poison_heap);
+  u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr);
+  for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) {
+    if (i + SHADOW_GRANULARITY <= size) {
+      *shadow = 0;  // fully addressable
+    } else if (i >= size) {
+      *shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value;  // unaddressable
+    } else {
+      // first size-i bytes are addressable
+      *shadow = static_cast<u8>(size - i);
+    }
+  }
+}
+
+}  // namespace __asan
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index ceaf120..5126a75 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -11,14 +11,15 @@
 //
 // Posix-specific details.
 //===----------------------------------------------------------------------===//
-#if defined(__linux__) || defined(__APPLE__)
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX || SANITIZER_MAC
 
 #include "asan_internal.h"
 #include "asan_interceptors.h"
 #include "asan_mapping.h"
 #include "asan_report.h"
 #include "asan_stack.h"
-#include "asan_thread_registry.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
 
@@ -42,7 +43,7 @@
   sigact.sa_sigaction = handler;
   sigact.sa_flags = SA_SIGINFO;
   if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
-  CHECK(0 == REAL(sigaction)(signum, &sigact, 0));
+  CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0));
   if (flags()->verbosity >= 1) {
     Report("Installed the sigaction for signal %d\n", signum);
   }
@@ -59,7 +60,7 @@
 
 void SetAlternateSignalStack() {
   stack_t altstack, oldstack;
-  CHECK(0 == sigaltstack(0, &oldstack));
+  CHECK_EQ(0, sigaltstack(0, &oldstack));
   // If the alternate stack is already in place, do nothing.
   if ((oldstack.ss_flags & SS_DISABLE) == 0) return;
   // TODO(glider): the mapped stack should have the MAP_STACK flag in the
@@ -69,10 +70,10 @@
   altstack.ss_sp = base;
   altstack.ss_flags = 0;
   altstack.ss_size = kAltStackSize;
-  CHECK(0 == sigaltstack(&altstack, 0));
+  CHECK_EQ(0, sigaltstack(&altstack, 0));
   if (flags()->verbosity > 0) {
     Report("Alternative stack for T%d set: [%p,%p)\n",
-           asanThreadRegistry().GetCurrentTidOrInvalid(),
+           GetCurrentTidOrInvalid(),
            altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
   }
 }
@@ -82,7 +83,7 @@
   altstack.ss_sp = 0;
   altstack.ss_flags = SS_DISABLE;
   altstack.ss_size = 0;
-  CHECK(0 == sigaltstack(&altstack, &oldstack));
+  CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
   UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
 }
 
@@ -102,7 +103,7 @@
 void AsanTSDInit(void (*destructor)(void *tsd)) {
   CHECK(!tsd_key_inited);
   tsd_key_inited = true;
-  CHECK(0 == pthread_key_create(&tsd_key, destructor));
+  CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
 }
 
 void *AsanTSDGet() {
@@ -117,4 +118,4 @@
 
 }  // namespace __asan
 
-#endif  // __linux__ || __APPLE_
+#endif  // SANITIZER_LINUX || SANITIZER_MAC
diff --git a/lib/asan/asan_preinit.cc b/lib/asan/asan_preinit.cc
index 07e0a53..586f551 100644
--- a/lib/asan/asan_preinit.cc
+++ b/lib/asan/asan_preinit.cc
@@ -18,9 +18,11 @@
   // On Linux, we force __asan_init to be called before anyone else
   // by placing it into .preinit_array section.
   // FIXME: do we have anything like this on Mac?
+  // The symbol is called __local_asan_preinit, because it's not intended to be
+  // exported.
   __attribute__((section(".preinit_array"), used))
-  void (*__asan_preinit)(void) =__asan_init;
-#elif defined(_WIN32) && defined(_DLL)
+  void (*__local_asan_preinit)(void) = __asan_init;
+#elif SANITIZER_WINDOWS && defined(_DLL)
   // On Windows, when using dynamic CRT (/MD), we can put a pointer
   // to __asan_init into the global list of C initializers.
   // See crt0dat.c in the CRT sources for the details.
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index 6359b26..9c46b49 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -17,8 +17,8 @@
 #include "asan_report.h"
 #include "asan_stack.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
 
@@ -125,12 +125,12 @@
          "application bytes):\n", (int)SHADOW_GRANULARITY);
   PrintShadowByte("  Addressable:           ", 0);
   Printf("  Partially addressable: ");
-  for (uptr i = 1; i < SHADOW_GRANULARITY; i++)
+  for (u8 i = 1; i < SHADOW_GRANULARITY; i++)
     PrintShadowByte("", i, " ");
   Printf("\n");
   PrintShadowByte("  Heap left redzone:     ", kAsanHeapLeftRedzoneMagic);
-  PrintShadowByte("  Heap righ redzone:     ", kAsanHeapRightRedzoneMagic);
-  PrintShadowByte("  Freed Heap region:     ", kAsanHeapFreeMagic);
+  PrintShadowByte("  Heap right redzone:    ", kAsanHeapRightRedzoneMagic);
+  PrintShadowByte("  Freed heap region:     ", kAsanHeapFreeMagic);
   PrintShadowByte("  Stack left redzone:    ", kAsanStackLeftRedzoneMagic);
   PrintShadowByte("  Stack mid redzone:     ", kAsanStackMidRedzoneMagic);
   PrintShadowByte("  Stack right redzone:   ", kAsanStackRightRedzoneMagic);
@@ -181,13 +181,21 @@
   return /*0x00 <= c &&*/ c <= 0x7F;
 }
 
+static const char *MaybeDemangleGlobalName(const char *name) {
+  // We can spoil names of globals with C linkage, so use an heuristic
+  // approach to check if the name should be demangled.
+  return (name[0] == '_' && name[1] == 'Z') ? Demangle(name) : name;
+}
+
 // Check if the global is a zero-terminated ASCII string. If so, print it.
 static void PrintGlobalNameIfASCII(const __asan_global &g) {
   for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
-    if (!IsASCII(*(unsigned char*)p)) return;
+    unsigned char c = *(unsigned char*)p;
+    if (c == '\0' || !IsASCII(c)) return;
   }
-  if (*(char*)(g.beg + g.size - 1) != 0) return;
-  Printf("  '%s' is ascii string '%s'\n", g.name, (char*)g.beg);
+  if (*(char*)(g.beg + g.size - 1) != '\0') return;
+  Printf("  '%s' is ascii string '%s'\n",
+         MaybeDemangleGlobalName(g.name), (char*)g.beg);
 }
 
 bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
@@ -209,7 +217,7 @@
     Printf("%p is located %zd bytes inside", (void*)addr, addr - g.beg);
   }
   Printf(" of global variable '%s' from '%s' (0x%zx) of size %zu\n",
-             g.name, g.module_name, g.beg, g.size);
+             MaybeDemangleGlobalName(g.name), g.module_name, g.beg, g.size);
   Printf("%s", d.EndLocation());
   PrintGlobalNameIfASCII(g);
   return true;
@@ -236,39 +244,75 @@
   return false;
 }
 
+// Return " (thread_name) " or an empty string if the name is empty.
+const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[],
+                                      uptr buff_len) {
+  const char *name = t->name;
+  if (name[0] == '\0') return "";
+  buff[0] = 0;
+  internal_strncat(buff, " (", 3);
+  internal_strncat(buff, name, buff_len - 4);
+  internal_strncat(buff, ")", 2);
+  return buff;
+}
+
+const char *ThreadNameWithParenthesis(u32 tid, char buff[],
+                                      uptr buff_len) {
+  if (tid == kInvalidTid) return "";
+  asanThreadRegistry().CheckLocked();
+  AsanThreadContext *t = GetThreadContextByTidLocked(tid);
+  return ThreadNameWithParenthesis(t, buff, buff_len);
+}
+
 bool DescribeAddressIfStack(uptr addr, uptr access_size) {
-  AsanThread *t = asanThreadRegistry().FindThreadByStackAddress(addr);
+  AsanThread *t = FindThreadByStackAddress(addr);
   if (!t) return false;
-  const sptr kBufSize = 4095;
+  const s64 kBufSize = 4095;
   char buf[kBufSize];
   uptr offset = 0;
-  const char *frame_descr = t->GetFrameNameByAddr(addr, &offset);
+  uptr frame_pc = 0;
+  char tname[128];
+  const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc);
+
+#ifdef __powerpc64__
+  // On PowerPC64, the address of a function actually points to a
+  // three-doubleword data structure with the first field containing
+  // the address of the function's code.
+  frame_pc = *reinterpret_cast<uptr *>(frame_pc);
+#endif
+
   // This string is created by the compiler and has the following form:
-  // "FunctioName n alloc_1 alloc_2 ... alloc_n"
+  // "n alloc_1 alloc_2 ... alloc_n"
   // where alloc_i looks like "offset size len ObjectName ".
   CHECK(frame_descr);
-  // Report the function name and the offset.
-  const char *name_end = internal_strchr(frame_descr, ' ');
-  CHECK(name_end);
-  buf[0] = 0;
-  internal_strncat(buf, frame_descr,
-                   Min(kBufSize,
-                       static_cast<sptr>(name_end - frame_descr)));
   Decorator d;
   Printf("%s", d.Location());
-  Printf("Address %p is located at offset %zu "
-             "in frame <%s> of T%d's stack:\n",
-             (void*)addr, offset, Demangle(buf), t->tid());
+  Printf("Address %p is located in stack of thread T%d%s "
+         "at offset %zu in frame\n",
+         addr, t->tid(),
+         ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)),
+         offset);
+  // Now we print the frame where the alloca has happened.
+  // We print this frame as a stack trace with one element.
+  // The symbolizer may print more than one frame if inlining was involved.
+  // The frame numbers may be different than those in the stack trace printed
+  // previously. That's unfortunate, but I have no better solution,
+  // especially given that the alloca may be from entirely different place
+  // (e.g. use-after-scope, or different thread's stack).
+  StackTrace alloca_stack;
+  alloca_stack.trace[0] = frame_pc + 16;
+  alloca_stack.size = 1;
   Printf("%s", d.EndLocation());
+  PrintStack(&alloca_stack);
   // Report the number of stack objects.
   char *p;
-  uptr n_objects = internal_simple_strtoll(name_end, &p, 10);
-  CHECK(n_objects > 0);
+  s64 n_objects = internal_simple_strtoll(frame_descr, &p, 10);
+  CHECK_GT(n_objects, 0);
   Printf("  This frame has %zu object(s):\n", n_objects);
   // Report all objects in this frame.
-  for (uptr i = 0; i < n_objects; i++) {
-    uptr beg, size;
-    sptr len;
+  for (s64 i = 0; i < n_objects; i++) {
+    s64 beg, size;
+    s64 len;
     beg  = internal_simple_strtoll(p, &p, 10);
     size = internal_simple_strtoll(p, &p, 10);
     len  = internal_simple_strtoll(p, &p, 10);
@@ -279,14 +323,14 @@
     }
     p++;
     buf[0] = 0;
-    internal_strncat(buf, p, Min(kBufSize, len));
+    internal_strncat(buf, p, static_cast<uptr>(Min(kBufSize, len)));
     p += len;
-    Printf("    [%zu, %zu) '%s'\n", beg, beg + size, buf);
+    Printf("    [%lld, %lld) '%s'\n", beg, beg + size, buf);
   }
   Printf("HINT: this may be a false positive if your program uses "
              "some custom stack unwind mechanism or swapcontext\n"
              "      (longjmp and C++ exceptions *are* supported)\n");
-  DescribeThread(t->summary());
+  DescribeThread(t->context());
   return true;
 }
 
@@ -314,63 +358,45 @@
   Printf("%s", d.EndLocation());
 }
 
-// Return " (thread_name) " or an empty string if the name is empty.
-const char *ThreadNameWithParenthesis(AsanThreadSummary *t, char buff[],
-                                      uptr buff_len) {
-  const char *name = t->name();
-  if (*name == 0) return "";
-  buff[0] = 0;
-  internal_strncat(buff, " (", 3);
-  internal_strncat(buff, name, buff_len - 4);
-  internal_strncat(buff, ")", 2);
-  return buff;
-}
-
-const char *ThreadNameWithParenthesis(u32 tid, char buff[],
-                                      uptr buff_len) {
-  if (tid == kInvalidTid) return "";
-  AsanThreadSummary *t = asanThreadRegistry().FindByTid(tid);
-  return ThreadNameWithParenthesis(t, buff, buff_len);
-}
-
 void DescribeHeapAddress(uptr addr, uptr access_size) {
   AsanChunkView chunk = FindHeapChunkByAddress(addr);
   if (!chunk.IsValid()) return;
   DescribeAccessToHeapChunk(chunk, addr, access_size);
   CHECK(chunk.AllocTid() != kInvalidTid);
-  AsanThreadSummary *alloc_thread =
-      asanThreadRegistry().FindByTid(chunk.AllocTid());
+  asanThreadRegistry().CheckLocked();
+  AsanThreadContext *alloc_thread =
+      GetThreadContextByTidLocked(chunk.AllocTid());
   StackTrace alloc_stack;
   chunk.GetAllocStack(&alloc_stack);
-  AsanThread *t = asanThreadRegistry().GetCurrent();
+  AsanThread *t = GetCurrentThread();
   CHECK(t);
   char tname[128];
   Decorator d;
   if (chunk.FreeTid() != kInvalidTid) {
-    AsanThreadSummary *free_thread =
-        asanThreadRegistry().FindByTid(chunk.FreeTid());
+    AsanThreadContext *free_thread =
+        GetThreadContextByTidLocked(chunk.FreeTid());
     Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
-           free_thread->tid(),
+           free_thread->tid,
            ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
            d.EndAllocation());
     StackTrace free_stack;
     chunk.GetFreeStack(&free_stack);
     PrintStack(&free_stack);
     Printf("%spreviously allocated by thread T%d%s here:%s\n",
-           d.Allocation(), alloc_thread->tid(),
+           d.Allocation(), alloc_thread->tid,
            ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
            d.EndAllocation());
     PrintStack(&alloc_stack);
-    DescribeThread(t->summary());
+    DescribeThread(t->context());
     DescribeThread(free_thread);
     DescribeThread(alloc_thread);
   } else {
     Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
-           alloc_thread->tid(),
+           alloc_thread->tid,
            ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
            d.EndAllocation());
     PrintStack(&alloc_stack);
-    DescribeThread(t->summary());
+    DescribeThread(t->context());
     DescribeThread(alloc_thread);
   }
 }
@@ -390,26 +416,27 @@
 
 // ------------------- Thread description -------------------- {{{1
 
-void DescribeThread(AsanThreadSummary *summary) {
-  CHECK(summary);
+void DescribeThread(AsanThreadContext *context) {
+  CHECK(context);
+  asanThreadRegistry().CheckLocked();
   // No need to announce the main thread.
-  if (summary->tid() == 0 || summary->announced()) {
+  if (context->tid == 0 || context->announced) {
     return;
   }
-  summary->set_announced(true);
+  context->announced = true;
   char tname[128];
-  Printf("Thread T%d%s", summary->tid(),
-         ThreadNameWithParenthesis(summary->tid(), tname, sizeof(tname)));
+  Printf("Thread T%d%s", context->tid,
+         ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
   Printf(" created by T%d%s here:\n",
-         summary->parent_tid(),
-         ThreadNameWithParenthesis(summary->parent_tid(),
+         context->parent_tid,
+         ThreadNameWithParenthesis(context->parent_tid,
                                    tname, sizeof(tname)));
-  PrintStack(summary->stack());
+  PrintStack(&context->stack);
   // Recursively described parent thread if needed.
   if (flags()->print_full_thread_history) {
-    AsanThreadSummary *parent_summary =
-        asanThreadRegistry().FindByTid(summary->parent_tid());
-    DescribeThread(parent_summary);
+    AsanThreadContext *parent_context =
+        GetThreadContextByTidLocked(context->parent_tid);
+    DescribeThread(parent_context);
   }
 }
 
@@ -428,7 +455,7 @@
       // they are defined as no-return.
       Report("AddressSanitizer: while reporting a bug found another one."
                  "Ignoring.\n");
-      u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
+      u32 current_tid = GetCurrentTidOrInvalid();
       if (current_tid != reporting_thread_tid) {
         // ASan found two bugs in different threads simultaneously. Sleep
         // long enough to make sure that the thread which started to print
@@ -440,23 +467,30 @@
       internal__exit(flags()->exitcode);
     }
     ASAN_ON_ERROR();
-    reporting_thread_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
+    // Make sure the registry and sanitizer report mutexes are locked while
+    // we're printing an error report.
+    // We can lock them only here to avoid self-deadlock in case of
+    // recursive reports.
+    asanThreadRegistry().Lock();
+    CommonSanitizerReportMutex.Lock();
+    reporting_thread_tid = GetCurrentTidOrInvalid();
     Printf("===================================================="
            "=============\n");
     if (reporting_thread_tid != kInvalidTid) {
       // We started reporting an error message. Stop using the fake stack
       // in case we call an instrumented function from a symbolizer.
-      AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
+      AsanThread *curr_thread = GetCurrentThread();
       CHECK(curr_thread);
-      curr_thread->fake_stack().StopUsingFakeStack();
+      if (curr_thread->fake_stack())
+        curr_thread->fake_stack()->StopUsingFakeStack();
     }
   }
   // Destructor is NORETURN, as functions that report errors are.
   NORETURN ~ScopedInErrorReport() {
     // Make sure the current thread is announced.
-    AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
+    AsanThread *curr_thread = GetCurrentThread();
     if (curr_thread) {
-      DescribeThread(curr_thread->summary());
+      DescribeThread(curr_thread->context());
     }
     // Print memory stats.
     if (flags()->print_stats)
@@ -475,9 +509,11 @@
     AddressInfo ai;
     // Currently, we include the first stack frame into the report summary.
     // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
-    SymbolizeCode(stack->trace[0], &ai, 1);
+    uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
+    SymbolizeCode(pc, &ai, 1);
     ReportErrorSummary(error_type,
-                       StripPathPrefix(ai.file, flags()->strip_path_prefix),
+                       StripPathPrefix(ai.file,
+                                       common_flags()->strip_path_prefix),
                        ai.line, ai.function);
   }
   // FIXME: do we need to print anything at all if there is no symbolizer?
@@ -490,7 +526,7 @@
   Report("ERROR: AddressSanitizer: SEGV on unknown address %p"
              " (pc %p sp %p bp %p T%d)\n",
              (void*)addr, (void*)pc, (void*)sp, (void*)bp,
-             asanThreadRegistry().GetCurrentTidOrInvalid());
+             GetCurrentTidOrInvalid());
   Printf("%s", d.EndWarning());
   Printf("AddressSanitizer can not provide additional info.\n");
   GET_STACK_TRACE_FATAL(pc, bp);
@@ -502,7 +538,13 @@
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
-  Report("ERROR: AddressSanitizer: attempting double-free on %p:\n", addr);
+  char tname[128];
+  u32 curr_tid = GetCurrentTidOrInvalid();
+  Report("ERROR: AddressSanitizer: attempting double-free on %p in "
+         "thread T%d%s:\n",
+         addr, curr_tid,
+         ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
+
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
@@ -513,8 +555,11 @@
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
+  char tname[128];
+  u32 curr_tid = GetCurrentTidOrInvalid();
   Report("ERROR: AddressSanitizer: attempting free on address "
-             "which was not malloc()-ed: %p\n", addr);
+             "which was not malloc()-ed: %p in thread T%d%s\n", addr,
+         curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
@@ -680,7 +725,7 @@
              bug_descr, (void*)addr, pc, bp, sp);
   Printf("%s", d.EndWarning());
 
-  u32 curr_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
+  u32 curr_tid = GetCurrentTidOrInvalid();
   char tname[128];
   Printf("%s%s of size %zu at %p thread T%d%s%s\n",
          d.Access(),
diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h
index 55a8039..db271fc 100644
--- a/lib/asan/asan_report.h
+++ b/lib/asan/asan_report.h
@@ -29,7 +29,7 @@
 // Determines memory type on its own.
 void DescribeAddress(uptr addr, uptr access_size);
 
-void DescribeThread(AsanThreadSummary *summary);
+void DescribeThread(AsanThreadContext *context);
 
 // Different kinds of error reports.
 void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 2902339..1459374 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -15,15 +15,16 @@
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_mapping.h"
+#include "asan_poisoning.h"
 #include "asan_report.h"
 #include "asan_stack.h"
 #include "asan_stats.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
+#include "lsan/lsan_common.h"
 
 namespace __asan {
 
@@ -64,13 +65,9 @@
 }
 
 // -------------------------- Flags ------------------------- {{{1
-static const int kDeafultMallocContextSize = 30;
+static const int kDefaultMallocContextSize = 30;
 
-static Flags asan_flags;
-
-Flags *flags() {
-  return &asan_flags;
-}
+Flags asan_flags_dont_use_directly;  // use via flags().
 
 static const char *MaybeCallAsanDefaultOptions() {
   return (&__asan_default_options) ? __asan_default_options() : "";
@@ -88,28 +85,30 @@
 }
 
 static void ParseFlagsFromString(Flags *f, const char *str) {
+  ParseCommonFlagsFromString(str);
+  CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax);
+
   ParseFlag(str, &f->quarantine_size, "quarantine_size");
-  ParseFlag(str, &f->symbolize, "symbolize");
   ParseFlag(str, &f->verbosity, "verbosity");
   ParseFlag(str, &f->redzone, "redzone");
-  CHECK(f->redzone >= 16);
+  CHECK_GE(f->redzone, 16);
   CHECK(IsPowerOfTwo(f->redzone));
 
   ParseFlag(str, &f->debug, "debug");
   ParseFlag(str, &f->report_globals, "report_globals");
-  ParseFlag(str, &f->check_initialization_order, "initialization_order");
-  ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
-  CHECK((uptr)f->malloc_context_size <= kStackTraceMax);
+  ParseFlag(str, &f->check_initialization_order, "check_initialization_order");
 
   ParseFlag(str, &f->replace_str, "replace_str");
   ParseFlag(str, &f->replace_intrin, "replace_intrin");
   ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free");
   ParseFlag(str, &f->use_fake_stack, "use_fake_stack");
   ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size");
+  ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte");
   ParseFlag(str, &f->exitcode, "exitcode");
   ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning");
   ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying");
   ParseFlag(str, &f->handle_segv, "handle_segv");
+  ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler");
   ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack");
   ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size");
   ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit");
@@ -118,40 +117,46 @@
   ParseFlag(str, &f->print_legend, "print_legend");
   ParseFlag(str, &f->atexit, "atexit");
   ParseFlag(str, &f->disable_core, "disable_core");
-  ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
   ParseFlag(str, &f->allow_reexec, "allow_reexec");
   ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
-  ParseFlag(str, &f->log_path, "log_path");
-  ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal");
-  ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc");
   ParseFlag(str, &f->poison_heap, "poison_heap");
   ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch");
   ParseFlag(str, &f->use_stack_depot, "use_stack_depot");
   ParseFlag(str, &f->strict_memcmp, "strict_memcmp");
+  ParseFlag(str, &f->strict_init_order, "strict_init_order");
 }
 
-static const char *asan_external_symbolizer;
-
 void InitializeFlags(Flags *f, const char *env) {
-  internal_memset(f, 0, sizeof(*f));
+  CommonFlags *cf = common_flags();
+  cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
+  cf->symbolize = true;
+  cf->malloc_context_size = kDefaultMallocContextSize;
+  cf->fast_unwind_on_fatal = false;
+  cf->fast_unwind_on_malloc = true;
+  cf->strip_path_prefix = "";
+  cf->handle_ioctl = false;
+  cf->log_path = 0;
+  cf->detect_leaks = false;
+  cf->leak_check_at_exit = true;
 
+  internal_memset(f, 0, sizeof(*f));
   f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;
-  f->symbolize = (asan_external_symbolizer != 0);
   f->verbosity = 0;
-  f->redzone = ASAN_ALLOCATOR_VERSION == 2 ? 16 : (ASAN_LOW_MEMORY) ? 64 : 128;
+  f->redzone = 16;
   f->debug = false;
   f->report_globals = 1;
   f->check_initialization_order = false;
-  f->malloc_context_size = kDeafultMallocContextSize;
   f->replace_str = true;
   f->replace_intrin = true;
   f->mac_ignore_invalid_free = false;
   f->use_fake_stack = true;
-  f->max_malloc_fill_size = 0;
+  f->max_malloc_fill_size = 0x1000;  // By default, fill only the first 4K.
+  f->malloc_fill_byte = 0xbe;
   f->exitcode = ASAN_DEFAULT_FAILURE_EXITCODE;
   f->allow_user_poisoning = true;
   f->sleep_before_dying = 0;
   f->handle_segv = ASAN_NEEDS_SEGV;
+  f->allow_user_segv_handler = false;
   f->use_sigaltstack = false;
   f->check_malloc_usable_size = true;
   f->unmap_shadow_on_exit = false;
@@ -160,18 +165,15 @@
   f->print_legend = true;
   f->atexit = false;
   f->disable_core = (SANITIZER_WORDSIZE == 64);
-  f->strip_path_prefix = "";
   f->allow_reexec = true;
   f->print_full_thread_history = true;
-  f->log_path = 0;
-  f->fast_unwind_on_fatal = false;
-  f->fast_unwind_on_malloc = true;
   f->poison_heap = true;
   // Turn off alloc/dealloc mismatch checker on Mac for now.
   // TODO(glider): Fix known issues and enable this back.
-  f->alloc_dealloc_mismatch = (ASAN_MAC == 0);;
-  f->use_stack_depot = true;  // Only affects allocator2.
+  f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0);;
+  f->use_stack_depot = true;
   f->strict_memcmp = true;
+  f->strict_init_order = false;
 
   // Override from compile definition.
   ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton());
@@ -185,6 +187,20 @@
 
   // Override from command line.
   ParseFlagsFromString(f, env);
+
+#if !CAN_SANITIZE_LEAKS
+  if (cf->detect_leaks) {
+    Report("%s: detect_leaks is not supported on this platform.\n",
+           SanitizerToolName);
+    cf->detect_leaks = false;
+  }
+#endif
+
+  if (cf->detect_leaks && !f->use_stack_depot) {
+    Report("%s: detect_leaks is ignored (requires use_stack_depot).\n",
+           SanitizerToolName);
+    cf->detect_leaks = false;
+  }
 }
 
 // -------------------------- Globals --------------------- {{{1
@@ -205,8 +221,8 @@
 // ---------------------- mmap -------------------- {{{1
 // Reserve memory range [beg, end].
 static void ReserveShadowMemoryRange(uptr beg, uptr end) {
-  CHECK((beg % GetPageSizeCached()) == 0);
-  CHECK(((end + 1) % GetPageSizeCached()) == 0);
+  CHECK_EQ((beg % GetPageSizeCached()), 0);
+  CHECK_EQ(((end + 1) % GetPageSizeCached()), 0);
   uptr size = end - beg + 1;
   void *res = MmapFixedNoReserve(beg, size);
   if (res != (void*)beg) {
@@ -291,7 +307,7 @@
     case 27: __asan_set_error_exit_code(0); break;
     case 28: __asan_stack_free(0, 0, 0); break;
     case 29: __asan_stack_malloc(0, 0); break;
-    case 30: __asan_before_dynamic_init(0, 0); break;
+    case 30: __asan_before_dynamic_init(0); break;
     case 31: __asan_after_dynamic_init(); break;
     case 32: __asan_poison_stack_memory(0, 0); break;
     case 33: __asan_unpoison_stack_memory(0, 0); break;
@@ -312,22 +328,12 @@
 
 static void InitializeHighMemEnd() {
 #if !ASAN_FIXED_MAPPING
-#if SANITIZER_WORDSIZE == 64
-# if defined(__powerpc64__)
-  // FIXME:
-  // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
-  // We somehow need to figure our which one we are using now and choose
-  // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
-  // Note that with 'ulimit -s unlimited' the stack is moved away from the top
-  // of the address space, so simply checking the stack address is not enough.
-  kHighMemEnd = (1ULL << 44) - 1;  // 0x00000fffffffffffUL
-# else
-  kHighMemEnd = (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
-# endif
-#else  // SANITIZER_WORDSIZE == 32
-  kHighMemEnd = (1ULL << 32) - 1;  // 0xffffffff;
-#endif  // SANITIZER_WORDSIZE
+  kHighMemEnd = GetMaxVirtualAddress();
+  // Increase kHighMemEnd to make sure it's properly
+  // aligned together with kHighMemBeg:
+  kHighMemEnd |= SHADOW_GRANULARITY * GetPageSizeCached() - 1;
 #endif  // !ASAN_FIXED_MAPPING
+  CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0);
 }
 
 static void ProtectGap(uptr a, uptr size) {
@@ -369,7 +375,8 @@
   }
   Printf("\n");
   Printf("red_zone=%zu\n", (uptr)flags()->redzone);
-  Printf("malloc_context_size=%zu\n", (uptr)flags()->malloc_context_size);
+  Printf("malloc_context_size=%zu\n",
+         (uptr)common_flags()->malloc_context_size);
 
   Printf("SHADOW_SCALE: %zx\n", (uptr)SHADOW_SCALE);
   Printf("SHADOW_GRANULARITY: %zx\n", (uptr)SHADOW_GRANULARITY);
@@ -401,11 +408,25 @@
 
 void NOINLINE __asan_handle_no_return() {
   int local_stack;
-  AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
+  AsanThread *curr_thread = GetCurrentThread();
   CHECK(curr_thread);
   uptr PageSize = GetPageSizeCached();
   uptr top = curr_thread->stack_top();
   uptr bottom = ((uptr)&local_stack - PageSize) & ~(PageSize-1);
+  static const uptr kMaxExpectedCleanupSize = 64 << 20;  // 64M
+  if (top - bottom > kMaxExpectedCleanupSize) {
+    static bool reported_warning = false;
+    if (reported_warning)
+      return;
+    reported_warning = true;
+    Report("WARNING: ASan is ignoring requested __asan_handle_no_return: "
+           "stack top: %p; bottom %p; size: %p (%zd)\n"
+           "False positive error reports may follow\n"
+           "For details see "
+           "http://code.google.com/p/address-sanitizer/issues/detail?id=189\n",
+           top, bottom, top - bottom, top - bottom);
+    return;
+  }
   PoisonShadow(bottom, top - bottom, 0);
 }
 
@@ -428,13 +449,11 @@
   SetCheckFailedCallback(AsanCheckFailed);
   SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
 
-  // Check if external symbolizer is defined before parsing the flags.
-  asan_external_symbolizer = GetEnv("ASAN_SYMBOLIZER_PATH");
   // Initialize flags. This must be done early, because most of the
   // initialization steps look at flags().
   const char *options = GetEnv("ASAN_OPTIONS");
   InitializeFlags(flags(), options);
-  __sanitizer_set_report_path(flags()->log_path);
+  __sanitizer_set_report_path(common_flags()->log_path);
 
   if (flags()->verbosity && options) {
     Report("Parsed ASAN_OPTIONS: %s\n", options);
@@ -457,12 +476,12 @@
   ReplaceOperatorsNewAndDelete();
 
   uptr shadow_start = kLowShadowBeg;
-  if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
-  uptr shadow_end = kHighShadowEnd;
+  if (kLowShadowBeg)
+    shadow_start -= GetMmapGranularity();
   bool full_shadow_is_available =
-      MemoryRangeIsAvailable(shadow_start, shadow_end);
+      MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
 
-#if ASAN_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
+#if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
   if (!full_shadow_is_available) {
     kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
     kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
@@ -486,7 +505,7 @@
     ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
   } else if (kMidMemBeg &&
       MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
-      MemoryRangeIsAvailable(kMidMemEnd + 1, shadow_end)) {
+      MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
     CHECK(kLowShadowBeg != kLowShadowEnd);
     // mmap the low shadow plus at least one page at the left.
     ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
@@ -506,10 +525,17 @@
   }
 
   InstallSignalHandlers();
+
+  AsanTSDInit(AsanThread::TSDDtor);
+  // Allocator should be initialized before starting external symbolizer, as
+  // fork() on Mac locks the allocator.
+  InitializeAllocator();
+
   // Start symbolizer process if necessary.
-  if (flags()->symbolize && asan_external_symbolizer &&
-      asan_external_symbolizer[0]) {
-    InitializeExternalSymbolizer(asan_external_symbolizer);
+  const char* external_symbolizer = common_flags()->external_symbolizer_path;
+  if (common_flags()->symbolize && external_symbolizer &&
+      external_symbolizer[0]) {
+    InitializeExternalSymbolizer(external_symbolizer);
   }
 
   // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
@@ -517,11 +543,24 @@
   asan_inited = 1;
   asan_init_is_running = false;
 
-  asanThreadRegistry().Init();
-  asanThreadRegistry().GetMain()->ThreadStart();
+  InitTlsSize();
+
+  // Create main thread.
+  AsanThread *main_thread = AsanThread::Create(0, 0);
+  CreateThreadContextArgs create_main_args = { main_thread, 0 };
+  u32 main_tid = asanThreadRegistry().CreateThread(
+      0, true, 0, &create_main_args);
+  CHECK_EQ(0, main_tid);
+  SetCurrentThread(main_thread);
+  main_thread->ThreadStart(internal_getpid());
   force_interface_symbols();  // no-op.
 
-  InitializeAllocator();
+#if CAN_SANITIZE_LEAKS
+  __lsan::InitCommonLsan();
+  if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
+    Atexit(__lsan::DoLeakCheck);
+  }
+#endif  // CAN_SANITIZE_LEAKS
 
   if (flags()->verbosity) {
     Report("AddressSanitizer Init done\n");
diff --git a/lib/asan/asan_stack.cc b/lib/asan/asan_stack.cc
index a50ab1d..21dae7d 100644
--- a/lib/asan/asan_stack.cc
+++ b/lib/asan/asan_stack.cc
@@ -14,6 +14,7 @@
 #include "asan_internal.h"
 #include "asan_flags.h"
 #include "asan_stack.h"
+#include "sanitizer_common/sanitizer_flags.h"
 
 namespace __asan {
 
@@ -24,8 +25,8 @@
 }
 
 void PrintStack(StackTrace *stack) {
-  stack->PrintStack(stack->trace, stack->size, flags()->symbolize,
-                    flags()->strip_path_prefix, MaybeCallAsanSymbolize);
+  stack->PrintStack(stack->trace, stack->size, common_flags()->symbolize,
+                    common_flags()->strip_path_prefix, MaybeCallAsanSymbolize);
 }
 
 }  // namespace __asan
@@ -35,7 +36,7 @@
 // Provide default implementation of __asan_symbolize that does nothing
 // and may be overriden by user if he wants to use his own symbolization.
 // ASan on Windows has its own implementation of this.
-#if !defined(_WIN32) && !SANITIZER_SUPPORTS_WEAK_HOOKS
+#if !SANITIZER_WINDOWS && !SANITIZER_SUPPORTS_WEAK_HOOKS
 SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
 bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
   return false;
diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h
index 46c9f34..176aa18 100644
--- a/lib/asan/asan_stack.h
+++ b/lib/asan/asan_stack.h
@@ -14,12 +14,13 @@
 #ifndef ASAN_STACK_H
 #define ASAN_STACK_H
 
-#include "sanitizer_common/sanitizer_stacktrace.h"
 #include "asan_flags.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 
 namespace __asan {
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast);
 void PrintStack(StackTrace *stack);
 
 }  // namespace __asan
@@ -27,10 +28,24 @@
 // Get the stack trace with the given pc and bp.
 // The pc will be in the position 0 of the resulting stack trace.
 // The bp may refer to the current frame or to the caller's frame.
-// fast_unwind is currently unused.
+#if SANITIZER_WINDOWS
 #define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast)     \
   StackTrace stack;                                             \
-  GetStackTrace(&stack, max_s, pc, bp, fast)
+  GetStackTrace(&stack, max_s, pc, bp, 0, 0, fast)
+#else
+#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast)     \
+  StackTrace stack;                                             \
+  {                                                             \
+    uptr stack_top = 0, stack_bottom = 0;                       \
+    AsanThread *t;                                              \
+    if (asan_inited && (t = GetCurrentThread())) {              \
+      stack_top = t->stack_top();                               \
+      stack_bottom = t->stack_bottom();                         \
+    }                                                           \
+    GetStackTrace(&stack, max_s, pc, bp,                        \
+                  stack_top, stack_bottom, fast);               \
+  }
+#endif  // SANITIZER_WINDOWS
 
 // NOTE: A Rule of thumb is to retrieve stack trace in the interceptors
 // as early as possible (in functions exposed to the user), as we generally
@@ -42,24 +57,24 @@
 
 #define GET_STACK_TRACE_FATAL(pc, bp)                                 \
   GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp,              \
-                                 flags()->fast_unwind_on_fatal)
+                                 common_flags()->fast_unwind_on_fatal)
 
-#define GET_STACK_TRACE_FATAL_HERE                           \
-  GET_STACK_TRACE(kStackTraceMax, flags()->fast_unwind_on_fatal)
+#define GET_STACK_TRACE_FATAL_HERE                                \
+  GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
 
-#define GET_STACK_TRACE_THREAD                              \
+#define GET_STACK_TRACE_THREAD                                    \
   GET_STACK_TRACE(kStackTraceMax, true)
 
-#define GET_STACK_TRACE_MALLOC                             \
-  GET_STACK_TRACE(flags()->malloc_context_size,            \
-                  flags()->fast_unwind_on_malloc)
+#define GET_STACK_TRACE_MALLOC                                    \
+  GET_STACK_TRACE(common_flags()->malloc_context_size,            \
+                  common_flags()->fast_unwind_on_malloc)
 
 #define GET_STACK_TRACE_FREE GET_STACK_TRACE_MALLOC
 
 #define PRINT_CURRENT_STACK()                    \
   {                                              \
     GET_STACK_TRACE(kStackTraceMax,              \
-      flags()->fast_unwind_on_fatal);            \
+      common_flags()->fast_unwind_on_fatal);     \
     PrintStack(&stack);                          \
   }
 
diff --git a/lib/asan/asan_stats.cc b/lib/asan/asan_stats.cc
index ba67c82..ba7c1ab 100644
--- a/lib/asan/asan_stats.cc
+++ b/lib/asan/asan_stats.cc
@@ -14,13 +14,14 @@
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_stats.h"
-#include "asan_thread_registry.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_mutex.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 
 namespace __asan {
 
 AsanStats::AsanStats() {
-  CHECK(REAL(memset) != 0);
+  CHECK(REAL(memset));
   REAL(memset)(this, 0, sizeof(AsanStats));
 }
 
@@ -57,7 +58,7 @@
 
 static void PrintAccumulatedStats() {
   AsanStats stats;
-  asanThreadRegistry().GetAccumulatedStats(&stats);
+  GetAccumulatedStats(&stats);
   // Use lock to keep reports from mixing up.
   BlockingMutexLock lock(&print_lock);
   stats.Print();
@@ -67,21 +68,103 @@
   PrintInternalAllocatorStats();
 }
 
+static AsanStats unknown_thread_stats(LINKER_INITIALIZED);
+static AsanStats accumulated_stats(LINKER_INITIALIZED);
+// Required for malloc_zone_statistics() on OS X. This can't be stored in
+// per-thread AsanStats.
+static uptr max_malloced_memory;
+static BlockingMutex acc_stats_lock(LINKER_INITIALIZED);
+
+static void FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
+  acc_stats_lock.CheckLocked();
+  uptr *dst = (uptr*)&accumulated_stats;
+  uptr *src = (uptr*)stats;
+  uptr num_fields = sizeof(*stats) / sizeof(uptr);
+  for (uptr i = 0; i < num_fields; i++) {
+    dst[i] += src[i];
+    src[i] = 0;
+  }
+}
+
+static void FlushThreadStats(ThreadContextBase *tctx_base, void *arg) {
+  AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
+  if (AsanThread *t = tctx->thread)
+    FlushToAccumulatedStatsUnlocked(&t->stats());
+}
+
+static void UpdateAccumulatedStatsUnlocked() {
+  acc_stats_lock.CheckLocked();
+  {
+    ThreadRegistryLock l(&asanThreadRegistry());
+    asanThreadRegistry().RunCallbackForEachThreadLocked(FlushThreadStats, 0);
+  }
+  FlushToAccumulatedStatsUnlocked(&unknown_thread_stats);
+  // This is not very accurate: we may miss allocation peaks that happen
+  // between two updates of accumulated_stats_. For more accurate bookkeeping
+  // the maximum should be updated on every malloc(), which is unacceptable.
+  if (max_malloced_memory < accumulated_stats.malloced) {
+    max_malloced_memory = accumulated_stats.malloced;
+  }
+}
+
+void FlushToAccumulatedStats(AsanStats *stats) {
+  BlockingMutexLock lock(&acc_stats_lock);
+  FlushToAccumulatedStatsUnlocked(stats);
+}
+
+void GetAccumulatedStats(AsanStats *stats) {
+  BlockingMutexLock lock(&acc_stats_lock);
+  UpdateAccumulatedStatsUnlocked();
+  internal_memcpy(stats, &accumulated_stats, sizeof(accumulated_stats));
+}
+
+void FillMallocStatistics(AsanMallocStats *malloc_stats) {
+  BlockingMutexLock lock(&acc_stats_lock);
+  UpdateAccumulatedStatsUnlocked();
+  malloc_stats->blocks_in_use = accumulated_stats.mallocs;
+  malloc_stats->size_in_use = accumulated_stats.malloced;
+  malloc_stats->max_size_in_use = max_malloced_memory;
+  malloc_stats->size_allocated = accumulated_stats.mmaped;
+}
+
+AsanStats &GetCurrentThreadStats() {
+  AsanThread *t = GetCurrentThread();
+  return (t) ? t->stats() : unknown_thread_stats;
+}
+
 }  // namespace __asan
 
 // ---------------------- Interface ---------------- {{{1
 using namespace __asan;  // NOLINT
 
 uptr __asan_get_current_allocated_bytes() {
-  return asanThreadRegistry().GetCurrentAllocatedBytes();
+  BlockingMutexLock lock(&acc_stats_lock);
+  UpdateAccumulatedStatsUnlocked();
+  uptr malloced = accumulated_stats.malloced;
+  uptr freed = accumulated_stats.freed;
+  // Return sane value if malloced < freed due to racy
+  // way we update accumulated stats.
+  return (malloced > freed) ? malloced - freed : 1;
 }
 
 uptr __asan_get_heap_size() {
-  return asanThreadRegistry().GetHeapSize();
+  BlockingMutexLock lock(&acc_stats_lock);
+  UpdateAccumulatedStatsUnlocked();
+  return accumulated_stats.mmaped - accumulated_stats.munmaped;
 }
 
 uptr __asan_get_free_bytes() {
-  return asanThreadRegistry().GetFreeBytes();
+  BlockingMutexLock lock(&acc_stats_lock);
+  UpdateAccumulatedStatsUnlocked();
+  uptr total_free = accumulated_stats.mmaped
+                  - accumulated_stats.munmaped
+                  + accumulated_stats.really_freed
+                  + accumulated_stats.really_freed_redzones;
+  uptr total_used = accumulated_stats.malloced
+                  + accumulated_stats.malloced_redzones;
+  // Return sane value if total_free < total_used due to racy
+  // way we update accumulated stats.
+  return (total_free > total_used) ? total_free - total_used : 1;
 }
 
 uptr __asan_get_unmapped_bytes() {
diff --git a/lib/asan/asan_stats.h b/lib/asan/asan_stats.h
index 37846bc..68495fb 100644
--- a/lib/asan/asan_stats.h
+++ b/lib/asan/asan_stats.h
@@ -56,6 +56,15 @@
   void Print();
 };
 
+// Returns stats for GetCurrentThread(), or stats for fake "unknown thread"
+// if GetCurrentThread() returns 0.
+AsanStats &GetCurrentThreadStats();
+// Flushes all thread-local stats to accumulated stats, and makes
+// a copy of accumulated stats.
+void GetAccumulatedStats(AsanStats *stats);
+// Flushes a given stats into accumulated stats.
+void FlushToAccumulatedStats(AsanStats *stats);
+
 // A cross-platform equivalent of malloc_statistics_t on Mac OS.
 struct AsanMallocStats {
   uptr blocks_in_use;
@@ -64,6 +73,8 @@
   uptr size_allocated;
 };
 
+void FillMallocStatistics(AsanMallocStats *malloc_stats);
+
 }  // namespace __asan
 
 #endif  // ASAN_STATS_H
diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index 778e919..1253ff1 100644
--- a/lib/asan/asan_thread.cc
+++ b/lib/asan/asan_thread.cc
@@ -13,46 +13,82 @@
 //===----------------------------------------------------------------------===//
 #include "asan_allocator.h"
 #include "asan_interceptors.h"
+#include "asan_poisoning.h"
 #include "asan_stack.h"
 #include "asan_thread.h"
-#include "asan_thread_registry.h"
 #include "asan_mapping.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "lsan/lsan_common.h"
 
 namespace __asan {
 
-AsanThread::AsanThread(LinkerInitialized x)
-    : fake_stack_(x),
-      malloc_storage_(x),
-      stats_(x) { }
+// AsanThreadContext implementation.
 
-AsanThread *AsanThread::Create(u32 parent_tid, thread_callback_t start_routine,
-                               void *arg, StackTrace *stack) {
+void AsanThreadContext::OnCreated(void *arg) {
+  CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
+  if (args->stack) {
+    internal_memcpy(&stack, args->stack, sizeof(stack));
+  }
+  thread = args->thread;
+  thread->set_context(this);
+}
+
+void AsanThreadContext::OnFinished() {
+  // Drop the link to the AsanThread object.
+  thread = 0;
+}
+
+// MIPS requires aligned address
+static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
+static ThreadRegistry *asan_thread_registry;
+
+static ThreadContextBase *GetAsanThreadContext(u32 tid) {
+  void *mem = MmapOrDie(sizeof(AsanThreadContext), "AsanThreadContext");
+  return new(mem) AsanThreadContext(tid);
+}
+
+ThreadRegistry &asanThreadRegistry() {
+  static bool initialized;
+  // Don't worry about thread_safety - this should be called when there is
+  // a single thread.
+  if (!initialized) {
+    // Never reuse ASan threads: we store pointer to AsanThreadContext
+    // in TSD and can't reliably tell when no more TSD destructors will
+    // be called. It would be wrong to reuse AsanThreadContext for another
+    // thread before all TSD destructors will be called for it.
+    asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry(
+        GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads);
+    initialized = true;
+  }
+  return *asan_thread_registry;
+}
+
+AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
+  return static_cast<AsanThreadContext *>(
+      asanThreadRegistry().GetThreadLocked(tid));
+}
+
+// AsanThread implementation.
+
+AsanThread *AsanThread::Create(thread_callback_t start_routine,
+                               void *arg) {
   uptr PageSize = GetPageSizeCached();
   uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
   AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
   thread->start_routine_ = start_routine;
   thread->arg_ = arg;
-
-  const uptr kSummaryAllocSize = PageSize;
-  CHECK_LE(sizeof(AsanThreadSummary), kSummaryAllocSize);
-  AsanThreadSummary *summary =
-      (AsanThreadSummary*)MmapOrDie(PageSize, "AsanThreadSummary");
-  summary->Init(parent_tid, stack);
-  summary->set_thread(thread);
-  thread->set_summary(summary);
+  thread->context_ = 0;
 
   return thread;
 }
 
-void AsanThreadSummary::TSDDtor(void *tsd) {
-  AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
-  if (flags()->verbosity >= 1) {
-    Report("T%d TSDDtor\n", summary->tid());
-  }
-  if (summary->thread()) {
-    summary->thread()->Destroy();
-  }
+void AsanThread::TSDDtor(void *tsd) {
+  AsanThreadContext *context = (AsanThreadContext*)tsd;
+  if (flags()->verbosity >= 1)
+    Report("T%d TSDDtor\n", context->tid);
+  if (context->thread)
+    context->thread->Destroy();
 }
 
 void AsanThread::Destroy() {
@@ -60,41 +96,42 @@
     Report("T%d exited\n", tid());
   }
 
-  asanThreadRegistry().UnregisterThread(this);
-  CHECK(summary()->thread() == 0);
+  asanThreadRegistry().FinishThread(tid());
+  FlushToAccumulatedStats(&stats_);
   // We also clear the shadow on thread destruction because
   // some code may still be executing in later TSD destructors
   // and we don't want it to have any poisoned stack.
-  ClearShadowForThreadStack();
-  fake_stack().Cleanup();
+  ClearShadowForThreadStackAndTLS();
+  DeleteFakeStack();
   uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
   UnmapOrDie(this, size);
 }
 
 void AsanThread::Init() {
-  SetThreadStackTopAndBottom();
+  SetThreadStackAndTls();
   CHECK(AddrIsInMem(stack_bottom_));
   CHECK(AddrIsInMem(stack_top_ - 1));
-  ClearShadowForThreadStack();
+  ClearShadowForThreadStackAndTLS();
   if (flags()->verbosity >= 1) {
     int local = 0;
     Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
            tid(), (void*)stack_bottom_, (void*)stack_top_,
            stack_top_ - stack_bottom_, &local);
   }
-  fake_stack_.Init(stack_size());
+  fake_stack_ = 0;  // Will be initialized lazily if needed.
   AsanPlatformThreadInit();
 }
 
-thread_return_t AsanThread::ThreadStart() {
+thread_return_t AsanThread::ThreadStart(uptr os_id) {
   Init();
+  asanThreadRegistry().StartThread(tid(), os_id, 0);
   if (flags()->use_sigaltstack) SetAlternateSignalStack();
 
   if (!start_routine_) {
     // start_routine_ == 0 if we're on the main thread or on one of the
     // OS X libdispatch worker threads. But nobody is supposed to call
     // ThreadStart() for the worker threads.
-    CHECK(tid() == 0);
+    CHECK_EQ(tid(), 0);
     return 0;
   }
 
@@ -107,24 +144,33 @@
   return res;
 }
 
-void AsanThread::SetThreadStackTopAndBottom() {
-  GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
+void AsanThread::SetThreadStackAndTls() {
+  uptr stack_size = 0, tls_size = 0;
+  GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
+                       &tls_size);
+  stack_top_ = stack_bottom_ + stack_size;
+  tls_end_ = tls_begin_ + tls_size;
+
   int local;
   CHECK(AddrIsInStack((uptr)&local));
 }
 
-void AsanThread::ClearShadowForThreadStack() {
+void AsanThread::ClearShadowForThreadStackAndTLS() {
   PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
+  if (tls_begin_ != tls_end_)
+    PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
 }
 
-const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
+const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
+                                           uptr *frame_pc) {
   uptr bottom = 0;
   if (AddrIsInStack(addr)) {
     bottom = stack_bottom();
-  } else {
-    bottom = fake_stack().AddrIsInFakeStack(addr);
+  } else if (fake_stack()) {
+    bottom = fake_stack()->AddrIsInFakeStack(addr);
     CHECK(bottom);
     *offset = addr - bottom;
+    *frame_pc = ((uptr*)bottom)[2];
     return  (const char *)((uptr*)bottom)[1];
   }
   uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1);  // align addr.
@@ -149,7 +195,104 @@
   uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
   CHECK(ptr[0] == kCurrentStackFrameMagic);
   *offset = addr - (uptr)ptr;
+  *frame_pc = ptr[2];
   return (const char*)ptr[1];
 }
 
+static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
+                                       void *addr) {
+  AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
+  AsanThread *t = tctx->thread;
+  if (!t) return false;
+  if (t->AddrIsInStack((uptr)addr)) return true;
+  if (t->fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr))
+    return true;
+  return false;
+}
+
+AsanThread *GetCurrentThread() {
+  AsanThreadContext *context =
+      reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
+  if (!context) {
+    if (SANITIZER_ANDROID) {
+      // On Android, libc constructor is called _after_ asan_init, and cleans up
+      // TSD. Try to figure out if this is still the main thread by the stack
+      // address. We are not entirely sure that we have correct main thread
+      // limits, so only do this magic on Android, and only if the found thread
+      // is the main thread.
+      AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
+      if (ThreadStackContainsAddress(tctx, &context)) {
+        SetCurrentThread(tctx->thread);
+        return tctx->thread;
+      }
+    }
+    return 0;
+  }
+  return context->thread;
+}
+
+void SetCurrentThread(AsanThread *t) {
+  CHECK(t->context());
+  if (flags()->verbosity >= 2) {
+    Report("SetCurrentThread: %p for thread %p\n",
+           t->context(), (void*)GetThreadSelf());
+  }
+  // Make sure we do not reset the current AsanThread.
+  CHECK_EQ(0, AsanTSDGet());
+  AsanTSDSet(t->context());
+  CHECK_EQ(t->context(), AsanTSDGet());
+}
+
+u32 GetCurrentTidOrInvalid() {
+  AsanThread *t = GetCurrentThread();
+  return t ? t->tid() : kInvalidTid;
+}
+
+AsanThread *FindThreadByStackAddress(uptr addr) {
+  asanThreadRegistry().CheckLocked();
+  AsanThreadContext *tctx = static_cast<AsanThreadContext *>(
+      asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress,
+                                                   (void *)addr));
+  return tctx ? tctx->thread : 0;
+}
+
+void EnsureMainThreadIDIsCorrect() {
+  AsanThreadContext *context =
+      reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
+  if (context && (context->tid == 0))
+    context->os_id = GetTid();
+}
 }  // namespace __asan
+
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+                           uptr *tls_begin, uptr *tls_end,
+                           uptr *cache_begin, uptr *cache_end) {
+  __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
+      __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
+  if (!context) return false;
+  __asan::AsanThread *t = context->thread;
+  if (!t) return false;
+  *stack_begin = t->stack_bottom();
+  *stack_end = t->stack_top();
+  *tls_begin = t->tls_begin();
+  *tls_end = t->tls_end();
+  // ASan doesn't keep allocator caches in TLS, so these are unused.
+  *cache_begin = 0;
+  *cache_end = 0;
+  return true;
+}
+
+void LockThreadRegistry() {
+  __asan::asanThreadRegistry().Lock();
+}
+
+void UnlockThreadRegistry() {
+  __asan::asanThreadRegistry().Unlock();
+}
+
+void EnsureMainThreadIDIsCorrect() {
+  __asan::EnsureMainThreadIDIsCorrect();
+}
+}  // namespace __lsan
diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h
index acc27e5..5fe8154 100644
--- a/lib/asan/asan_thread.h
+++ b/lib/asan/asan_thread.h
@@ -16,99 +16,116 @@
 
 #include "asan_allocator.h"
 #include "asan_internal.h"
+#include "asan_fake_stack.h"
 #include "asan_stack.h"
 #include "asan_stats.h"
 #include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
 
 namespace __asan {
 
 const u32 kInvalidTid = 0xffffff;  // Must fit into 24 bits.
+const u32 kMaxNumberOfThreads = (1 << 22);  // 4M
 
 class AsanThread;
 
 // These objects are created for every thread and are never deleted,
 // so we can find them by tid even if the thread is long dead.
-class AsanThreadSummary {
+class AsanThreadContext : public ThreadContextBase {
  public:
-  explicit AsanThreadSummary(LinkerInitialized) { }  // for T0.
-  void Init(u32 parent_tid, StackTrace *stack) {
-    parent_tid_ = parent_tid;
-    announced_ = false;
-    tid_ = kInvalidTid;
-    if (stack) {
-      internal_memcpy(&stack_, stack, sizeof(*stack));
-    }
-    thread_ = 0;
-    name_[0] = 0;
+  explicit AsanThreadContext(int tid)
+      : ThreadContextBase(tid),
+        announced(false),
+        thread(0) {
+    internal_memset(&stack, 0, sizeof(stack));
   }
-  u32 tid() { return tid_; }
-  void set_tid(u32 tid) { tid_ = tid; }
-  u32 parent_tid() { return parent_tid_; }
-  bool announced() { return announced_; }
-  void set_announced(bool announced) { announced_ = announced; }
-  StackTrace *stack() { return &stack_; }
-  AsanThread *thread() { return thread_; }
-  void set_thread(AsanThread *thread) { thread_ = thread; }
-  static void TSDDtor(void *tsd);
-  void set_name(const char *name) {
-    internal_strncpy(name_, name, sizeof(name_) - 1);
-  }
-  const char *name() { return name_; }
+  bool announced;
+  StackTrace stack;
+  AsanThread *thread;
 
- private:
-  u32 tid_;
-  u32 parent_tid_;
-  bool announced_;
-  StackTrace stack_;
-  AsanThread *thread_;
-  char name_[128];
+  void OnCreated(void *arg);
+  void OnFinished();
 };
 
-// AsanThreadSummary objects are never freed, so we need many of them.
-COMPILER_CHECK(sizeof(AsanThreadSummary) <= 4094);
+// AsanThreadContext objects are never freed, so we need many of them.
+COMPILER_CHECK(sizeof(AsanThreadContext) <= 4096);
 
 // AsanThread are stored in TSD and destroyed when the thread dies.
 class AsanThread {
  public:
-  explicit AsanThread(LinkerInitialized);  // for T0.
-  static AsanThread *Create(u32 parent_tid, thread_callback_t start_routine,
-                            void *arg, StackTrace *stack);
+  static AsanThread *Create(thread_callback_t start_routine, void *arg);
+  static void TSDDtor(void *tsd);
   void Destroy();
 
   void Init();  // Should be called from the thread itself.
-  thread_return_t ThreadStart();
+  thread_return_t ThreadStart(uptr os_id);
 
   uptr stack_top() { return stack_top_; }
   uptr stack_bottom() { return stack_bottom_; }
   uptr stack_size() { return stack_top_ - stack_bottom_; }
-  u32 tid() { return summary_->tid(); }
-  AsanThreadSummary *summary() { return summary_; }
-  void set_summary(AsanThreadSummary *summary) { summary_ = summary; }
+  uptr tls_begin() { return tls_begin_; }
+  uptr tls_end() { return tls_end_; }
+  u32 tid() { return context_->tid; }
+  AsanThreadContext *context() { return context_; }
+  void set_context(AsanThreadContext *context) { context_ = context; }
 
-  const char *GetFrameNameByAddr(uptr addr, uptr *offset);
+  const char *GetFrameNameByAddr(uptr addr, uptr *offset, uptr *frame_pc);
 
   bool AddrIsInStack(uptr addr) {
     return addr >= stack_bottom_ && addr < stack_top_;
   }
 
-  FakeStack &fake_stack() { return fake_stack_; }
+  void LazyInitFakeStack() {
+    if (fake_stack_) return;
+    fake_stack_ = (FakeStack*)MmapOrDie(sizeof(FakeStack), "FakeStack");
+    fake_stack_->Init(stack_size());
+  }
+  void DeleteFakeStack() {
+    if (!fake_stack_) return;
+    fake_stack_->Cleanup();
+    UnmapOrDie(fake_stack_, sizeof(FakeStack));
+  }
+  FakeStack *fake_stack() { return fake_stack_; }
+
   AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
   AsanStats &stats() { return stats_; }
 
  private:
-  void SetThreadStackTopAndBottom();
-  void ClearShadowForThreadStack();
-  AsanThreadSummary *summary_;
+  AsanThread() {}
+  void SetThreadStackAndTls();
+  void ClearShadowForThreadStackAndTLS();
+  AsanThreadContext *context_;
   thread_callback_t start_routine_;
   void *arg_;
   uptr  stack_top_;
   uptr  stack_bottom_;
+  uptr tls_begin_;
+  uptr tls_end_;
 
-  FakeStack fake_stack_;
+  FakeStack *fake_stack_;
   AsanThreadLocalMallocStorage malloc_storage_;
   AsanStats stats_;
 };
 
+struct CreateThreadContextArgs {
+  AsanThread *thread;
+  StackTrace *stack;
+};
+
+// Returns a single instance of registry.
+ThreadRegistry &asanThreadRegistry();
+
+// Must be called under ThreadRegistryLock.
+AsanThreadContext *GetThreadContextByTidLocked(u32 tid);
+
+// Get the current thread. May return 0.
+AsanThread *GetCurrentThread();
+void SetCurrentThread(AsanThread *t);
+u32 GetCurrentTidOrInvalid();
+AsanThread *FindThreadByStackAddress(uptr addr);
+
+// Used to handle fork().
+void EnsureMainThreadIDIsCorrect();
 }  // namespace __asan
 
 #endif  // ASAN_THREAD_H
diff --git a/lib/asan/asan_thread_registry.cc b/lib/asan/asan_thread_registry.cc
deleted file mode 100644
index 8067540..0000000
--- a/lib/asan/asan_thread_registry.cc
+++ /dev/null
@@ -1,198 +0,0 @@
-//===-- asan_thread_registry.cc -------------------------------------------===//
-//
-//                     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.
-//
-// AsanThreadRegistry-related code. AsanThreadRegistry is a container
-// for summaries of all created threads.
-//===----------------------------------------------------------------------===//
-
-#include "asan_stack.h"
-#include "asan_thread.h"
-#include "asan_thread_registry.h"
-#include "sanitizer_common/sanitizer_common.h"
-
-namespace __asan {
-
-static AsanThreadRegistry asan_thread_registry(LINKER_INITIALIZED);
-
-AsanThreadRegistry &asanThreadRegistry() {
-  return asan_thread_registry;
-}
-
-AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x)
-    : main_thread_(x),
-      main_thread_summary_(x),
-      accumulated_stats_(x),
-      max_malloced_memory_(x),
-      mu_(x) { }
-
-void AsanThreadRegistry::Init() {
-  AsanTSDInit(AsanThreadSummary::TSDDtor);
-  main_thread_.set_summary(&main_thread_summary_);
-  main_thread_summary_.set_thread(&main_thread_);
-  RegisterThread(&main_thread_);
-  SetCurrent(&main_thread_);
-  // At this point only one thread exists.
-  inited_ = true;
-}
-
-void AsanThreadRegistry::RegisterThread(AsanThread *thread) {
-  BlockingMutexLock lock(&mu_);
-  u32 tid = n_threads_;
-  n_threads_++;
-  CHECK(n_threads_ < kMaxNumberOfThreads);
-
-  AsanThreadSummary *summary = thread->summary();
-  CHECK(summary != 0);
-  summary->set_tid(tid);
-  thread_summaries_[tid] = summary;
-}
-
-void AsanThreadRegistry::UnregisterThread(AsanThread *thread) {
-  BlockingMutexLock lock(&mu_);
-  FlushToAccumulatedStatsUnlocked(&thread->stats());
-  AsanThreadSummary *summary = thread->summary();
-  CHECK(summary);
-  summary->set_thread(0);
-}
-
-AsanThread *AsanThreadRegistry::GetMain() {
-  return &main_thread_;
-}
-
-AsanThread *AsanThreadRegistry::GetCurrent() {
-  AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet();
-  if (!summary) {
-#if ASAN_ANDROID
-    // On Android, libc constructor is called _after_ asan_init, and cleans up
-    // TSD. Try to figure out if this is still the main thread by the stack
-    // address. We are not entirely sure that we have correct main thread
-    // limits, so only do this magic on Android, and only if the found thread is
-    // the main thread.
-    AsanThread* thread = FindThreadByStackAddress((uptr)&summary);
-    if (thread && thread->tid() == 0) {
-      SetCurrent(thread);
-      return thread;
-    }
-#endif
-    return 0;
-  }
-  return summary->thread();
-}
-
-void AsanThreadRegistry::SetCurrent(AsanThread *t) {
-  CHECK(t->summary());
-  if (flags()->verbosity >= 2) {
-    Report("SetCurrent: %p for thread %p\n",
-           t->summary(), (void*)GetThreadSelf());
-  }
-  // Make sure we do not reset the current AsanThread.
-  CHECK(AsanTSDGet() == 0);
-  AsanTSDSet(t->summary());
-  CHECK(AsanTSDGet() == t->summary());
-}
-
-AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
-  AsanThread *t = GetCurrent();
-  return (t) ? t->stats() : main_thread_.stats();
-}
-
-void AsanThreadRegistry::GetAccumulatedStats(AsanStats *stats) {
-  BlockingMutexLock lock(&mu_);
-  UpdateAccumulatedStatsUnlocked();
-  internal_memcpy(stats, &accumulated_stats_, sizeof(accumulated_stats_));
-}
-
-uptr AsanThreadRegistry::GetCurrentAllocatedBytes() {
-  BlockingMutexLock lock(&mu_);
-  UpdateAccumulatedStatsUnlocked();
-  uptr malloced = accumulated_stats_.malloced;
-  uptr freed = accumulated_stats_.freed;
-  // Return sane value if malloced < freed due to racy
-  // way we update accumulated stats.
-  return (malloced > freed) ? malloced - freed : 1;
-}
-
-uptr AsanThreadRegistry::GetHeapSize() {
-  BlockingMutexLock lock(&mu_);
-  UpdateAccumulatedStatsUnlocked();
-  return accumulated_stats_.mmaped - accumulated_stats_.munmaped;
-}
-
-uptr AsanThreadRegistry::GetFreeBytes() {
-  BlockingMutexLock lock(&mu_);
-  UpdateAccumulatedStatsUnlocked();
-  uptr total_free = accumulated_stats_.mmaped
-                  - accumulated_stats_.munmaped
-                  + accumulated_stats_.really_freed
-                  + accumulated_stats_.really_freed_redzones;
-  uptr total_used = accumulated_stats_.malloced
-                  + accumulated_stats_.malloced_redzones;
-  // Return sane value if total_free < total_used due to racy
-  // way we update accumulated stats.
-  return (total_free > total_used) ? total_free - total_used : 1;
-}
-
-// Return several stats counters with a single call to
-// UpdateAccumulatedStatsUnlocked().
-void AsanThreadRegistry::FillMallocStatistics(AsanMallocStats *malloc_stats) {
-  BlockingMutexLock lock(&mu_);
-  UpdateAccumulatedStatsUnlocked();
-  malloc_stats->blocks_in_use = accumulated_stats_.mallocs;
-  malloc_stats->size_in_use = accumulated_stats_.malloced;
-  malloc_stats->max_size_in_use = max_malloced_memory_;
-  malloc_stats->size_allocated = accumulated_stats_.mmaped;
-}
-
-AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) {
-  CHECK(tid < n_threads_);
-  CHECK(thread_summaries_[tid]);
-  return thread_summaries_[tid];
-}
-
-AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) {
-  BlockingMutexLock lock(&mu_);
-  for (u32 tid = 0; tid < n_threads_; tid++) {
-    AsanThread *t = thread_summaries_[tid]->thread();
-    if (!t || !(t->fake_stack().StackSize())) continue;
-    if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) {
-      return t;
-    }
-  }
-  return 0;
-}
-
-void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
-  for (u32 tid = 0; tid < n_threads_; tid++) {
-    AsanThread *t = thread_summaries_[tid]->thread();
-    if (t != 0) {
-      FlushToAccumulatedStatsUnlocked(&t->stats());
-    }
-  }
-  // This is not very accurate: we may miss allocation peaks that happen
-  // between two updates of accumulated_stats_. For more accurate bookkeeping
-  // the maximum should be updated on every malloc(), which is unacceptable.
-  if (max_malloced_memory_ < accumulated_stats_.malloced) {
-    max_malloced_memory_ = accumulated_stats_.malloced;
-  }
-}
-
-void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
-  // AsanStats consists of variables of type uptr only.
-  uptr *dst = (uptr*)&accumulated_stats_;
-  uptr *src = (uptr*)stats;
-  uptr num_fields = sizeof(AsanStats) / sizeof(uptr);
-  for (uptr i = 0; i < num_fields; i++) {
-    dst[i] += src[i];
-    src[i] = 0;
-  }
-}
-
-}  // namespace __asan
diff --git a/lib/asan/asan_thread_registry.h b/lib/asan/asan_thread_registry.h
deleted file mode 100644
index adb1a6d..0000000
--- a/lib/asan/asan_thread_registry.h
+++ /dev/null
@@ -1,85 +0,0 @@
-//===-- asan_thread_registry.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.
-//
-// ASan-private header for asan_thread_registry.cc
-//===----------------------------------------------------------------------===//
-
-#ifndef ASAN_THREAD_REGISTRY_H
-#define ASAN_THREAD_REGISTRY_H
-
-#include "asan_stack.h"
-#include "asan_stats.h"
-#include "asan_thread.h"
-#include "sanitizer_common/sanitizer_mutex.h"
-
-namespace __asan {
-
-// Stores summaries of all created threads, returns current thread,
-// thread by tid, thread by stack address. There is a single instance
-// of AsanThreadRegistry for the whole program.
-// AsanThreadRegistry is thread-safe.
-class AsanThreadRegistry {
- public:
-  explicit AsanThreadRegistry(LinkerInitialized);
-  void Init();
-  void RegisterThread(AsanThread *thread);
-  void UnregisterThread(AsanThread *thread);
-
-  AsanThread *GetMain();
-  // Get the current thread. May return 0.
-  AsanThread *GetCurrent();
-  void SetCurrent(AsanThread *t);
-
-  u32 GetCurrentTidOrInvalid() {
-    if (!inited_) return 0;
-    AsanThread *t = GetCurrent();
-    return t ? t->tid() : kInvalidTid;
-  }
-
-  // Returns stats for GetCurrent(), or stats for
-  // T0 if GetCurrent() returns 0.
-  AsanStats &GetCurrentThreadStats();
-  // Flushes all thread-local stats to accumulated stats, and makes
-  // a copy of accumulated stats.
-  void GetAccumulatedStats(AsanStats *stats);
-  uptr GetCurrentAllocatedBytes();
-  uptr GetHeapSize();
-  uptr GetFreeBytes();
-  void FillMallocStatistics(AsanMallocStats *malloc_stats);
-
-  AsanThreadSummary *FindByTid(u32 tid);
-  AsanThread *FindThreadByStackAddress(uptr addr);
-
- private:
-  void UpdateAccumulatedStatsUnlocked();
-  // Adds values of all counters in "stats" to accumulated stats,
-  // and fills "stats" with zeroes.
-  void FlushToAccumulatedStatsUnlocked(AsanStats *stats);
-
-  static const u32 kMaxNumberOfThreads = (1 << 22);  // 4M
-  AsanThreadSummary *thread_summaries_[kMaxNumberOfThreads];
-  AsanThread main_thread_;
-  AsanThreadSummary main_thread_summary_;
-  AsanStats accumulated_stats_;
-  // Required for malloc_zone_statistics() on OS X. This can't be stored in
-  // per-thread AsanStats.
-  uptr max_malloced_memory_;
-  u32 n_threads_;
-  BlockingMutex mu_;
-  bool inited_;
-};
-
-// Returns a single instance of registry.
-AsanThreadRegistry &asanThreadRegistry();
-
-}  // namespace __asan
-
-#endif  // ASAN_THREAD_REGISTRY_H
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index d8ce050..f74de72 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -11,7 +11,9 @@
 //
 // Windows-specific details.
 //===----------------------------------------------------------------------===//
-#ifdef _WIN32
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS
 #include <windows.h>
 
 #include <dbghelp.h>
@@ -30,30 +32,6 @@
 static bool dbghelp_initialized = false;
 #pragma comment(lib, "dbghelp.lib")
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
-  (void)fast;
-  stack->max_size = max_s;
-  void *tmp[kStackTraceMax];
-
-  // FIXME: CaptureStackBackTrace might be too slow for us.
-  // FIXME: Compare with StackWalk64.
-  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
-  uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
-  uptr offset = 0;
-  // Skip the RTL frames by searching for the PC in the stacktrace.
-  // FIXME: this doesn't work well for the malloc/free stacks yet.
-  for (uptr i = 0; i < cs_ret; i++) {
-    if (pc != (uptr)tmp[i])
-      continue;
-    offset = i;
-    break;
-  }
-
-  stack->size = cs_ret - offset;
-  for (uptr i = 0; i < stack->size; i++)
-    stack->trace[i] = (uptr)tmp[i + offset];
-}
-
 // ---------------------- TSD ---------------- {{{1
 static bool tsd_key_inited = false;
 
diff --git a/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in b/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in
new file mode 100644
index 0000000..99496c2
--- /dev/null
+++ b/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in
@@ -0,0 +1,13 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Load common config for all compiler-rt lit tests.
+lit.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
+
+# Tool-specific config options.
+config.asan_source_dir = "@ASAN_SOURCE_DIR@"
+config.bits = "32"
+
+# Load tool-specific config that would do the real work.
+lit.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg")
+
diff --git a/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in b/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in
new file mode 100644
index 0000000..94b0228
--- /dev/null
+++ b/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in
@@ -0,0 +1,12 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Load common config for all compiler-rt lit tests.
+lit.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
+
+# Tool-specific config options.
+config.asan_source_dir = "@ASAN_SOURCE_DIR@"
+config.bits = "64"
+
+# Load tool-specific config that would do the real work.
+lit.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg")
diff --git a/lib/asan/lit_tests/CMakeLists.txt b/lib/asan/lit_tests/CMakeLists.txt
index 1609032..b65d347 100644
--- a/lib/asan/lit_tests/CMakeLists.txt
+++ b/lib/asan/lit_tests/CMakeLists.txt
@@ -2,8 +2,13 @@
 set(ASAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..)
 
 configure_lit_site_cfg(
-  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+  ${CMAKE_CURRENT_SOURCE_DIR}/64bitConfig/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig/lit.site.cfg
+  )
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/32bitConfig/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg
   )
 
 configure_lit_site_cfg(
@@ -12,21 +17,27 @@
   )
 
 if(COMPILER_RT_CAN_EXECUTE_TESTS)
+  set(ASAN_TESTSUITES)
+  if(CAN_TARGET_i386)
+    list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig)
+  endif()
+  if(CAN_TARGET_x86_64 OR CAN_TARGET_powerpc64)
+    list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig)
+  endif()
   # Run ASan tests only if we're sure we may produce working binaries.
   set(ASAN_TEST_DEPS
-    clang clang-headers FileCheck count not llvm-nm llvm-symbolizer
+    ${SANITIZER_COMMON_LIT_TEST_DEPS}
     ${ASAN_RUNTIME_LIBRARIES}
-    )
+    asan_blacklist)
   set(ASAN_TEST_PARAMS
-    asan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
-    )
+    asan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
   if(LLVM_INCLUDE_TESTS)
     list(APPEND ASAN_TEST_DEPS AsanUnitTests)
+    list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit)
   endif()
   add_lit_testsuite(check-asan "Running the AddressSanitizer tests"
-    ${CMAKE_CURRENT_BINARY_DIR}
+    ${ASAN_TESTSUITES}
     PARAMS ${ASAN_TEST_PARAMS}
-    DEPENDS ${ASAN_TEST_DEPS}
-    )
+    DEPENDS ${ASAN_TEST_DEPS})
   set_target_properties(check-asan PROPERTIES FOLDER "ASan tests")
 endif()
diff --git a/lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc b/lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc
deleted file mode 100644
index cf89949..0000000
--- a/lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Make sure ASan removes the runtime library from DYLD_INSERT_LIBRARIES before
-// executing other programs.
-
-// RUN: %clangxx_asan -m64 %s -o %t
-// RUN: %clangxx -m64 %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
-// RUN:     -dynamiclib -o darwin-dummy-shared-lib-so.dylib
-
-// Make sure DYLD_INSERT_LIBRARIES doesn't contain the runtime library before
-// execl().
-
-// RUN: %t >/dev/null 2>&1
-// RUN: DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \
-// RUN:     %t 2>&1 | FileCheck %s || exit 1
-#include <unistd.h>
-int main() {
-  execl("/bin/bash", "/bin/bash", "-c",
-        "echo DYLD_INSERT_LIBRARIES=$DYLD_INSERT_LIBRARIES", NULL);
-  // CHECK:  {{DYLD_INSERT_LIBRARIES=.*darwin-dummy-shared-lib-so.dylib.*}}
-  return 0;
-}
diff --git a/lib/asan/lit_tests/Helpers/initialization-blacklist.txt b/lib/asan/lit_tests/Helpers/initialization-blacklist.txt
deleted file mode 100644
index c5f6610..0000000
--- a/lib/asan/lit_tests/Helpers/initialization-blacklist.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-global-init:*badGlobal*
-global-init-type:*badNamespace::BadClass*
diff --git a/lib/asan/lit_tests/Helpers/initialization-nobug-extra.cc b/lib/asan/lit_tests/Helpers/initialization-nobug-extra.cc
deleted file mode 100644
index 490b333..0000000
--- a/lib/asan/lit_tests/Helpers/initialization-nobug-extra.cc
+++ /dev/null
@@ -1,9 +0,0 @@
-// Linker initialized:
-int getAB();
-static int ab = getAB();
-// Function local statics:
-int countCalls();
-static int one = countCalls();
-// Constexpr:
-int getCoolestInteger();
-static int coolest_integer = getCoolestInteger();
diff --git a/lib/asan/lit_tests/Linux/interception_failure_test.cc b/lib/asan/lit_tests/Linux/interception_failure_test.cc
deleted file mode 100644
index dfad909..0000000
--- a/lib/asan/lit_tests/Linux/interception_failure_test.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// If user provides his own libc functions, ASan doesn't
-// intercept these functions.
-
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <stdio.h>
-
-extern "C" long strtol(const char *nptr, char **endptr, int base) {
-  fprintf(stderr, "my_strtol_interceptor\n");
-  return 0;
-}
-
-int main() {
-  char *x = (char*)malloc(10 * sizeof(char));
-  free(x);
-  return (int)strtol(x, 0, 10);
-  // CHECK: my_strtol_interceptor
-  // CHECK-NOT: heap-use-after-free
-}
diff --git a/lib/asan/lit_tests/Linux/interception_malloc_test.cc b/lib/asan/lit_tests/Linux/interception_malloc_test.cc
deleted file mode 100644
index 8f66788..0000000
--- a/lib/asan/lit_tests/Linux/interception_malloc_test.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// ASan interceptor can be accessed with __interceptor_ prefix.
-
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-
-extern "C" void *__interceptor_malloc(size_t size);
-extern "C" void *malloc(size_t size) {
-  write(2, "malloc call\n", sizeof("malloc call\n") - 1);
-  return __interceptor_malloc(size);
-}
-
-int main() {
-  char *x = (char*)malloc(10 * sizeof(char));
-  free(x);
-  return (int)strtol(x, 0, 10);
-  // CHECK: malloc call
-  // CHECK: heap-use-after-free
-}
diff --git a/lib/asan/lit_tests/Linux/interception_test.cc b/lib/asan/lit_tests/Linux/interception_test.cc
deleted file mode 100644
index 94fb499..0000000
--- a/lib/asan/lit_tests/Linux/interception_test.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// ASan interceptor can be accessed with __interceptor_ prefix.
-
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <stdio.h>
-
-extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
-extern "C" long strtol(const char *nptr, char **endptr, int base) {
-  fprintf(stderr, "my_strtol_interceptor\n");
-  return __interceptor_strtol(nptr, endptr, base);
-}
-
-int main() {
-  char *x = (char*)malloc(10 * sizeof(char));
-  free(x);
-  return (int)strtol(x, 0, 10);
-  // CHECK: my_strtol_interceptor
-  // CHECK: heap-use-after-free
-}
diff --git a/lib/asan/lit_tests/Linux/swapcontext_test.cc b/lib/asan/lit_tests/Linux/swapcontext_test.cc
deleted file mode 100644
index 0404b4f..0000000
--- a/lib/asan/lit_tests/Linux/swapcontext_test.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Check that ASan plays well with easy cases of makecontext/swapcontext.
-
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-
-#include <stdio.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-ucontext_t orig_context;
-ucontext_t child_context;
-
-void Child(int mode) {
-  char x[32] = {0};  // Stack gets poisoned.
-  printf("Child: %p\n", x);
-  // (a) Do nothing, just return to parent function.
-  // (b) Jump into the original function. Stack remains poisoned unless we do
-  //     something.
-  if (mode == 1) {
-    if (swapcontext(&child_context, &orig_context) < 0) {
-      perror("swapcontext");
-      _exit(0);
-    }
-  }
-}
-
-int Run(int arg, int mode) {
-  const int kStackSize = 1 << 20;
-  char child_stack[kStackSize + 1];
-  printf("Child stack: %p\n", child_stack);
-  // Setup child context.
-  getcontext(&child_context);
-  child_context.uc_stack.ss_sp = child_stack;
-  child_context.uc_stack.ss_size = kStackSize / 2;
-  if (mode == 0) {
-    child_context.uc_link = &orig_context;
-  }
-  makecontext(&child_context, (void (*)())Child, 1, mode);
-  if (swapcontext(&orig_context, &child_context) < 0) {
-    perror("swapcontext");
-    return 0;
-  }
-  // Touch childs's stack to make sure it's unpoisoned.
-  for (int i = 0; i < kStackSize; i++) {
-    child_stack[i] = i;
-  }
-  return child_stack[arg];
-}
-
-int main(int argc, char **argv) {
-  // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext
-  int ret = 0;
-  ret += Run(argc - 1, 0);
-  printf("Test1 passed\n");
-  // CHECK: Test1 passed
-  ret += Run(argc - 1, 1);
-  printf("Test2 passed\n");
-  // CHECK: Test2 passed
-  return ret;
-}
diff --git a/lib/asan/lit_tests/Linux/zero-base-shadow.cc b/lib/asan/lit_tests/Linux/zero-base-shadow.cc
deleted file mode 100644
index d6ea1aa..0000000
--- a/lib/asan/lit_tests/Linux/zero-base-shadow.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out
-// RUN: %clangxx_asan -m64 -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out
-// RUN: %clangxx_asan -m64 -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out
-// RUN: %clangxx_asan -m32 -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out
-// RUN: %clangxx_asan -m32 -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out
-// RUN: %clangxx_asan -m32 -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out
-
-#include <string.h>
-int main(int argc, char **argv) {
-  char x[10];
-  memset(x, 0, 10);
-  int res = x[argc * 10];  // BOOOM
-  // CHECK: {{READ of size 1 at 0x.* thread T0}}
-  // CHECK: {{    #0 0x.* in _?main .*zero-base-shadow.cc:}}[[@LINE-2]]
-  // CHECK: {{Address 0x.* is .* frame <main>}}
-
-  // Check that shadow for stack memory occupies lower part of address space.
-  // CHECK-64: =>0x0f{{.*}}
-  // CHECK-32: =>0x1f{{.*}}
-  return res;
-}
diff --git a/lib/asan/lit_tests/Darwin/interface_symbols_darwin.c b/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c
similarity index 89%
rename from lib/asan/lit_tests/Darwin/interface_symbols_darwin.c
rename to lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c
index 18bba70..319175a 100644
--- a/lib/asan/lit_tests/Darwin/interface_symbols_darwin.c
+++ b/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c
@@ -2,10 +2,10 @@
 // If you're changing this file, please also change
 // ../Linux/interface_symbols.c
 
-// RUN: %clang -fsanitize=address -dead_strip -O2 %s -o %t.exe
+// RUN: %clang_asan -dead_strip -O2 %s -o %t.exe
 // RUN: rm -f %t.symbols %t.interface
 
-// RUN: nm `otool -L %t.exe | grep "asan_osx_dynamic.dylib" | \
+// RUN: nm -g `otool -L %t.exe | grep "asan_osx_dynamic.dylib" | \
 // RUN:                       tr -d '\011' | \
 // RUN:                       sed "s/.dylib.*/.dylib/"` \
 // RUN:   | grep " T " | sed "s/.* T //" \
@@ -16,7 +16,7 @@
 // RUN:   | grep -v "__asan_default_options" \
 // RUN:   | grep -v "__asan_on_error" > %t.symbols
 
-// RUN: cat %p/../../asan_interface_internal.h \
+// RUN: cat %p/../../../asan_interface_internal.h \
 // RUN:    | sed "s/\/\/.*//" | sed "s/typedef.*//" \
 // RUN:    | grep -v "OPTIONAL" \
 // RUN:    | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
diff --git a/lib/asan/lit_tests/Darwin/lit.local.cfg b/lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg
similarity index 100%
rename from lib/asan/lit_tests/Darwin/lit.local.cfg
rename to lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg
diff --git a/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc b/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc
new file mode 100644
index 0000000..807a828
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc
@@ -0,0 +1,51 @@
+// Regression test for a bug in malloc_create_zone()
+// (https://code.google.com/p/address-sanitizer/issues/detail?id=203)
+// The old implementation of malloc_create_zone() didn't always return a
+// page-aligned address, so we can only test on a best-effort basis.
+
+// RUN: %clangxx_asan %s -o %t
+// RUN: %t 2>&1
+
+#include <malloc/malloc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+const int kNumIter = 4096;
+const int kNumZones = 100;
+int main() {
+  char *mem[kNumIter * 2];
+  // Allocate memory chunks from different size classes up to 1 page.
+  // (For the case malloc() returns memory chunks in descending order)
+  for (int i = 0; i < kNumIter; i++) {
+    mem[i] = (char*)malloc(8 * i);
+  }
+  // Try to allocate a page-aligned malloc zone. Otherwise the mprotect() call
+  // in malloc_set_zone_name() will silently fail.
+  malloc_zone_t *zone = NULL;
+  bool aligned = false;
+  for (int i = 0; i < kNumZones; i++) {
+    zone = malloc_create_zone(0, 0);
+    if (((uintptr_t)zone & (~0xfff)) == (uintptr_t)zone) {
+      aligned = true;
+      break;
+    }
+  }
+  if (!aligned) {
+    printf("Warning: couldn't allocate a page-aligned zone.");
+    return 0;
+  }
+  // malloc_set_zone_name() calls mprotect(zone, 4096, PROT_READ | PROT_WRITE),
+  // modifies the zone contents and then calls mprotect(zone, 4096, PROT_READ).
+  malloc_set_zone_name(zone, "foobar");
+  // Allocate memory chunks from different size classes again.
+  for (int i = 0; i < kNumIter; i++) {
+    mem[i + kNumIter] = (char*)malloc(8 * i);
+  }
+  // Access the allocated memory chunks and free them.
+  for (int i = 0; i < kNumIter * 2; i++) {
+    memset(mem[i], 'a', 8 * (i % kNumIter));
+    free(mem[i]);
+  }
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc b/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc
new file mode 100644
index 0000000..d5f6c7c
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc
@@ -0,0 +1,20 @@
+// Make sure the zones created by malloc_create_zone() are write-protected.
+#include <malloc/malloc.h>
+#include <stdio.h>
+
+// RUN: %clangxx_asan %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+
+
+void *pwn(malloc_zone_t *unused_zone, size_t unused_size) {
+  printf("PWNED\n");
+  return NULL;
+}
+
+int main() {
+  malloc_zone_t *zone = malloc_create_zone(0, 0);
+  zone->malloc = pwn;
+  void *v = malloc_zone_malloc(zone, 1);
+  // CHECK-NOT: PWNED
+  return 0;
+}
diff --git a/lib/asan/lit_tests/Darwin/reexec-insert-libraries-env.cc b/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc
similarity index 86%
rename from lib/asan/lit_tests/Darwin/reexec-insert-libraries-env.cc
rename to lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc
index 40a459f..208fe43 100644
--- a/lib/asan/lit_tests/Darwin/reexec-insert-libraries-env.cc
+++ b/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc
@@ -2,8 +2,8 @@
 // This is a regression test for
 // https://code.google.com/p/address-sanitizer/issues/detail?id=159
 
-// RUN: %clangxx_asan -m64 %s -o %t
-// RUN: %clangxx -m64 %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
+// RUN: %clangxx_asan %s -o %t
+// RUN: %clangxx %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
 // RUN:     -dynamiclib -o darwin-dummy-shared-lib-so.dylib
 
 // FIXME: the following command line may hang in the case of a regression.
diff --git a/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc b/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc
new file mode 100644
index 0000000..fa0dd4f
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc
@@ -0,0 +1,20 @@
+// Make sure ASan removes the runtime library from DYLD_INSERT_LIBRARIES before
+// executing other programs.
+
+// RUN: %clangxx_asan %s -o %t
+// RUN: %clangxx %p/../Helpers/echo-env.cc -o %T/echo-env
+// RUN: %clangxx %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
+// RUN:     -dynamiclib -o %t-darwin-dummy-shared-lib-so.dylib
+
+// Make sure DYLD_INSERT_LIBRARIES doesn't contain the runtime library before
+// execl().
+
+// RUN: %t %T/echo-env >/dev/null 2>&1
+// RUN: DYLD_INSERT_LIBRARIES=%t-darwin-dummy-shared-lib-so.dylib \
+// RUN:     %t %T/echo-env 2>&1 | FileCheck %s || exit 1
+#include <unistd.h>
+int main(int argc, char *argv[]) {
+  execl(argv[1], argv[1], "DYLD_INSERT_LIBRARIES", NULL);
+  // CHECK:  {{DYLD_INSERT_LIBRARIES = .*darwin-dummy-shared-lib-so.dylib.*}}
+  return 0;
+}
diff --git a/lib/asan/lit_tests/Helpers/blacklist-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc
similarity index 100%
rename from lib/asan/lit_tests/Helpers/blacklist-extra.cc
rename to lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc
diff --git a/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc b/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc
new file mode 100644
index 0000000..65e91c1
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc
@@ -0,0 +1,19 @@
+// Helper binary for
+// lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc
+// Prints the environment variable with the given name.
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+  if (argc != 2) {
+    printf("Usage: %s ENVNAME\n", argv[0]);
+    exit(1);
+  }
+  const char *value = getenv(argv[1]);
+  if (value) {
+    printf("%s = %s\n", argv[1], value);
+  } else {
+    printf("%s not set.\n", argv[1]);
+  }
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc
new file mode 100644
index 0000000..e4189d1
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+class C {
+ public:
+  C() { value = 42; }
+  ~C() { }
+  int value;
+};
+
+C c;
+
+void AccessC() {
+  printf("C value: %d\n", c.value);
+}
+
+int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc
new file mode 100644
index 0000000..d4606f0
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc
@@ -0,0 +1,2 @@
+void *bar(void *input);
+void *glob2 = bar((void*)0x2345);
diff --git a/lib/asan/lit_tests/Helpers/initialization-blacklist-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc
similarity index 100%
rename from lib/asan/lit_tests/Helpers/initialization-blacklist-extra.cc
rename to lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc
new file mode 100644
index 0000000..69455a0
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc
@@ -0,0 +1,4 @@
+int zero_init();
+int badSrcGlobal = zero_init();
+int readBadSrcGlobal() { return badSrcGlobal; }
+
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt
new file mode 100644
index 0000000..8329463
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt
@@ -0,0 +1,3 @@
+global:*badGlobal*=init
+type:*badNamespace::BadClass*=init
+src:*initialization-blacklist-extra2.cc=init
diff --git a/lib/asan/lit_tests/Helpers/initialization-bug-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc
similarity index 100%
rename from lib/asan/lit_tests/Helpers/initialization-bug-extra.cc
rename to lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc
diff --git a/lib/asan/lit_tests/Helpers/initialization-bug-extra2.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc
similarity index 100%
rename from lib/asan/lit_tests/Helpers/initialization-bug-extra2.cc
rename to lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc
new file mode 100644
index 0000000..b32466a
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc
@@ -0,0 +1,3 @@
+// Constexpr:
+int getCoolestInteger();
+static int coolest_integer = getCoolestInteger();
diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc
new file mode 100644
index 0000000..886165a
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc
@@ -0,0 +1,9 @@
+// Linker initialized:
+int getAB();
+static int ab = getAB();
+// Function local statics:
+int countCalls();
+static int one = countCalls();
+// Trivial constructor, non-trivial destructor:
+int getStructWithDtorValue();
+static int val = getStructWithDtorValue();
diff --git a/lib/asan/lit_tests/Helpers/lit.local.cfg b/lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg
similarity index 100%
rename from lib/asan/lit_tests/Helpers/lit.local.cfg
rename to lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg
diff --git a/lib/asan/lit_tests/Linux/asan_prelink_test.cc b/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc
similarity index 64%
rename from lib/asan/lit_tests/Linux/asan_prelink_test.cc
rename to lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc
index 522c191..0f158c1 100644
--- a/lib/asan/lit_tests/Linux/asan_prelink_test.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc
@@ -3,11 +3,13 @@
 // or gold's flag -Ttext (we try the first flag first, if that fails we
 // try the second flag).
 //
-// RUN: %clangxx_asan -m64 -c %s -o %t.o
-// RUN: %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 ||\
-// RUN: %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000
-// RUN: %clangxx_asan -m64 %t.o %t.so -Wl,-R. -o %t
+// RUN: %clangxx_asan -c %s -o %t.o
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 ||\
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000
+// RUN: %clangxx_asan %t.o %t.so -Wl,-R. -o %t
 // RUN: ASAN_OPTIONS=verbosity=1 %t 2>&1 | FileCheck %s
+
+// REQUIRES: x86_64-supported-target, asan-64-bits
 #if BUILD_SO
 int G;
 int *getG() {
diff --git a/lib/asan/lit_tests/Linux/clone_test.cc b/lib/asan/lit_tests/TestCases/Linux/clone_test.cc
similarity index 69%
rename from lib/asan/lit_tests/Linux/clone_test.cc
rename to lib/asan/lit_tests/TestCases/Linux/clone_test.cc
index ca13b22..0e12f35 100644
--- a/lib/asan/lit_tests/Linux/clone_test.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/clone_test.cc
@@ -1,14 +1,10 @@
 // Regression test for:
 // http://code.google.com/p/address-sanitizer/issues/detail?id=37
 
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -o %t && %t | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && %t | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && %t | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %t | FileCheck %s
 
 #include <stdio.h>
 #include <sched.h>
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob.cc b/lib/asan/lit_tests/TestCases/Linux/glob.cc
new file mode 100644
index 0000000..a375f1b
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/glob.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <string>
+
+
+int main(int argc, char *argv[]) {
+  std::string path = argv[1];
+  std::string pattern = path + "/glob_test_root/*a";
+  printf("pattern: %s\n", pattern.c_str());
+
+  glob_t globbuf;
+  int res = glob(pattern.c_str(), 0, 0, &globbuf);
+
+  printf("%d %s\n", errno, strerror(errno));
+  assert(res == 0);
+  assert(globbuf.gl_pathc == 2);
+  printf("%zu\n", strlen(globbuf.gl_pathv[0]));
+  printf("%zu\n", strlen(globbuf.gl_pathv[1]));
+  printf("PASS\n");
+  // CHECK: PASS
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba
diff --git a/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc b/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc
new file mode 100644
index 0000000..8bddb76
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc
@@ -0,0 +1,53 @@
+// RUN: %clangxx_asan -fsanitize=use-after-return -O0 %s -o %t && \
+// RUN:   not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -fsanitize=use-after-return -O2 %s -o %t && \
+// RUN:   not %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+__attribute__((noinline))
+char *pretend_to_do_something(char *x) {
+  __asm__ __volatile__("" : : "r" (x) : "memory");
+  return x;
+}
+
+__attribute__((noinline))
+char *LeakStack() {
+  char x[1024];
+  memset(x, 0, sizeof(x));
+  return pretend_to_do_something(x);
+}
+
+template<size_t kFrameSize>
+__attribute__((noinline))
+void RecuriveFunctionWithStackFrame(int depth) {
+  if (depth <= 0) return;
+  char x[kFrameSize];
+  x[0] = depth;
+  pretend_to_do_something(x);
+  RecuriveFunctionWithStackFrame<kFrameSize>(depth - 1);
+}
+
+int main(int argc, char **argv) {
+  int n_iter = argc >= 2 ? atoi(argv[1]) : 1000;
+  int depth  = argc >= 3 ? atoi(argv[2]) : 500;
+  for (int i = 0; i < n_iter; i++) {
+    RecuriveFunctionWithStackFrame<10>(depth);
+    RecuriveFunctionWithStackFrame<100>(depth);
+    RecuriveFunctionWithStackFrame<500>(depth);
+    RecuriveFunctionWithStackFrame<1024>(depth);
+    RecuriveFunctionWithStackFrame<2000>(depth);
+    RecuriveFunctionWithStackFrame<5000>(depth);
+    RecuriveFunctionWithStackFrame<10000>(depth);
+  }
+  char *stale_stack = LeakStack();
+  RecuriveFunctionWithStackFrame<1024>(10);
+  stale_stack[100]++;
+  // CHECK: ERROR: AddressSanitizer: stack-use-after-return on address
+  // CHECK: is located in stack of thread T0 at offset 132 in frame
+  // CHECK:  in LeakStack(){{.*}}heavy_uar_test.cc:
+  // CHECK: [32, 1056) 'x'
+  return 0;
+}
diff --git a/lib/asan/lit_tests/Linux/initialization-bug-any-order.cc b/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc
similarity index 67%
rename from lib/asan/lit_tests/Linux/initialization-bug-any-order.cc
rename to lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc
index f054a81..2787fc5 100644
--- a/lib/asan/lit_tests/Linux/initialization-bug-any-order.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc
@@ -1,13 +1,14 @@
 // Test to make sure basic initialization order errors are caught.
 // Check that on Linux initialization order bugs are caught
-// independently on order in which we list source files.
+// independently on order in which we list source files (if we specify
+// strict init-order checking).
 
-// RUN: %clangxx_asan -m64 -O0 %s %p/../Helpers/initialization-bug-extra.cc -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 \
-// RUN:    | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O0 %p/../Helpers/initialization-bug-extra.cc %s -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 \
-// RUN:    | %symbolize | FileCheck %s
+// RUN: %clangxx_asan -O0 %s %p/../Helpers/initialization-bug-extra.cc -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true not %t 2>&1 \
+// RUN:    | FileCheck %s
+// RUN: %clangxx_asan -O0 %p/../Helpers/initialization-bug-extra.cc %s -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true not %t 2>&1 \
+// RUN:    | FileCheck %s
 
 // Do not test with optimization -- the error may be optimized away.
 
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc
new file mode 100644
index 0000000..9d161aa
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc
@@ -0,0 +1,22 @@
+// If user provides his own libc functions, ASan doesn't
+// intercept these functions.
+
+// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+  fprintf(stderr, "my_strtol_interceptor\n");
+  return 0;
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return (int)strtol(x, 0, 10);
+  // CHECK: my_strtol_interceptor
+  // CHECK-NOT: heap-use-after-free
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc
new file mode 100644
index 0000000..cdd7239
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc
@@ -0,0 +1,23 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern "C" void *__interceptor_malloc(size_t size);
+extern "C" void *malloc(size_t size) {
+  write(2, "malloc call\n", sizeof("malloc call\n") - 1);
+  return __interceptor_malloc(size);
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return (int)strtol(x, 0, 10);
+  // CHECK: malloc call
+  // CHECK: heap-use-after-free
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc
new file mode 100644
index 0000000..28c7df4
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc
@@ -0,0 +1,57 @@
+// RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+//
+// RUN: %clangxx_asan -O0 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+
+#include <dirent.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+int main() {
+  // Ensure the readdir_r interceptor doesn't erroneously mark the entire dirent
+  // as written when the end of the directory pointer is reached.
+  fputs("test1: reading the " TEMP_DIR " directory...\n", stderr);
+  DIR *d = opendir(TEMP_DIR);
+  struct dirent *result = (struct dirent *)(0xfeedbeef);
+  // We assume the temp dir for this test doesn't have crazy long file names.
+  char entry_buffer[4096];
+  memset(entry_buffer, 0xab, sizeof(entry_buffer));
+  unsigned count = 0;
+  do {
+    // Stamp the entry struct to try to trick the interceptor.
+    ((struct dirent *)entry_buffer)->d_reclen = 9999;
+    if (readdir_r(d, (struct dirent *)entry_buffer, &result) != 0)
+      abort();
+    ++count;
+  } while (result != NULL);
+  fprintf(stderr, "read %d entries\n", count);
+  // CHECK: test1: reading the {{.*}} directory...
+  // CHECK-NOT: stack-buffer-overflow
+  // CHECK: read {{.*}} entries
+
+  // Ensure the readdir64_r interceptor doesn't have the bug either.
+  fputs("test2: reading the " TEMP_DIR " directory...\n", stderr);
+  d = opendir(TEMP_DIR);
+  struct dirent64 *result64;
+  memset(entry_buffer, 0xab, sizeof(entry_buffer));
+  count = 0;
+  do {
+    // Stamp the entry struct to try to trick the interceptor.
+    ((struct dirent64 *)entry_buffer)->d_reclen = 9999;
+    if (readdir64_r(d, (struct dirent64 *)entry_buffer, &result64) != 0)
+      abort();
+    ++count;
+  } while (result64 != NULL);
+  fprintf(stderr, "read %d entries\n", count);
+  // CHECK: test2: reading the {{.*}} directory...
+  // CHECK-NOT: stack-buffer-overflow
+  // CHECK: read {{.*}} entries
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_test.cc
new file mode 100644
index 0000000..2b3316d
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_test.cc
@@ -0,0 +1,22 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+  fprintf(stderr, "my_strtol_interceptor\n");
+  return __interceptor_strtol(nptr, endptr, base);
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return (int)strtol(x, 0, 10);
+  // CHECK: my_strtol_interceptor
+  // CHECK: heap-use-after-free
+}
diff --git a/lib/asan/lit_tests/Linux/interface_symbols_linux.c b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c
similarity index 79%
rename from lib/asan/lit_tests/Linux/interface_symbols_linux.c
rename to lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c
index 6ea61e6..baabc05 100644
--- a/lib/asan/lit_tests/Linux/interface_symbols_linux.c
+++ b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c
@@ -1,14 +1,14 @@
 // Check the presense of interface symbols in compiled file.
 
-// RUN: %clang -fsanitize=address -O2 %s -o %t.exe
-// RUN: nm %t.exe | grep " T " | sed "s/.* T //" \
+// RUN: %clang_asan -O2 %s -o %t.exe
+// RUN: nm -D %t.exe | grep " T " | sed "s/.* T //" \
 // RUN:    | grep "__asan_" | sed "s/___asan_/__asan_/" \
 // RUN:    | grep -v "__asan_malloc_hook" \
 // RUN:    | grep -v "__asan_free_hook" \
 // RUN:    | grep -v "__asan_symbolize" \
 // RUN:    | grep -v "__asan_default_options" \
 // RUN:    | grep -v "__asan_on_error" > %t.symbols
-// RUN: cat %p/../../asan_interface_internal.h \
+// RUN: cat %p/../../../asan_interface_internal.h \
 // RUN:    | sed "s/\/\/.*//" | sed "s/typedef.*//" \
 // RUN:    | grep -v "OPTIONAL" \
 // RUN:    | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
@@ -27,4 +27,8 @@
 // RUN: echo __asan_report_store_n >> %t.interface
 // RUN: cat %t.interface | sort -u | diff %t.symbols -
 
+// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing
+// in "initialized data section".
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
 int main() { return 0; }
diff --git a/lib/asan/lit_tests/Linux/lit.local.cfg b/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg
similarity index 100%
copy from lib/asan/lit_tests/Linux/lit.local.cfg
copy to lib/asan/lit_tests/TestCases/Linux/lit.local.cfg
diff --git a/lib/asan/lit_tests/Linux/malloc-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc
similarity index 82%
rename from lib/asan/lit_tests/Linux/malloc-in-qsort.cc
rename to lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc
index a3fa255..73d2bc1 100644
--- a/lib/asan/lit_tests/Linux/malloc-in-qsort.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc
@@ -1,10 +1,14 @@
 // RUN: %clangxx_asan -O2 %s -o %t
-// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-FAST
-// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-SLOW
+// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST
+// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW
 
 // Test how well we unwind in presence of qsort in the stack
 // (i.e. if we can unwind through a function compiled w/o frame pointers).
 // https://code.google.com/p/address-sanitizer/issues/detail?id=137
+
+// Fast unwinder is only avaliable on x86_64 and i386.
+// REQUIRES: x86_64-supported-target
+
 #include <stdlib.h>
 #include <stdio.h>
 
diff --git a/lib/asan/lit_tests/Linux/malloc_delete_mismatch.cc b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc
similarity index 87%
rename from lib/asan/lit_tests/Linux/malloc_delete_mismatch.cc
rename to lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc
index f34b33a..c39dcf6 100644
--- a/lib/asan/lit_tests/Linux/malloc_delete_mismatch.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc
@@ -2,8 +2,7 @@
 // is set.
 
 // RUN: %clangxx_asan -g %s -o %t 2>&1
-// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1 %t 2>&1 | \
-// RUN: %symbolize | FileCheck %s
+// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1 not %t 2>&1 | FileCheck %s
 
 // No error here.
 // RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=0 %t
diff --git a/lib/asan/lit_tests/Linux/overflow-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc
similarity index 81%
rename from lib/asan/lit_tests/Linux/overflow-in-qsort.cc
rename to lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc
index c298991..1399772 100644
--- a/lib/asan/lit_tests/Linux/overflow-in-qsort.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc
@@ -1,10 +1,14 @@
 // RUN: %clangxx_asan -O2 %s -o %t
-// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-FAST
-// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-SLOW
+// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST
+// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW
 
 // Test how well we unwind in presence of qsort in the stack
 // (i.e. if we can unwind through a function compiled w/o frame pointers).
 // https://code.google.com/p/address-sanitizer/issues/detail?id=137
+
+// Fast unwinder is only avaliable on x86_64 and i386.
+// REQUIRES: x86_64-supported-target
+
 #include <stdlib.h>
 #include <stdio.h>
 
diff --git a/lib/asan/lit_tests/Linux/preinit_test.cc b/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc
similarity index 100%
rename from lib/asan/lit_tests/Linux/preinit_test.cc
rename to lib/asan/lit_tests/TestCases/Linux/preinit_test.cc
diff --git a/lib/asan/lit_tests/TestCases/Linux/ptrace.cc b/lib/asan/lit_tests/TestCases/Linux/ptrace.cc
new file mode 100644
index 0000000..8831b81
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/ptrace.cc
@@ -0,0 +1,52 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %t
+// RUN: %clangxx_asan -DPOSITIVE -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int main(void) {
+  pid_t pid;
+  pid = fork();
+  if (pid == 0) { // child
+    ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+    execl("/bin/true", "true", NULL);
+  } else {
+    wait(NULL);
+    user_regs_struct regs;
+    int res;
+    user_regs_struct * volatile pregs = &regs;
+#ifdef POSITIVE
+    ++pregs;
+#endif
+    res = ptrace(PTRACE_GETREGS, pid, NULL, pregs);
+    // CHECK: AddressSanitizer: stack-buffer-overflow
+    // CHECK: {{.*ptrace.cc:}}[[@LINE-2]]
+    assert(!res);
+#if __WORDSIZE == 64
+    printf("%zx\n", regs.rip);
+#else
+    printf("%lx\n", regs.eip);
+#endif
+
+    user_fpregs_struct fpregs;
+    res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs);
+    assert(!res);
+    printf("%lx\n", (unsigned long)fpregs.cwd);
+
+#if __WORDSIZE == 32
+    user_fpxregs_struct fpxregs;
+    res = ptrace(PTRACE_GETFPXREGS, pid, NULL, &fpxregs);
+    assert(!res);
+    printf("%lx\n", (unsigned long)fpxregs.mxcsr);
+#endif
+
+    ptrace(PTRACE_CONT, pid, NULL, NULL);
+    wait(NULL);
+  }
+  return 0;
+}
diff --git a/lib/asan/lit_tests/Linux/rlimit_mmap_test.cc b/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc
similarity index 85%
rename from lib/asan/lit_tests/Linux/rlimit_mmap_test.cc
rename to lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc
index 8679475..0d1d4ba 100644
--- a/lib/asan/lit_tests/Linux/rlimit_mmap_test.cc
+++ b/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc
@@ -1,5 +1,5 @@
 // Check that we properly report mmap failure.
-// RUN: %clangxx_asan %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan %s -o %t && not %t 2>&1 | FileCheck %s
 #include <stdlib.h>
 #include <assert.h>
 #include <sys/time.h>
diff --git a/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc b/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc
new file mode 100644
index 0000000..6cbb69a
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc
@@ -0,0 +1,90 @@
+// Check that ASan plays well with easy cases of makecontext/swapcontext.
+
+// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
+//
+// This test is too sublte to try on non-x86 arch for now.
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
+#include <stdio.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+ucontext_t orig_context;
+ucontext_t child_context;
+
+const int kStackSize = 1 << 20;
+
+__attribute__((noinline))
+void Throw() {
+  throw 1;
+}
+
+__attribute__((noinline))
+void ThrowAndCatch() {
+  try {
+    Throw();
+  } catch(int a) {
+    printf("ThrowAndCatch: %d\n", a);
+  }
+}
+
+void Child(int mode) {
+  char x[32] = {0};  // Stack gets poisoned.
+  printf("Child: %p\n", x);
+  ThrowAndCatch();  // Simulate __asan_handle_no_return().
+  // (a) Do nothing, just return to parent function.
+  // (b) Jump into the original function. Stack remains poisoned unless we do
+  //     something.
+  if (mode == 1) {
+    if (swapcontext(&child_context, &orig_context) < 0) {
+      perror("swapcontext");
+      _exit(0);
+    }
+  }
+}
+
+int Run(int arg, int mode, char *child_stack) {
+  printf("Child stack: %p\n", child_stack);
+  // Setup child context.
+  getcontext(&child_context);
+  child_context.uc_stack.ss_sp = child_stack;
+  child_context.uc_stack.ss_size = kStackSize / 2;
+  if (mode == 0) {
+    child_context.uc_link = &orig_context;
+  }
+  makecontext(&child_context, (void (*)())Child, 1, mode);
+  if (swapcontext(&orig_context, &child_context) < 0) {
+    perror("swapcontext");
+    return 0;
+  }
+  // Touch childs's stack to make sure it's unpoisoned.
+  for (int i = 0; i < kStackSize; i++) {
+    child_stack[i] = i;
+  }
+  return child_stack[arg];
+}
+
+int main(int argc, char **argv) {
+  char stack[kStackSize + 1];
+  // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext
+  int ret = 0;
+  ret += Run(argc - 1, 0, stack);
+  printf("Test1 passed\n");
+  // CHECK: Test1 passed
+  ret += Run(argc - 1, 1, stack);
+  printf("Test2 passed\n");
+  // CHECK: Test2 passed
+  char *heap = new char[kStackSize + 1];
+  ret += Run(argc - 1, 0, heap);
+  printf("Test3 passed\n");
+  // CHECK: Test3 passed
+  ret += Run(argc - 1, 1, heap);
+  printf("Test4 passed\n");
+  // CHECK: Test4 passed
+
+  delete [] heap;
+  return ret;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/syscalls.cc b/lib/asan/lit_tests/TestCases/Linux/syscalls.cc
new file mode 100644
index 0000000..b1ffe63
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/syscalls.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <errno.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sanitizer/linux_syscall_hooks.h>
+
+/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general
+   sanity of their behaviour. */
+
+int main(int argc, char *argv[]) {
+  char buf[1000];
+  __sanitizer_syscall_pre_recvmsg(0, buf - 1, 0);
+  // CHECK: AddressSanitizer: stack-buffer-{{.*}}erflow
+  // CHECK: READ of size {{.*}} at {{.*}} thread T0
+  // CHECK: #0 {{.*}} in __sanitizer_syscall_pre_recvmsg
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc b/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc
new file mode 100644
index 0000000..566409b
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_asan -O0 %s -fsanitize-address-zero-base-shadow -pie -o %t && %t 2>&1 | FileCheck %s
+
+// Zero-base shadow only works on x86_64 and i386.
+// REQUIRES: x86_64-supported-target
+
+// A regression test for time(NULL), which caused ASan to crash in the
+// zero-based shadow mode on Linux.
+// FIXME: this test does not work on Darwin, because the code pages of the
+// executable interleave with the zero-based shadow.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+int main() {
+  time_t t = time(NULL);
+  fprintf(stderr, "Time: %s\n", ctime(&t));  // NOLINT
+  // CHECK: {{Time: .* .* .*}}
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc b/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc
new file mode 100644
index 0000000..d67c4f9
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc
@@ -0,0 +1,35 @@
+// Test that TLS is unpoisoned on thread death.
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
+// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#include <sanitizer/asan_interface.h>
+
+__thread int64_t tls_var[2];
+
+volatile int64_t *p_tls_var;
+
+void *first(void *arg) {
+  ASAN_POISON_MEMORY_REGION(&tls_var, sizeof(tls_var));
+  p_tls_var = tls_var;
+  return 0;
+}
+
+void *second(void *arg) {
+  assert(tls_var == p_tls_var);
+  *p_tls_var = 1;
+  return 0;
+}
+
+int main(int argc, char *argv[]) {
+  pthread_t p;
+  assert(0 == pthread_create(&p, 0, first, 0));
+  assert(0 == pthread_join(p, 0));
+  assert(0 == pthread_create(&p, 0, second, 0));
+  assert(0 == pthread_join(p, 0));
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc
new file mode 100644
index 0000000..e6bcc55
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+
+// Zero-base shadow only works on x86_64 and i386.
+// REQUIRES: i386-supported-target, asan-32-bits
+
+#include <string.h>
+int main(int argc, char **argv) {
+  char x[10];
+  memset(x, 0, 10);
+  int res = x[argc * 10];  // BOOOM
+  // CHECK: {{READ of size 1 at 0x.* thread T0}}
+  // CHECK: {{    #0 0x.* in main .*zero-base-shadow32.cc:}}[[@LINE-2]]
+  // CHECK: {{Address 0x.* is .* frame}}
+  // CHECK: main
+
+  // Check that shadow for stack memory occupies lower part of address space.
+  // CHECK: =>0x1
+  return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc
new file mode 100644
index 0000000..1db725c
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+
+// Zero-base shadow only works on x86_64 and i386.
+// REQUIRES: x86_64-supported-target, asan-64-bits
+
+#include <string.h>
+int main(int argc, char **argv) {
+  char x[10];
+  memset(x, 0, 10);
+  int res = x[argc * 10];  // BOOOM
+  // CHECK: {{READ of size 1 at 0x.* thread T0}}
+  // CHECK: {{    #0 0x.* in main .*zero-base-shadow64.cc:}}[[@LINE-2]]
+  // CHECK: {{Address 0x.* is .* frame}}
+  // CHECK: main
+
+  // Check that shadow for stack memory occupies lower part of address space.
+  // CHECK: =>0x0f
+  return res;
+}
diff --git a/lib/asan/lit_tests/SharedLibs/darwin-dummy-shared-lib-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc
similarity index 100%
rename from lib/asan/lit_tests/SharedLibs/darwin-dummy-shared-lib-so.cc
rename to lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc
diff --git a/lib/asan/lit_tests/SharedLibs/dlclose-test-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc
similarity index 100%
rename from lib/asan/lit_tests/SharedLibs/dlclose-test-so.cc
rename to lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc
diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc
new file mode 100644
index 0000000..20ef2d8
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <unistd.h>
+
+void inc_global();
+
+int slow_init() {
+  sleep(1);
+  inc_global();
+  return 42;
+}
+
+int slowly_init_glob = slow_init();
diff --git a/lib/asan/lit_tests/SharedLibs/lit.local.cfg b/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg
similarity index 100%
copy from lib/asan/lit_tests/SharedLibs/lit.local.cfg
copy to lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg
diff --git a/lib/asan/lit_tests/SharedLibs/shared-lib-test-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc
similarity index 91%
rename from lib/asan/lit_tests/SharedLibs/shared-lib-test-so.cc
rename to lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc
index 686a245..6ef565c 100644
--- a/lib/asan/lit_tests/SharedLibs/shared-lib-test-so.cc
+++ b/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc
@@ -19,3 +19,8 @@
 void inc(int index) {
   GLOB[index]++;
 }
+
+extern "C"
+void inc2(int *a, int index) {
+  a[index]++;
+}
diff --git a/lib/asan/lit_tests/TestCases/allow_user_segv.cc b/lib/asan/lit_tests/TestCases/allow_user_segv.cc
new file mode 100644
index 0000000..55cf604
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/allow_user_segv.cc
@@ -0,0 +1,48 @@
+// Regression test for
+// https://code.google.com/p/address-sanitizer/issues/detail?id=180
+
+// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true not %t 2>&1 | FileCheck %s
+
+#include <signal.h>
+#include <stdio.h>
+
+struct sigaction user_sigaction;
+struct sigaction original_sigaction;
+
+void User_OnSIGSEGV(int signum, siginfo_t *siginfo, void *context) {
+  fprintf(stderr, "User sigaction called\n");
+  if (original_sigaction.sa_flags | SA_SIGINFO)
+    original_sigaction.sa_sigaction(signum, siginfo, context);
+  else
+    original_sigaction.sa_handler(signum);
+}
+
+int DoSEGV() {
+  volatile int *x = 0;
+  return *x;
+}
+
+int main() {
+  user_sigaction.sa_sigaction = User_OnSIGSEGV;
+  user_sigaction.sa_flags = SA_SIGINFO;
+#if defined(__APPLE__) && !defined(__LP64__)
+  // On 32-bit Darwin KERN_PROTECTION_FAILURE (SIGBUS) is delivered.
+  int signum = SIGBUS;
+#else
+  // On 64-bit Darwin KERN_INVALID_ADDRESS (SIGSEGV) is delivered.
+  // On Linux SIGSEGV is delivered as well.
+  int signum = SIGSEGV;
+#endif
+  if (sigaction(signum, &user_sigaction, &original_sigaction)) {
+    perror("sigaction");
+    return 1;
+  }
+  fprintf(stderr, "User sigaction installed\n");
+  return DoSEGV();
+}
+
+// CHECK: User sigaction installed
+// CHECK-NEXT: User sigaction called
+// CHECK-NEXT: ASAN:SIGSEGV
+// CHECK: AddressSanitizer: SEGV on unknown address
diff --git a/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc b/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc
new file mode 100644
index 0000000..0efe245
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc
@@ -0,0 +1,39 @@
+// Check that asan_symbolize.py script works (for binaries, ASan RTL and
+// shared object files.
+
+// RUN: %clangxx_asan -O0 %p/SharedLibs/shared-lib-test-so.cc -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: ASAN_SYMBOLIZER_PATH= not %t 2>&1 | %asan_symbolize | FileCheck %s
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string>
+
+using std::string;
+
+typedef void (fun_t)(int*, int);
+
+int main(int argc, char *argv[]) {
+  string path = string(argv[0]) + "-so.so";
+  printf("opening %s ... \n", path.c_str());
+  void *lib = dlopen(path.c_str(), RTLD_NOW);
+  if (!lib) {
+    printf("error in dlopen(): %s\n", dlerror());
+    return 1;
+  }
+  fun_t *inc2 = (fun_t*)dlsym(lib, "inc2");
+  if (!inc2) return 1;
+  printf("ok\n");
+  int *array = (int*)malloc(40);
+  inc2(array, 1);
+  inc2(array, -1);  // BOOM
+  // CHECK: ERROR: AddressSanitizer: heap-buffer-overflow
+  // CHECK: READ of size 4 at 0x{{.*}}
+  // CHECK: #0 {{.*}} in inc2 {{.*}}shared-lib-test-so.cc:25
+  // CHECK: #1 {{.*}} in main {{.*}}asan-symbolize-sanity-test.cc:[[@LINE-4]]
+  // CHECK: allocated by thread T{{.*}} here:
+  // CHECK: #{{.*}} in {{(wrap_|__interceptor_)?}}malloc
+  // CHECK: #{{.*}} in main {{.*}}asan-symbolize-sanity-test.cc:[[@LINE-9]]
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/blacklist.cc b/lib/asan/lit_tests/TestCases/blacklist.cc
new file mode 100644
index 0000000..5e6d4c8
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/blacklist.cc
@@ -0,0 +1,36 @@
+// Test the blacklist functionality of ASan
+
+// RUN: echo "fun:*brokenFunction*" > %tmp
+// RUN: echo "global:*badGlobal*" >> %tmp
+// RUN: echo "src:*blacklist-extra.cc" >> %tmp
+// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O0 %s -o %t \
+// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
+// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O1 %s -o %t \
+// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
+// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O2 %s -o %t \
+// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
+// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O3 %s -o %t \
+// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
+
+// badGlobal is accessed improperly, but we blacklisted it.
+int badGlobal;
+int readBadGlobal() {
+  return (&badGlobal)[1];
+}
+
+// A function which is broken, but excluded in the blacklist.
+int brokenFunction(int argc) {
+  char x[10] = {0};
+  return x[argc * 10];  // BOOM
+}
+
+// This function is defined in Helpers/blacklist-extra.cc, a source file which
+// is blacklisted by name
+int externalBrokenFunction(int x);
+
+int main(int argc, char **argv) {
+  brokenFunction(argc);
+  int x = readBadGlobal();
+  externalBrokenFunction(argc);
+  return 0;
+}
diff --git a/lib/asan/lit_tests/deep_stack_uaf.cc b/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc
similarity index 65%
rename from lib/asan/lit_tests/deep_stack_uaf.cc
rename to lib/asan/lit_tests/TestCases/deep_stack_uaf.cc
index 7b32798..920411c 100644
--- a/lib/asan/lit_tests/deep_stack_uaf.cc
+++ b/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc
@@ -1,12 +1,7 @@
 // Check that we can store lots of stack frames if asked to.
 
-// RUN: %clangxx_asan -m64 -O0 %s -o %t 2>&1
-// RUN: ASAN_OPTIONS=malloc_context_size=120:redzone=512 %t 2>&1 | \
-// RUN: %symbolize | FileCheck %s
-
-// RUN: %clangxx_asan -m32 -O0 %s -o %t 2>&1
-// RUN: ASAN_OPTIONS=malloc_context_size=120:redzone=512 %t 2>&1 | \
-// RUN: %symbolize | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -o %t 2>&1
+// RUN: ASAN_OPTIONS=malloc_context_size=120:redzone=512 not %t 2>&1 | FileCheck %s
 #include <stdlib.h>
 #include <stdio.h>
 
diff --git a/lib/asan/lit_tests/TestCases/deep_tail_call.cc b/lib/asan/lit_tests/TestCases/deep_tail_call.cc
new file mode 100644
index 0000000..2e7aa8e
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/deep_tail_call.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+// CHECK: AddressSanitizer: global-buffer-overflow
+int global[10];
+// CHECK: {{#0.*call4}}
+void __attribute__((noinline)) call4(int i) { global[i+10]++; }
+// CHECK: {{#1.*call3}}
+void __attribute__((noinline)) call3(int i) { call4(i); }
+// CHECK: {{#2.*call2}}
+void __attribute__((noinline)) call2(int i) { call3(i); }
+// CHECK: {{#3.*call1}}
+void __attribute__((noinline)) call1(int i) { call2(i); }
+// CHECK: {{#4.*main}}
+int main(int argc, char **argv) {
+  call1(argc);
+  return global[0];
+}
diff --git a/lib/asan/lit_tests/deep_thread_stack.cc b/lib/asan/lit_tests/TestCases/deep_thread_stack.cc
similarity index 68%
rename from lib/asan/lit_tests/deep_thread_stack.cc
rename to lib/asan/lit_tests/TestCases/deep_thread_stack.cc
index 781508d..92e0d66 100644
--- a/lib/asan/lit_tests/deep_thread_stack.cc
+++ b/lib/asan/lit_tests/TestCases/deep_thread_stack.cc
@@ -1,11 +1,7 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
 
 #include <pthread.h>
 
diff --git a/lib/asan/lit_tests/TestCases/default_blacklist.cc b/lib/asan/lit_tests/TestCases/default_blacklist.cc
new file mode 100644
index 0000000..25a1ae1
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/default_blacklist.cc
@@ -0,0 +1,3 @@
+// Test that ASan uses the default blacklist from resource directory.
+// RUN: %clangxx_asan -### %s 2>&1 | FileCheck %s
+// CHECK: fsanitize-blacklist={{.*}}asan_blacklist.txt
diff --git a/lib/asan/lit_tests/default_options.cc b/lib/asan/lit_tests/TestCases/default_options.cc
similarity index 100%
rename from lib/asan/lit_tests/default_options.cc
rename to lib/asan/lit_tests/TestCases/default_options.cc
diff --git a/lib/asan/lit_tests/TestCases/dlclose-test.cc b/lib/asan/lit_tests/TestCases/dlclose-test.cc
new file mode 100644
index 0000000..03ed160
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/dlclose-test.cc
@@ -0,0 +1,81 @@
+// Regression test for
+// http://code.google.com/p/address-sanitizer/issues/detail?id=19
+// Bug description:
+// 1. application dlopens foo.so
+// 2. asan registers all globals from foo.so
+// 3. application dlcloses foo.so
+// 4. application mmaps some memory to the location where foo.so was before
+// 5. application starts using this mmaped memory, but asan still thinks there
+// are globals.
+// 6. BOOM
+
+// This sublte test assumes that after a foo.so is dlclose-d
+// we can mmap the region of memory that has been occupied by the library.
+// It works on i368/x86_64 Linux, but not necessary anywhere else.
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
+// RUN: %clangxx_asan -O0 %p/SharedLibs/dlclose-test-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %p/SharedLibs/dlclose-test-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %p/SharedLibs/dlclose-test-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %p/SharedLibs/dlclose-test-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <string>
+
+using std::string;
+
+typedef int *(fun_t)();
+
+int main(int argc, char *argv[]) {
+  string path = string(argv[0]) + "-so.so";
+  size_t PageSize = sysconf(_SC_PAGESIZE);
+  printf("opening %s ... \n", path.c_str());
+  void *lib = dlopen(path.c_str(), RTLD_NOW);
+  if (!lib) {
+    printf("error in dlopen(): %s\n", dlerror());
+    return 1;
+  }
+  fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var");
+  if (!get) {
+    printf("failed dlsym\n");
+    return 1;
+  }
+  int *addr = get();
+  assert(((size_t)addr % 32) == 0);  // should be 32-byte aligned.
+  printf("addr: %p\n", addr);
+  addr[0] = 1;  // make sure we can write there.
+
+  // Now dlclose the shared library.
+  printf("attempting to dlclose\n");
+  if (dlclose(lib)) {
+    printf("failed to dlclose\n");
+    return 1;
+  }
+  // Now, the page where 'addr' is unmapped. Map it.
+  size_t page_beg = ((size_t)addr) & ~(PageSize - 1);
+  void *res = mmap((void*)(page_beg), PageSize,
+                   PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
+  if (res == (char*)-1L) {
+    printf("failed to mmap\n");
+    return 1;
+  }
+  addr[1] = 2;  // BOOM (if the bug is not fixed).
+  printf("PASS\n");
+  // CHECK: PASS
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/double-free.cc b/lib/asan/lit_tests/TestCases/double-free.cc
new file mode 100644
index 0000000..738a894
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/double-free.cc
@@ -0,0 +1,18 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+  char *x = (char*)malloc(10 * sizeof(char));
+  memset(x, 0, 10);
+  int res = x[argc];
+  free(x);
+  free(x + argc - 1);  // BOOM
+  // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0
+  // CHECK: double-free.cc:[[@LINE-2]]
+  // CHECK: freed by thread T0 here:
+  // CHECK: double-free.cc:[[@LINE-5]]
+  // CHECK: allocated by thread T0 here:
+  // CHECK: double-free.cc:[[@LINE-10]]
+  return res;
+}
diff --git a/lib/asan/lit_tests/force_inline_opt0.cc b/lib/asan/lit_tests/TestCases/force_inline_opt0.cc
similarity index 69%
rename from lib/asan/lit_tests/force_inline_opt0.cc
rename to lib/asan/lit_tests/TestCases/force_inline_opt0.cc
index 955ce38..775a66d 100644
--- a/lib/asan/lit_tests/force_inline_opt0.cc
+++ b/lib/asan/lit_tests/TestCases/force_inline_opt0.cc
@@ -1,7 +1,7 @@
 // This test checks that we are no instrumenting a memory access twice
 // (before and after inlining)
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t
+// RUN: %clangxx_asan -O1 %s -o %t && %t
+// RUN: %clangxx_asan -O0 %s -o %t && %t
 __attribute__((always_inline))
 void foo(int *x) {
   *x = 0;
diff --git a/lib/asan/lit_tests/TestCases/free_hook_realloc.cc b/lib/asan/lit_tests/TestCases/free_hook_realloc.cc
new file mode 100644
index 0000000..92f5acd
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/free_hook_realloc.cc
@@ -0,0 +1,31 @@
+// Check that free hook doesn't conflict with Realloc.
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <unistd.h>
+
+static void *glob_ptr;
+
+extern "C" {
+void __asan_free_hook(void *ptr) {
+  if (ptr == glob_ptr) {
+    *(int*)ptr = 0;
+    write(1, "FreeHook\n", sizeof("FreeHook\n"));
+  }
+}
+}
+
+int main() {
+  int *x = (int*)malloc(100);
+  x[0] = 42;
+  glob_ptr = x;
+  int *y = (int*)realloc(x, 200);
+  // Verify that free hook was called and didn't spoil the memory.
+  if (y[0] != 42) {
+    _exit(1);
+  }
+  write(1, "Passed\n", sizeof("Passed\n"));
+  // CHECK: FreeHook
+  // CHECK: Passed
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/global-demangle.cc b/lib/asan/lit_tests/TestCases/global-demangle.cc
new file mode 100644
index 0000000..d050b70
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/global-demangle.cc
@@ -0,0 +1,17 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+
+namespace XXX {
+class YYY {
+ public:
+  static char ZZZ[];
+};
+char YYY::ZZZ[] = "abc";
+}
+
+int main(int argc, char **argv) {
+  return (int)XXX::YYY::ZZZ[argc + 5];  // BOOM
+  // CHECK: {{READ of size 1 at 0x.*}}
+  // CHECK: {{0x.* is located 2 bytes to the right of global variable}}
+  // CHECK: 'XXX::YYY::ZZZ' {{.*}} of size 4
+  // CHECK: 'XXX::YYY::ZZZ' is ascii string 'abc'
+}
diff --git a/lib/asan/lit_tests/TestCases/global-overflow.cc b/lib/asan/lit_tests/TestCases/global-overflow.cc
new file mode 100644
index 0000000..0f080f5
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/global-overflow.cc
@@ -0,0 +1,21 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <string.h>
+int main(int argc, char **argv) {
+  static char XXX[10];
+  static char YYY[10];
+  static char ZZZ[10];
+  memset(XXX, 0, 10);
+  memset(YYY, 0, 10);
+  memset(ZZZ, 0, 10);
+  int res = YYY[argc * 10];  // BOOOM
+  // CHECK: {{READ of size 1 at 0x.* thread T0}}
+  // CHECK: {{    #0 0x.* in main .*global-overflow.cc:}}[[@LINE-2]]
+  // CHECK: {{0x.* is located 0 bytes to the right of global variable}}
+  // CHECK:   {{.*YYY.* of size 10}}
+  res += XXX[argc] + ZZZ[argc];
+  return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/heap-overflow.cc b/lib/asan/lit_tests/TestCases/heap-overflow.cc
new file mode 100644
index 0000000..a5f68e2
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/heap-overflow.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+  char *x = (char*)malloc(10 * sizeof(char));
+  memset(x, 0, 10);
+  int res = x[argc * 10];  // BOOOM
+  // CHECK: {{READ of size 1 at 0x.* thread T0}}
+  // CHECK: {{    #0 0x.* in main .*heap-overflow.cc:}}[[@LINE-2]]
+  // CHECK: {{0x.* is located 0 bytes to the right of 10-byte region}}
+  // CHECK: {{allocated by thread T0 here:}}
+
+  // CHECK-Linux: {{    #0 0x.* in .*malloc}}
+  // CHECK-Linux: {{    #1 0x.* in main .*heap-overflow.cc:13}}
+
+  // CHECK-Darwin: {{    #0 0x.* in wrap_malloc.*}}
+  // CHECK-Darwin: {{    #1 0x.* in main .*heap-overflow.cc:13}}
+  free(x);
+  return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc b/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc
new file mode 100644
index 0000000..58a44c5
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc
@@ -0,0 +1,13 @@
+// RUN: %clangxx_asan %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O %s -o %t && not %t 2>&1 | FileCheck %s
+// Check that we can find huge buffer overflows to the left.
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+  char *x = (char*)malloc(1 << 20);
+  memset(x, 0, 10);
+  int res = x[-argc * 4000];  // BOOOM
+  // CHECK: is located 4000 bytes to the left of
+  free(x);
+  return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/init-order-atexit.cc b/lib/asan/lit_tests/TestCases/init-order-atexit.cc
new file mode 100644
index 0000000..b5551df
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/init-order-atexit.cc
@@ -0,0 +1,31 @@
+// Test for the following situation:
+// (1) global A is constructed.
+// (2) exit() is called during construction of global B.
+// (3) destructor of A reads uninitialized global C from another module.
+// We do *not* want to report init-order bug in this case.
+
+// RUN: %clangxx_asan -O0 %s %p/Helpers/init-order-atexit-extra.cc -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true not %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void AccessC();
+
+class A {
+ public:
+  A() { }
+  ~A() { AccessC(); printf("PASSED\n"); }
+  // CHECK-NOT: AddressSanitizer
+  // CHECK: PASSED
+};
+
+A a;
+
+class B {
+ public:
+  B() { exit(1); }
+  ~B() { }
+};
+
+B b;
diff --git a/lib/asan/lit_tests/TestCases/init-order-dlopen.cc b/lib/asan/lit_tests/TestCases/init-order-dlopen.cc
new file mode 100644
index 0000000..001fa8a
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/init-order-dlopen.cc
@@ -0,0 +1,52 @@
+// Regression test for
+// https://code.google.com/p/address-sanitizer/issues/detail?id=178
+
+// RUN: %clangxx_asan -O0 %p/SharedLibs/init-order-dlopen-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// If the linker doesn't support --export-dynamic (which is ELF-specific),
+// try to link without that option.
+// FIXME: find a better solution.
+// RUN: %clangxx_asan -O0 %s -o %t -Wl,--export-dynamic || \
+// RUN:     %clangxx_asan -O0 %s -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 | FileCheck %s
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <string>
+
+using std::string;
+
+int foo() {
+  return 42;
+}
+int global = foo();
+
+__attribute__((visibility("default")))
+void inc_global() {
+  global++;
+}
+
+void *global_poller(void *arg) {
+  while (true) {
+    if (global != 42)
+      break;
+    usleep(100);
+  }
+  return 0;
+}
+
+int main(int argc, char *argv[]) {
+  pthread_t p;
+  pthread_create(&p, 0, global_poller, 0);
+  string path = string(argv[0]) + "-so.so";
+  if (0 == dlopen(path.c_str(), RTLD_NOW)) {
+    fprintf(stderr, "dlerror: %s\n", dlerror());
+    return 1;
+  }
+  pthread_join(p, 0);
+  printf("PASSED\n");
+  // CHECK: PASSED
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc b/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc
new file mode 100644
index 0000000..a75d1eb
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc
@@ -0,0 +1,32 @@
+// Check that init-order checking is properly disabled if pthread_create is
+// called.
+
+// RUN: %clangxx_asan %s %p/Helpers/init-order-pthread-create-extra.cc -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t
+
+#include <stdio.h>
+#include <pthread.h>
+
+void *run(void *arg) {
+  return arg;
+}
+
+void *foo(void *input) {
+  pthread_t t;
+  pthread_create(&t, 0, run, input);
+  void *res;
+  pthread_join(t, &res);
+  return res;
+}
+
+void *bar(void *input) {
+  return input;
+}
+
+void *glob = foo((void*)0x1234);
+extern void *glob2;
+
+int main() {
+  printf("%p %p\n", glob, glob2);
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/initialization-blacklist.cc b/lib/asan/lit_tests/TestCases/initialization-blacklist.cc
new file mode 100644
index 0000000..f40fcc0
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/initialization-blacklist.cc
@@ -0,0 +1,32 @@
+// Test for blacklist functionality of initialization-order checker.
+
+// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-blacklist-extra.cc\
+// RUN:   %p/Helpers/initialization-blacklist-extra2.cc \
+// RUN:   -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
+// RUN:   -fsanitize=init-order -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
+// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-blacklist-extra.cc\
+// RUN:   %p/Helpers/initialization-blacklist-extra2.cc \
+// RUN:   -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
+// RUN:   -fsanitize=init-order -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
+// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-blacklist-extra.cc\
+// RUN:   %p/Helpers/initialization-blacklist-extra2.cc \
+// RUN:   -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
+// RUN:   -fsanitize=init-order -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
+
+// Function is defined in another TU.
+int readBadGlobal();
+int x = readBadGlobal();  // init-order bug.
+
+// Function is defined in another TU.
+int accessBadObject();
+int y = accessBadObject();  // init-order bug.
+
+int readBadSrcGlobal();
+int z = readBadSrcGlobal();  // init-order bug.
+
+int main(int argc, char **argv) {
+  return argc + x + y + z - 1;
+}
diff --git a/lib/asan/lit_tests/initialization-bug.cc b/lib/asan/lit_tests/TestCases/initialization-bug.cc
similarity index 77%
rename from lib/asan/lit_tests/initialization-bug.cc
rename to lib/asan/lit_tests/TestCases/initialization-bug.cc
index 624afb0..fb289b1 100644
--- a/lib/asan/lit_tests/initialization-bug.cc
+++ b/lib/asan/lit_tests/TestCases/initialization-bug.cc
@@ -1,14 +1,13 @@
 // Test to make sure basic initialization order errors are caught.
 
-// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 \
-// RUN:    | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 \
-// RUN:     | %symbolize | FileCheck %s
+// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true not %t 2>&1 | FileCheck %s
 
 // Do not test with optimization -- the error may be optimized away.
 
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=186
+// XFAIL: darwin
+
 #include <cstdio>
 
 // The structure of the test is:
diff --git a/lib/asan/lit_tests/TestCases/initialization-constexpr.cc b/lib/asan/lit_tests/TestCases/initialization-constexpr.cc
new file mode 100644
index 0000000..65c95ed
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/initialization-constexpr.cc
@@ -0,0 +1,31 @@
+// Constexpr:
+// We need to check that a global variable initialized with a constexpr
+// constructor can be accessed during dynamic initialization (as a constexpr
+// constructor implies that it was initialized during constant initialization,
+// not dynamic initialization).
+
+// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-constexpr-extra.cc\
+// RUN:   --std=c++11 -fsanitize=init-order -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
+// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-constexpr-extra.cc\
+// RUN:   --std=c++11 -fsanitize=init-order -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
+// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-constexpr-extra.cc\
+// RUN:   --std=c++11 -fsanitize=init-order -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
+// RUN: %clangxx_asan -O3 %s %p/Helpers/initialization-constexpr-extra.cc\
+// RUN:   --std=c++11 -fsanitize=init-order -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
+
+class Integer {
+  private:
+  int value;
+
+  public:
+  constexpr Integer(int x = 0) : value(x) {}
+  int getValue() {return value;}
+};
+Integer coolestInteger(42);
+int getCoolestInteger() { return coolestInteger.getValue(); }
+
+int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/initialization-nobug.cc b/lib/asan/lit_tests/TestCases/initialization-nobug.cc
new file mode 100644
index 0000000..ed37d13
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/initialization-nobug.cc
@@ -0,0 +1,48 @@
+// A collection of various initializers which shouldn't trip up initialization
+// order checking.  If successful, this will just return 0.
+
+// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
+// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
+// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
+// RUN: %clangxx_asan -O3 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t
+// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
+
+// Simple access:
+// Make sure that accessing a global in the same TU is safe
+
+bool condition = true;
+int initializeSameTU() {
+  return condition ? 0x2a : 052;
+}
+int sameTU = initializeSameTU();
+
+// Linker initialized:
+// Check that access to linker initialized globals originating from a different
+// TU's initializer is safe.
+
+int A = (1 << 1) + (1 << 3) + (1 << 5), B;
+int getAB() {
+  return A * B;
+}
+
+// Function local statics:
+// Check that access to function local statics originating from a different
+// TU's initializer is safe.
+
+int countCalls() {
+  static int calls;
+  return ++calls;
+}
+
+// Trivial constructor, non-trivial destructor.
+struct StructWithDtor {
+  ~StructWithDtor() { }
+  int value;
+};
+StructWithDtor struct_with_dtor;
+int getStructWithDtorValue() { return struct_with_dtor.value; }
+
+int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/interface_test.cc b/lib/asan/lit_tests/TestCases/interface_test.cc
new file mode 100644
index 0000000..297b552
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/interface_test.cc
@@ -0,0 +1,8 @@
+// Check that user may include ASan interface header.
+// RUN: %clang_asan %s -o %t && %t
+// RUN: %clang %s -o %t && %t
+#include <sanitizer/asan_interface.h>
+
+int main() {
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/invalid-free.cc b/lib/asan/lit_tests/TestCases/invalid-free.cc
new file mode 100644
index 0000000..aeca536
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/invalid-free.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+  char *x = (char*)malloc(10 * sizeof(char));
+  memset(x, 0, 10);
+  int res = x[argc];
+  free(x + 5);  // BOOM
+  // CHECK: AddressSanitizer: attempting free on address{{.*}}in thread T0
+  // CHECK: invalid-free.cc:[[@LINE-2]]
+  // CHECK: is located 5 bytes inside of 10-byte region
+  // CHECK: allocated by thread T0 here:
+  // CHECK: invalid-free.cc:[[@LINE-8]]
+  return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/ioctl.cc b/lib/asan/lit_tests/TestCases/ioctl.cc
new file mode 100644
index 0000000..08ca688
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/ioctl.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_asan -O0 -g %s -o %t && ASAN_OPTIONS=handle_ioctl=1 not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 -g %s -o %t && ASAN_OPTIONS=handle_ioctl=1 not %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -O0 -g %s -o %t && %t
+// RUN: %clangxx_asan -O3 -g %s -o %t && %t
+
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+  int fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+  int nonblock;
+  int res = ioctl(fd, FIONBIO, &nonblock + 1);
+  // CHECK: AddressSanitizer: stack-buffer-overflow
+  // CHECK: READ of size 4 at
+  // CHECK: {{#.* in main .*ioctl.cc:}}[[@LINE-3]]
+  assert(res == 0);
+  close(fd);
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/large_func_test.cc b/lib/asan/lit_tests/TestCases/large_func_test.cc
new file mode 100644
index 0000000..5010950
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/large_func_test.cc
@@ -0,0 +1,55 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+
+#include <stdlib.h>
+__attribute__((noinline))
+static void LargeFunction(int *x, int zero) {
+  x[0]++;
+  x[1]++;
+  x[2]++;
+  x[3]++;
+  x[4]++;
+  x[5]++;
+  x[6]++;
+  x[7]++;
+  x[8]++;
+  x[9]++;
+
+  // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK:   {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
+  // CHECK: {{READ of size 4 at 0x.* thread T0}}
+  x[zero + 103]++;  // we should report this exact line
+  // atos incorrectly extracts the symbol name for the static functions on
+  // Darwin.
+  // CHECK-Linux:  {{#0 0x.* in LargeFunction.*large_func_test.cc:}}[[@LINE-3]]
+  // CHECK-Darwin: {{#0 0x.* in .*LargeFunction.*large_func_test.cc}}:[[@LINE-4]]
+
+  x[10]++;
+  x[11]++;
+  x[12]++;
+  x[13]++;
+  x[14]++;
+  x[15]++;
+  x[16]++;
+  x[17]++;
+  x[18]++;
+  x[19]++;
+}
+
+int main(int argc, char **argv) {
+  int *x = new int[100];
+  LargeFunction(x, argc - 1);
+  // CHECK: {{    #1 0x.* in main .*large_func_test.cc:}}[[@LINE-1]]
+  // CHECK: {{0x.* is located 12 bytes to the right of 400-byte region}}
+  // CHECK: {{allocated by thread T0 here:}}
+  // CHECK-Linux: {{    #0 0x.* in operator new.*}}
+  // CHECK-Darwin: {{    #0 0x.* in .*_Zna.*}}
+  // CHECK: {{    #1 0x.* in main .*large_func_test.cc:}}[[@LINE-7]]
+  delete x;
+}
diff --git a/lib/asan/lit_tests/log-path_test.cc b/lib/asan/lit_tests/TestCases/log-path_test.cc
similarity index 100%
rename from lib/asan/lit_tests/log-path_test.cc
rename to lib/asan/lit_tests/TestCases/log-path_test.cc
diff --git a/lib/asan/lit_tests/log_path_fork_test.cc.disabled b/lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled
similarity index 100%
rename from lib/asan/lit_tests/log_path_fork_test.cc.disabled
rename to lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled
diff --git a/lib/asan/lit_tests/TestCases/lsan_annotations.cc b/lib/asan/lit_tests/TestCases/lsan_annotations.cc
new file mode 100644
index 0000000..c55ab86
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/lsan_annotations.cc
@@ -0,0 +1,16 @@
+// Check that LSan annotations work fine.
+// RUN: %clangxx_asan -O0 %s -o %t && %t
+// RUN: %clangxx_asan -O3 %s -o %t && %t
+
+#include <sanitizer/lsan_interface.h>
+#include <stdlib.h>
+
+int main() {
+  int *x = new int;
+  __lsan_ignore_object(x);
+  {
+    __lsan::ScopedDisabler disabler;
+    double *y = new double;
+  }
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/malloc_fill.cc b/lib/asan/lit_tests/TestCases/malloc_fill.cc
new file mode 100644
index 0000000..57f50d1
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/malloc_fill.cc
@@ -0,0 +1,22 @@
+// Check that we fill malloc-ed memory correctly.
+// RUN: %clangxx_asan %s -o %t
+// RUN: %t | FileCheck %s
+// RUN: ASAN_OPTIONS=max_malloc_fill_size=10:malloc_fill_byte=8 %t | FileCheck %s --check-prefix=CHECK-10-8
+// RUN: ASAN_OPTIONS=max_malloc_fill_size=20:malloc_fill_byte=171 %t | FileCheck %s --check-prefix=CHECK-20-ab
+
+#include <stdio.h>
+int main(int argc, char **argv) {
+  // With asan allocator this makes sure we get memory from mmap.
+  static const int kSize = 1 << 25;
+  unsigned char *x = new unsigned char[kSize];
+  printf("-");
+  for (int i = 0; i <= 32; i++) {
+    printf("%02x", x[i]);
+  }
+  printf("-\n");
+  delete [] x;
+}
+
+// CHECK: -bebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebe-
+// CHECK-10-8: -080808080808080808080000000000000000000000000000000000000000000000-
+// CHECK-20-ab: -abababababababababababababababababababab00000000000000000000000000-
diff --git a/lib/asan/lit_tests/TestCases/malloc_hook.cc b/lib/asan/lit_tests/TestCases/malloc_hook.cc
new file mode 100644
index 0000000..83be102
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/malloc_hook.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <unistd.h>
+
+extern "C" {
+bool __asan_get_ownership(const void *p);
+
+void *global_ptr;
+
+// Note: avoid calling functions that allocate memory in malloc/free
+// to avoid infinite recursion.
+void __asan_malloc_hook(void *ptr, size_t sz) {
+  if (__asan_get_ownership(ptr)) {
+    write(1, "MallocHook\n", sizeof("MallocHook\n"));
+    global_ptr = ptr;
+  }
+}
+void __asan_free_hook(void *ptr) {
+  if (__asan_get_ownership(ptr) && ptr == global_ptr)
+    write(1, "FreeHook\n", sizeof("FreeHook\n"));
+}
+}  // extern "C"
+
+int main() {
+  volatile int *x = new int;
+  // CHECK: MallocHook
+  // Check that malloc hook was called with correct argument.
+  if (global_ptr != (void*)x) {
+    _exit(1);
+  }
+  *x = 0;
+  delete x;
+  // CHECK: FreeHook
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc b/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc
new file mode 100644
index 0000000..e06a8c7
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=0 %t
+// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=1 not %t 2>&1 | FileCheck %s
+// Default to strict_memcmp=1.
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+int main() {
+  char kFoo[] = "foo";
+  char kFubar[] = "fubar";
+  int res = memcmp(kFoo, kFubar, strlen(kFubar));
+  printf("res: %d\n", res);
+  // CHECK: AddressSanitizer: stack-buffer-overflow
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/memcmp_test.cc b/lib/asan/lit_tests/TestCases/memcmp_test.cc
new file mode 100644
index 0000000..32067a9
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/memcmp_test.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <string.h>
+int main(int argc, char **argv) {
+  char a1[] = {argc, 2, 3, 4};
+  char a2[] = {1, 2*argc, 3, 4};
+  int res = memcmp(a1, a2, 4 + argc);  // BOOM
+  // CHECK: AddressSanitizer: stack-buffer-overflow
+  // CHECK: {{#0.*memcmp}}
+  // CHECK: {{#1.*main}}
+  return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/null_deref.cc b/lib/asan/lit_tests/TestCases/null_deref.cc
new file mode 100644
index 0000000..4529616
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/null_deref.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+  // CHECK: ERROR: AddressSanitizer: SEGV on unknown address
+  // CHECK:   {{0x0*00028 .*pc 0x.*}}
+  // CHECK: {{AddressSanitizer can not provide additional info.}}
+  ptr[10]++;  // BOOM
+  // atos on Mac cannot extract the symbol name correctly.
+  // CHECK-Linux: {{    #0 0x.* in NullDeref.*null_deref.cc:}}[[@LINE-2]]
+  // CHECK-Darwin: {{    #0 0x.* in .*NullDeref.*null_deref.cc:}}[[@LINE-3]]
+}
+int main() {
+  NullDeref((int*)0);
+  // CHECK: {{    #1 0x.* in main.*null_deref.cc:}}[[@LINE-1]]
+}
diff --git a/lib/asan/lit_tests/on_error_callback.cc b/lib/asan/lit_tests/TestCases/on_error_callback.cc
similarity index 79%
rename from lib/asan/lit_tests/on_error_callback.cc
rename to lib/asan/lit_tests/TestCases/on_error_callback.cc
index bb94d9f..d0cec2e 100644
--- a/lib/asan/lit_tests/on_error_callback.cc
+++ b/lib/asan/lit_tests/TestCases/on_error_callback.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/lib/asan/lit_tests/TestCases/partial_right.cc b/lib/asan/lit_tests/TestCases/partial_right.cc
new file mode 100644
index 0000000..a000a91
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/partial_right.cc
@@ -0,0 +1,13 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+int main(int argc, char **argv) {
+  volatile int *x = (int*)malloc(2*sizeof(int) + 2);
+  int res = x[2];  // BOOOM
+  // CHECK: {{READ of size 4 at 0x.* thread T0}}
+  // CHECK: [[ADDR:0x[01-9a-fa-f]+]] is located 0 bytes to the right of {{.*}}-byte region [{{.*}},{{.*}}[[ADDR]])
+  return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/readv.cc b/lib/asan/lit_tests/TestCases/readv.cc
new file mode 100644
index 0000000..ba17505
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/readv.cc
@@ -0,0 +1,32 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %t
+// RUN: %clangxx_asan -O0 %s -DPOSITIVE -o %t && not %t 2>&1 | FileCheck %s
+
+// Test the readv() interceptor.
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+#include <time.h>
+
+int main() {
+  char buf[2011];
+  struct iovec iov[2];
+#ifdef POSITIVE
+  char * volatile buf_ = buf;
+  iov[0].iov_base = buf_ - 1;
+#else
+  iov[0].iov_base = buf + 1;
+#endif
+  iov[0].iov_len = 5;
+  iov[1].iov_base = buf + 10;
+  iov[1].iov_len = 2000;
+  int fd = open("/etc/hosts", O_RDONLY);
+  assert(fd > 0);
+  readv(fd, iov, 2);
+  // CHECK: WRITE of size 5 at
+  close(fd);
+  return 0;
+}
diff --git a/lib/asan/lit_tests/sanity_check_pure_c.c b/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c
similarity index 65%
rename from lib/asan/lit_tests/sanity_check_pure_c.c
rename to lib/asan/lit_tests/TestCases/sanity_check_pure_c.c
index 3d83065..df15067 100644
--- a/lib/asan/lit_tests/sanity_check_pure_c.c
+++ b/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c
@@ -1,10 +1,10 @@
 // Sanity checking a test in pure C.
-// RUN: %clang -g -fsanitize=address -O2 %s -o %t
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
 
 // Sanity checking a test in pure C with -pie.
-// RUN: %clang -g -fsanitize=address -O2 %s -pie -o %t
-// RUN: %t 2>&1 | %symbolize | FileCheck %s
+// RUN: %clang_asan -O2 %s -pie -o %t
+// RUN: not %t 2>&1 | FileCheck %s
 
 #include <stdlib.h>
 int main() {
diff --git a/lib/asan/lit_tests/TestCases/shared-lib-test.cc b/lib/asan/lit_tests/TestCases/shared-lib-test.cc
new file mode 100644
index 0000000..126903a
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/shared-lib-test.cc
@@ -0,0 +1,42 @@
+// RUN: %clangxx_asan -O0 %p/SharedLibs/shared-lib-test-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %p/SharedLibs/shared-lib-test-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %p/SharedLibs/shared-lib-test-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %p/SharedLibs/shared-lib-test-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+
+using std::string;
+
+typedef void (fun_t)(int x);
+
+int main(int argc, char *argv[]) {
+  string path = string(argv[0]) + "-so.so";
+  printf("opening %s ... \n", path.c_str());
+  void *lib = dlopen(path.c_str(), RTLD_NOW);
+  if (!lib) {
+    printf("error in dlopen(): %s\n", dlerror());
+    return 1;
+  }
+  fun_t *inc = (fun_t*)dlsym(lib, "inc");
+  if (!inc) return 1;
+  printf("ok\n");
+  inc(1);
+  inc(-1);  // BOOM
+  // CHECK: {{.*ERROR: AddressSanitizer: global-buffer-overflow}}
+  // CHECK: {{READ of size 4 at 0x.* thread T0}}
+  // CHECK: {{    #0 0x.*}}
+  // CHECK: {{    #1 0x.* in main .*shared-lib-test.cc:}}[[@LINE-4]]
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/sleep_before_dying.c b/lib/asan/lit_tests/TestCases/sleep_before_dying.c
new file mode 100644
index 0000000..8dee9f2
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/sleep_before_dying.c
@@ -0,0 +1,10 @@
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: ASAN_OPTIONS="sleep_before_dying=1" not %t 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+  // CHECK: Sleeping for 1 second
+}
diff --git a/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc b/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc
new file mode 100644
index 0000000..2b83ecc
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <string.h>
+
+namespace XXX {
+struct YYY {
+  static int ZZZ(int x) {
+    char array[10];
+    memset(array, 0, 10);
+    return array[x];  // BOOOM
+    // CHECK: ERROR: AddressSanitizer: stack-buffer-overflow
+    // CHECK: READ of size 1 at
+    // CHECK: is located in stack of thread T0 at offset
+    // CHECK: XXX::YYY::ZZZ
+  }
+};
+}  // namespace XXX
+
+int main(int argc, char **argv) {
+  int res = XXX::YYY::ZZZ(argc + 10);
+  return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/stack-oob-frames.cc b/lib/asan/lit_tests/TestCases/stack-oob-frames.cc
new file mode 100644
index 0000000..909e700
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/stack-oob-frames.cc
@@ -0,0 +1,59 @@
+// RUN: %clangxx_asan -O1 %s -o %t
+// RUN: not %t 0 2>&1 | FileCheck %s --check-prefix=CHECK0
+// RUN: not %t 1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: not %t 2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: not %t 3 2>&1 | FileCheck %s --check-prefix=CHECK3
+
+#define NOINLINE __attribute__((noinline))
+inline void break_optimization(void *arg) {
+  __asm__ __volatile__("" : : "r" (arg) : "memory");
+}
+
+NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
+  char s[4] = {0};
+  char *d = s;
+  break_optimization(&d);
+  switch (frame) {
+    case 3: a[5]++; break;
+    case 2: b[5]++; break;
+    case 1: c[5]++; break;
+    case 0: d[5]++; break;
+  }
+}
+NOINLINE static void Frame1(int frame, char *a, char *b) {
+  char c[4] = {0}; Frame0(frame, a, b, c);
+  break_optimization(0);
+}
+NOINLINE static void Frame2(int frame, char *a) {
+  char b[4] = {0}; Frame1(frame, a, b);
+  break_optimization(0);
+}
+NOINLINE static void Frame3(int frame) {
+  char a[4] = {0}; Frame2(frame, a);
+  break_optimization(0);
+}
+
+int main(int argc, char **argv) {
+  if (argc != 2) return 1;
+  Frame3(argv[1][0] - '0');
+}
+
+// CHECK0: AddressSanitizer: stack-buffer-overflow
+// CHECK0: #0{{.*}}Frame0
+// CHECK0: #1{{.*}}Frame1
+// CHECK0: #2{{.*}}Frame2
+// CHECK0: #3{{.*}}Frame3
+// CHECK0: is located in stack of thread T0 at offset
+// CHECK0-NEXT: #0{{.*}}Frame0
+//
+// CHECK1: AddressSanitizer: stack-buffer-overflow
+// CHECK1: is located in stack of thread T0 at offset
+// CHECK1-NEXT: #0{{.*}}Frame1
+//
+// CHECK2: AddressSanitizer: stack-buffer-overflow
+// CHECK2: is located in stack of thread T0 at offset
+// CHECK2-NEXT: #0{{.*}}Frame2
+//
+// CHECK3: AddressSanitizer: stack-buffer-overflow
+// CHECK3: is located in stack of thread T0 at offset
+// CHECK3-NEXT: #0{{.*}}Frame3
diff --git a/lib/asan/lit_tests/TestCases/stack-overflow.cc b/lib/asan/lit_tests/TestCases/stack-overflow.cc
new file mode 100644
index 0000000..adf1c07
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/stack-overflow.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <string.h>
+int main(int argc, char **argv) {
+  char x[10];
+  memset(x, 0, 10);
+  int res = x[argc * 10];  // BOOOM
+  // CHECK: {{READ of size 1 at 0x.* thread T0}}
+  // CHECK: {{    #0 0x.* in main .*stack-overflow.cc:}}[[@LINE-2]]
+  // CHECK: {{Address 0x.* is located in stack of thread T0 at offset}}
+  // CHECK-NEXT: in{{.*}}main{{.*}}stack-overflow.cc
+  return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/stack-use-after-return.cc b/lib/asan/lit_tests/TestCases/stack-use-after-return.cc
new file mode 100644
index 0000000..8064ffd
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/stack-use-after-return.cc
@@ -0,0 +1,37 @@
+// XFAIL: *
+// RUN: %clangxx_asan -fsanitize=use-after-return -O0 %s -o %t && \
+// RUN:   %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -fsanitize=use-after-return -O1 %s -o %t && \
+// RUN:   %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -fsanitize=use-after-return -O2 %s -o %t && \
+// RUN:   %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -fsanitize=use-after-return -O3 %s -o %t && \
+// RUN:   %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+
+__attribute__((noinline))
+char *Ident(char *x) {
+  fprintf(stderr, "1: %p\n", x);
+  return x;
+}
+
+__attribute__((noinline))
+char *Func1() {
+  char local;
+  return Ident(&local);
+}
+
+__attribute__((noinline))
+void Func2(char *x) {
+  fprintf(stderr, "2: %p\n", x);
+  *x = 1;
+  // CHECK: WRITE of size 1 {{.*}} thread T0
+  // CHECK:     #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-2]]
+  // CHECK: is located {{.*}} in frame <{{.*}}Func1{{.*}}> of T0's stack
+}
+
+int main(int argc, char **argv) {
+  Func2(Func1());
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/strdup_oob_test.cc b/lib/asan/lit_tests/TestCases/strdup_oob_test.cc
new file mode 100644
index 0000000..e92afd3
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/strdup_oob_test.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <string.h>
+
+char kString[] = "foo";
+
+int main(int argc, char **argv) {
+  char *copy = strdup(kString);
+  int x = copy[4 + argc];  // BOOM
+  // CHECK: AddressSanitizer: heap-buffer-overflow
+  // CHECK: #0 {{.*}}main {{.*}}strdup_oob_test.cc:[[@LINE-2]]
+  // CHECK: allocated by thread T{{.*}} here:
+  // CHECK: #0 {{.*}}strdup
+  // CHECK: strdup_oob_test.cc:[[@LINE-6]]
+  return x;
+}
diff --git a/lib/asan/lit_tests/strip_path_prefix.c b/lib/asan/lit_tests/TestCases/strip_path_prefix.c
similarity index 67%
rename from lib/asan/lit_tests/strip_path_prefix.c
rename to lib/asan/lit_tests/TestCases/strip_path_prefix.c
index ef7bf98..c4d6ba4 100644
--- a/lib/asan/lit_tests/strip_path_prefix.c
+++ b/lib/asan/lit_tests/TestCases/strip_path_prefix.c
@@ -1,5 +1,5 @@
-// RUN: %clang -g -fsanitize=address -O2 %s -o %t
-// RUN: ASAN_OPTIONS="strip_path_prefix='/'" %t 2>&1 | FileCheck %s
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: ASAN_OPTIONS="strip_path_prefix='/'" not %t 2>&1 | FileCheck %s
 
 #include <stdlib.h>
 int main() {
diff --git a/lib/asan/lit_tests/TestCases/strncpy-overflow.cc b/lib/asan/lit_tests/TestCases/strncpy-overflow.cc
new file mode 100644
index 0000000..2b5f5b7
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/strncpy-overflow.cc
@@ -0,0 +1,30 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+
+#include <string.h>
+#include <stdlib.h>
+int main(int argc, char **argv) {
+  char *hello = (char*)malloc(6);
+  strcpy(hello, "hello");
+  char *short_buffer = (char*)malloc(9);
+  strncpy(short_buffer, hello, 10);  // BOOM
+  // CHECK: {{WRITE of size 10 at 0x.* thread T0}}
+  // CHECK-Linux: {{    #0 0x.* in .*strncpy}}
+  // CHECK-Darwin: {{    #0 0x.* in wrap_strncpy}}
+  // CHECK: {{    #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-4]]
+  // CHECK: {{0x.* is located 0 bytes to the right of 9-byte region}}
+  // CHECK: {{allocated by thread T0 here:}}
+
+  // CHECK-Linux: {{    #0 0x.* in .*malloc}}
+  // CHECK-Linux: {{    #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-10]]
+
+  // CHECK-Darwin: {{    #0 0x.* in wrap_malloc.*}}
+  // CHECK-Darwin: {{    #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-13]]
+  return short_buffer[8];
+}
diff --git a/lib/asan/lit_tests/symbolize_callback.cc b/lib/asan/lit_tests/TestCases/symbolize_callback.cc
similarity index 82%
rename from lib/asan/lit_tests/symbolize_callback.cc
rename to lib/asan/lit_tests/TestCases/symbolize_callback.cc
index 0691d50..058b315 100644
--- a/lib/asan/lit_tests/symbolize_callback.cc
+++ b/lib/asan/lit_tests/TestCases/symbolize_callback.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/lib/asan/lit_tests/throw_call_test.cc b/lib/asan/lit_tests/TestCases/throw_call_test.cc
similarity index 100%
rename from lib/asan/lit_tests/throw_call_test.cc
rename to lib/asan/lit_tests/TestCases/throw_call_test.cc
diff --git a/lib/asan/lit_tests/throw_invoke_test.cc b/lib/asan/lit_tests/TestCases/throw_invoke_test.cc
similarity index 100%
rename from lib/asan/lit_tests/throw_invoke_test.cc
rename to lib/asan/lit_tests/TestCases/throw_invoke_test.cc
diff --git a/lib/asan/lit_tests/TestCases/time_interceptor.cc b/lib/asan/lit_tests/TestCases/time_interceptor.cc
new file mode 100644
index 0000000..3be00d6
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/time_interceptor.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+
+// Test the time() interceptor.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+int main() {
+  time_t *tm = (time_t*)malloc(sizeof(time_t));
+  free(tm);
+  time_t t = time(tm);
+  printf("Time: %s\n", ctime(&t));  // NOLINT
+  // CHECK: use-after-free
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc b/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc
new file mode 100644
index 0000000..d50566c
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc
@@ -0,0 +1,52 @@
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %t A 2>&1 | FileCheck --check-prefix=CHECK-A %s
+// RUN: not %t B 2>&1 | FileCheck --check-prefix=CHECK-B %s
+// RUN: not %t C 2>&1 | FileCheck --check-prefix=CHECK-C %s
+// RUN: not %t D 2>&1 | FileCheck --check-prefix=CHECK-D %s
+// RUN: not %t E 2>&1 | FileCheck --check-prefix=CHECK-E %s
+
+// RUN: not %t K 2>&1 | FileCheck --check-prefix=CHECK-K %s
+// RUN: not %t L 2>&1 | FileCheck --check-prefix=CHECK-L %s
+// RUN: not %t M 2>&1 | FileCheck --check-prefix=CHECK-M %s
+// RUN: not %t N 2>&1 | FileCheck --check-prefix=CHECK-N %s
+// RUN: not %t O 2>&1 | FileCheck --check-prefix=CHECK-O %s
+
+#include <sanitizer/asan_interface.h>
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+  if (argc != 2) return 1;
+  char *x = new char[16];
+  memset(x, 0xab, 16);
+  int res = 1;
+  switch (argv[1][0]) {
+    case 'A': res = __sanitizer_unaligned_load16(x + 15); break;
+//  CHECK-A ERROR: AddressSanitizer: heap-buffer-overflow on address
+//  CHECK-A: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]]
+//  CHECK-A: is located 0 bytes to the right of 16-byte region
+    case 'B': res = __sanitizer_unaligned_load32(x + 14); break;
+//  CHECK-B: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+    case 'C': res = __sanitizer_unaligned_load32(x + 13); break;
+//  CHECK-C: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+    case 'D': res = __sanitizer_unaligned_load64(x + 15); break;
+//  CHECK-D: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+    case 'E': res = __sanitizer_unaligned_load64(x + 9); break;
+//  CHECK-E: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+
+    case 'K': __sanitizer_unaligned_store16(x + 15, 0); break;
+//  CHECK-K ERROR: AddressSanitizer: heap-buffer-overflow on address
+//  CHECK-K: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]]
+//  CHECK-K: is located 0 bytes to the right of 16-byte region
+    case 'L': __sanitizer_unaligned_store32(x + 15, 0); break;
+//  CHECK-L: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+    case 'M': __sanitizer_unaligned_store32(x + 13, 0); break;
+//  CHECK-M: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+    case 'N': __sanitizer_unaligned_store64(x + 10, 0); break;
+//  CHECK-N: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+    case 'O': __sanitizer_unaligned_store64(x + 14, 0); break;
+//  CHECK-O: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+  }
+  delete x;
+  return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/use-after-free-right.cc b/lib/asan/lit_tests/TestCases/use-after-free-right.cc
new file mode 100644
index 0000000..ceb7a19
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-free-right.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+
+// Test use-after-free report in the case when access is at the right border of
+//  the allocation.
+
+#include <stdlib.h>
+int main() {
+  volatile char *x = (char*)malloc(sizeof(char));
+  free((void*)x);
+  *x = 42;
+  // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
+  // CHECK:   {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
+  // CHECK: {{WRITE of size 1 at 0x.* thread T0}}
+  // CHECK: {{    #0 0x.* in main .*use-after-free-right.cc:17}}
+  // CHECK: {{0x.* is located 0 bytes inside of 1-byte region .0x.*,0x.*}}
+  // CHECK: {{freed by thread T0 here:}}
+
+  // CHECK-Linux: {{    #0 0x.* in .*free}}
+  // CHECK-Linux: {{    #1 0x.* in main .*use-after-free-right.cc:16}}
+
+  // CHECK-Darwin: {{    #0 0x.* in wrap_free}}
+  // CHECK-Darwin: {{    #1 0x.* in main .*use-after-free-right.cc:16}}
+
+  // CHECK: {{previously allocated by thread T0 here:}}
+
+  // CHECK-Linux: {{    #0 0x.* in .*malloc}}
+  // CHECK-Linux: {{    #1 0x.* in main .*use-after-free-right.cc:15}}
+
+  // CHECK-Darwin: {{    #0 0x.* in wrap_malloc.*}}
+  // CHECK-Darwin: {{    #1 0x.* in main .*use-after-free-right.cc:15}}
+}
diff --git a/lib/asan/lit_tests/TestCases/use-after-free.cc b/lib/asan/lit_tests/TestCases/use-after-free.cc
new file mode 100644
index 0000000..cad2819
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-free.cc
@@ -0,0 +1,35 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>%t.out
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+  // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
+  // CHECK:   {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
+  // CHECK: {{READ of size 1 at 0x.* thread T0}}
+  // CHECK: {{    #0 0x.* in main .*use-after-free.cc:14}}
+  // CHECK: {{0x.* is located 5 bytes inside of 10-byte region .0x.*,0x.*}}
+  // CHECK: {{freed by thread T0 here:}}
+
+  // CHECK-Linux: {{    #0 0x.* in .*free}}
+  // CHECK-Linux: {{    #1 0x.* in main .*use-after-free.cc:13}}
+
+  // CHECK-Darwin: {{    #0 0x.* in wrap_free}}
+  // CHECK-Darwin: {{    #1 0x.* in main .*use-after-free.cc:13}}
+
+  // CHECK: {{previously allocated by thread T0 here:}}
+
+  // CHECK-Linux: {{    #0 0x.* in .*malloc}}
+  // CHECK-Linux: {{    #1 0x.* in main .*use-after-free.cc:12}}
+
+  // CHECK-Darwin: {{    #0 0x.* in wrap_malloc.*}}
+  // CHECK-Darwin: {{    #1 0x.* in main .*use-after-free.cc:12}}
+}
diff --git a/lib/asan/lit_tests/TestCases/use-after-poison.cc b/lib/asan/lit_tests/TestCases/use-after-poison.cc
new file mode 100644
index 0000000..e3bc6ec
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-poison.cc
@@ -0,0 +1,20 @@
+// Check that __asan_poison_memory_region works.
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+//
+// Check that we can disable it
+// RUN: ASAN_OPTIONS=allow_user_poisoning=0 %t
+
+#include <stdlib.h>
+
+extern "C" void __asan_poison_memory_region(void *, size_t);
+
+int main(int argc, char **argv) {
+  char *x = new char[16];
+  x[10] = 0;
+  __asan_poison_memory_region(x, 16);
+  int res = x[argc * 10];  // BOOOM
+  // CHECK: ERROR: AddressSanitizer: use-after-poison
+  // CHECK: main{{.*}}use-after-poison.cc:[[@LINE-2]]
+  delete [] x;
+  return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc b/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc
new file mode 100644
index 0000000..32fa6ad
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc
@@ -0,0 +1,25 @@
+// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
+// RUN:     not %t 2>&1 | FileCheck %s
+#include <stdio.h>
+
+struct IntHolder {
+  explicit IntHolder(int *val = 0) : val_(val) { }
+  ~IntHolder() {
+    printf("Value: %d\n", *val_);  // BOOM
+    // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+    // CHECK:  #0 0x{{.*}} in IntHolder::~IntHolder{{.*}}use-after-scope-dtor-order.cc:[[@LINE-2]]
+  }
+  void set(int *val) { val_ = val; }
+  int *get() { return val_; }
+
+  int *val_;
+};
+
+int main(int argc, char *argv[]) {
+  // It is incorrect to use "x" int IntHolder destructor, because "x" is
+  // "destroyed" earlier as it's declared later.
+  IntHolder holder;
+  int x = argc;
+  holder.set(&x);
+  return 0;
+}
diff --git a/lib/asan/lit_tests/use-after-scope-inlined.cc b/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc
similarity index 61%
rename from lib/asan/lit_tests/use-after-scope-inlined.cc
rename to lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc
index 3d730de..0bad048 100644
--- a/lib/asan/lit_tests/use-after-scope-inlined.cc
+++ b/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc
@@ -2,10 +2,7 @@
 // happens. "always_inline" is not enough, as Clang doesn't emit
 // llvm.lifetime intrinsics at -O0.
 //
-// RUN: %clangxx_asan -m64 -O2 -fsanitize=use-after-scope %s -o %t && \
-// RUN:     %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 -fsanitize=use-after-scope %s -o %t && \
-// RUN:     %t 2>&1 | %symbolize | FileCheck %s
+// RUN: %clangxx_asan -O2 -fsanitize=use-after-scope %s -o %t && not %t 2>&1 | FileCheck %s
 
 int *arr;
 
@@ -21,9 +18,10 @@
   return arr[argc - 1];  // BOOM
   // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
   // CHECK: READ of size 4 at 0x{{.*}} thread T0
-  // CHECK:   #0 0x{{.*}} in {{_?}}main
+  // CHECK:   #0 0x{{.*}} in main
   // CHECK:      {{.*}}use-after-scope-inlined.cc:[[@LINE-4]]
-  // CHECK: Address 0x{{.*}} is located at offset
-  // CHECK:      [[OFFSET:[^ ]*]] in frame <main> of T0{{.*}}:
+  // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset
+  // CHECK:      [[OFFSET:[^ ]*]] in frame
+  // CHECK: main
   // CHECK:   {{\[}}[[OFFSET]], {{.*}}) 'x.i'
 }
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc b/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc
new file mode 100644
index 0000000..c23acf7
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc
@@ -0,0 +1,14 @@
+// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && %t
+
+#include <stdio.h>
+
+int main() {
+  int *p = 0;
+  // Variable goes in and out of scope.
+  for (int i = 0; i < 3; i++) {
+    int x = 0;
+    p = &x;
+  }
+  printf("PASSED\n");
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc b/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc
new file mode 100644
index 0000000..13d714f
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
+// RUN:     %t 2>&1 | FileCheck %s
+//
+// Lifetime for temporaries is not emitted yet.
+// XFAIL: *
+
+#include <stdio.h>
+
+struct IntHolder {
+  explicit IntHolder(int val) : val(val) {
+    printf("IntHolder: %d\n", val);
+  }
+  int val;
+};
+
+const IntHolder *saved;
+
+void save(const IntHolder &holder) {
+  saved = &holder;
+}
+
+int main(int argc, char *argv[]) {
+  save(IntHolder(10));
+  int x = saved->val;  // BOOM
+  // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+  // CHECK:  #0 0x{{.*}} in main {{.*}}use-after-scope-temp.cc:[[@LINE-2]]
+  printf("saved value: %d\n", x);
+  return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/use-after-scope.cc b/lib/asan/lit_tests/TestCases/use-after-scope.cc
new file mode 100644
index 0000000..4afe0bb
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/use-after-scope.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
+// RUN:     not %t 2>&1 | FileCheck %s
+
+int main() {
+  int *p = 0;
+  {
+    int x = 0;
+    p = &x;
+  }
+  return *p;  // BOOM
+  // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+  // CHECK:  #0 0x{{.*}} in main {{.*}}use-after-scope.cc:[[@LINE-2]]
+  // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame
+  // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x'
+}
diff --git a/lib/asan/lit_tests/TestCases/wait.cc b/lib/asan/lit_tests/TestCases/wait.cc
new file mode 100644
index 0000000..b5580dc
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/wait.cc
@@ -0,0 +1,63 @@
+// RUN: %clangxx_asan -DWAIT -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -DWAITPID -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAITPID -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -DWAITID -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAITID -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -DWAIT3 -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT3 -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -DWAIT4 -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT4 -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -DWAIT3_RUSAGE -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT3_RUSAGE -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -DWAIT4_RUSAGE -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT4_RUSAGE -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+
+#include <assert.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+  pid_t pid = fork();
+  if (pid) { // parent
+    int x[3];
+    int *status = x + argc * 3;
+    int res;
+#if defined(WAIT)
+    res = wait(status);
+#elif defined(WAITPID)
+    res = waitpid(pid, status, WNOHANG);
+#elif defined(WAITID)
+    siginfo_t *si = (siginfo_t*)(x + argc * 3);
+    res = waitid(P_ALL, 0, si, WEXITED | WNOHANG);
+#elif defined(WAIT3)
+    res = wait3(status, WNOHANG, NULL);
+#elif defined(WAIT4)
+    res = wait4(pid, status, WNOHANG, NULL);
+#elif defined(WAIT3_RUSAGE) || defined(WAIT4_RUSAGE)
+    struct rusage *ru = (struct rusage*)(x + argc * 3);
+    int good_status;
+# if defined(WAIT3_RUSAGE)
+    res = wait3(&good_status, WNOHANG, ru);
+# elif defined(WAIT4_RUSAGE)
+    res = wait4(pid, &good_status, WNOHANG, ru);
+# endif
+#endif
+    // CHECK: stack-buffer-overflow
+    // CHECK: {{WRITE of size .* at 0x.* thread T0}}
+    // CHECK: {{in .*wait}}
+    // CHECK: {{in main .*wait.cc:}}
+    // CHECK: is located in stack of thread T0 at offset
+    // CHECK: {{in main}}
+    return res != -1;
+  }
+  // child
+  return 0;
+}
diff --git a/lib/asan/lit_tests/Unit/lit.cfg b/lib/asan/lit_tests/Unit/lit.cfg
deleted file mode 100644
index 243eb7f..0000000
--- a/lib/asan/lit_tests/Unit/lit.cfg
+++ /dev/null
@@ -1,27 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
-  attr_value = getattr(config, attr_name, None)
-  if not attr_value:
-    lit.fatal("No attribute %r in test configuration! You may need to run "
-              "tests from your build directory or add this attribute "
-              "to lit.site.cfg " % attr_name)
-  return attr_value
-
-# Setup attributes common for all compiler-rt projects.
-llvm_src_root = get_required_attr(config, 'llvm_src_root')
-compiler_rt_lit_unit_cfg = os.path.join(llvm_src_root, "projects",
-                                        "compiler-rt", "lib",
-                                        "lit.common.unit.cfg")
-lit.load_config(config, compiler_rt_lit_unit_cfg)
-
-# Setup config name.
-config.name = 'AddressSanitizer-Unit'
-
-# Setup test source and exec root. For unit tests, we define
-# it as build directory with ASan unit tests.
-asan_binary_dir = get_required_attr(config, "asan_binary_dir")
-config.test_exec_root = os.path.join(asan_binary_dir, "tests")
-config.test_source_root = config.test_exec_root
diff --git a/lib/asan/lit_tests/Unit/lit.site.cfg.in b/lib/asan/lit_tests/Unit/lit.site.cfg.in
index 07584a6..6864c80 100644
--- a/lib/asan/lit_tests/Unit/lit.site.cfg.in
+++ b/lib/asan/lit_tests/Unit/lit.site.cfg.in
@@ -1,16 +1,13 @@
 ## Autogenerated by LLVM/Clang configuration.
 # Do not edit!
 
-config.target_triple = "@TARGET_TRIPLE@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.llvm_build_mode = "@LLVM_BUILD_MODE@"
-config.asan_binary_dir = "@ASAN_BINARY_DIR@"
+# Load common config for all compiler-rt unit tests.
+lit.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
 
-try:
-  config.llvm_build_mode = config.llvm_build_mode % lit.params
-except KeyError,e:
-  key, = e.args
-  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
+# Setup config name.
+config.name = 'AddressSanitizer-Unit'
 
-# Let the main config do the real work.
-lit.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/Unit/lit.cfg")
+# Setup test source and exec root. For unit tests, we define
+# it as build directory with ASan unit tests.
+config.test_exec_root = "@ASAN_BINARY_DIR@/tests"
+config.test_source_root = config.test_exec_root
diff --git a/lib/asan/lit_tests/blacklist.cc b/lib/asan/lit_tests/blacklist.cc
deleted file mode 100644
index 6cfc150..0000000
--- a/lib/asan/lit_tests/blacklist.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Test the blacklist functionality of ASan
-
-// RUN: echo "fun:*brokenFunction*" > %tmp
-// RUN: echo "global:*badGlobal*" >> %tmp
-// RUN: echo "src:*blacklist-extra.cc" >> %tmp
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m64 -O0 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m64 -O1 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m64 -O2 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m64 -O3 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O0 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O1 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O2 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O3 %s -o %t \
-// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1
-
-// badGlobal is accessed improperly, but we blacklisted it.
-int badGlobal;
-int readBadGlobal() {
-  return (&badGlobal)[1];
-}
-
-// A function which is broken, but excluded in the blacklist.
-int brokenFunction(int argc) {
-  char x[10] = {0};
-  return x[argc * 10];  // BOOM
-}
-
-// This function is defined in Helpers/blacklist-extra.cc, a source file which
-// is blacklisted by name
-int externalBrokenFunction(int x);
-
-int main(int argc, char **argv) {
-  brokenFunction(argc);
-  int x = readBadGlobal();
-  externalBrokenFunction(argc);
-  return 0;
-}
diff --git a/lib/asan/lit_tests/deep_tail_call.cc b/lib/asan/lit_tests/deep_tail_call.cc
deleted file mode 100644
index 6aa15e8..0000000
--- a/lib/asan/lit_tests/deep_tail_call.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-// CHECK: AddressSanitizer: global-buffer-overflow
-int global[10];
-// CHECK: {{#0.*call4}}
-void __attribute__((noinline)) call4(int i) { global[i+10]++; }
-// CHECK: {{#1.*call3}}
-void __attribute__((noinline)) call3(int i) { call4(i); }
-// CHECK: {{#2.*call2}}
-void __attribute__((noinline)) call2(int i) { call3(i); }
-// CHECK: {{#3.*call1}}
-void __attribute__((noinline)) call1(int i) { call2(i); }
-// CHECK: {{#4.*main}}
-int main(int argc, char **argv) {
-  call1(argc);
-  return global[0];
-}
diff --git a/lib/asan/lit_tests/dlclose-test.cc b/lib/asan/lit_tests/dlclose-test.cc
deleted file mode 100644
index 229f508..0000000
--- a/lib/asan/lit_tests/dlclose-test.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Regression test for
-// http://code.google.com/p/address-sanitizer/issues/detail?id=19
-// Bug description:
-// 1. application dlopens foo.so
-// 2. asan registers all globals from foo.so
-// 3. application dlcloses foo.so
-// 4. application mmaps some memory to the location where foo.so was before
-// 5. application starts using this mmaped memory, but asan still thinks there
-// are globals.
-// 6. BOOM
-
-// RUN: %clangxx_asan -m64 -O0 %p/SharedLibs/dlclose-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %p/SharedLibs/dlclose-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %p/SharedLibs/dlclose-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %p/SharedLibs/dlclose-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %p/SharedLibs/dlclose-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %p/SharedLibs/dlclose-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %p/SharedLibs/dlclose-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %p/SharedLibs/dlclose-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s
-
-#include <assert.h>
-#include <dlfcn.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/mman.h>
-
-#include <string>
-
-using std::string;
-
-static const int kPageSize = 4096;
-
-typedef int *(fun_t)();
-
-int main(int argc, char *argv[]) {
-  string path = string(argv[0]) + "-so.so";
-  printf("opening %s ... \n", path.c_str());
-  void *lib = dlopen(path.c_str(), RTLD_NOW);
-  if (!lib) {
-    printf("error in dlopen(): %s\n", dlerror());
-    return 1;
-  }
-  fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var");
-  if (!get) {
-    printf("failed dlsym\n");
-    return 1;
-  }
-  int *addr = get();
-  assert(((size_t)addr % 32) == 0);  // should be 32-byte aligned.
-  printf("addr: %p\n", addr);
-  addr[0] = 1;  // make sure we can write there.
-
-  // Now dlclose the shared library.
-  printf("attempting to dlclose\n");
-  if (dlclose(lib)) {
-    printf("failed to dlclose\n");
-    return 1;
-  }
-  // Now, the page where 'addr' is unmapped. Map it.
-  size_t page_beg = ((size_t)addr) & ~(kPageSize - 1);
-  void *res = mmap((void*)(page_beg), kPageSize,
-                   PROT_READ | PROT_WRITE,
-                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
-  if (res == (char*)-1L) {
-    printf("failed to mmap\n");
-    return 1;
-  }
-  addr[1] = 2;  // BOOM (if the bug is not fixed).
-  printf("PASS\n");
-  // CHECK: PASS
-  return 0;
-}
diff --git a/lib/asan/lit_tests/global-overflow.cc b/lib/asan/lit_tests/global-overflow.cc
deleted file mode 100644
index 6a2f12e..0000000
--- a/lib/asan/lit_tests/global-overflow.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-#include <string.h>
-int main(int argc, char **argv) {
-  static char XXX[10];
-  static char YYY[10];
-  static char ZZZ[10];
-  memset(XXX, 0, 10);
-  memset(YYY, 0, 10);
-  memset(ZZZ, 0, 10);
-  int res = YYY[argc * 10];  // BOOOM
-  // CHECK: {{READ of size 1 at 0x.* thread T0}}
-  // CHECK: {{    #0 0x.* in _?main .*global-overflow.cc:}}[[@LINE-2]]
-  // CHECK: {{0x.* is located 0 bytes to the right of global variable}}
-  // CHECK:   {{.*YYY.* of size 10}}
-  res += XXX[argc] + ZZZ[argc];
-  return res;
-}
diff --git a/lib/asan/lit_tests/heap-overflow.cc b/lib/asan/lit_tests/heap-overflow.cc
deleted file mode 100644
index f1d719c..0000000
--- a/lib/asan/lit_tests/heap-overflow.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-#include <stdlib.h>
-#include <string.h>
-int main(int argc, char **argv) {
-  char *x = (char*)malloc(10 * sizeof(char));
-  memset(x, 0, 10);
-  int res = x[argc * 10];  // BOOOM
-  // CHECK: {{READ of size 1 at 0x.* thread T0}}
-  // CHECK: {{    #0 0x.* in _?main .*heap-overflow.cc:}}[[@LINE-2]]
-  // CHECK: {{0x.* is located 0 bytes to the right of 10-byte region}}
-  // CHECK: {{allocated by thread T0 here:}}
-
-  // CHECK-Linux: {{    #0 0x.* in .*malloc}}
-  // CHECK-Linux: {{    #1 0x.* in main .*heap-overflow.cc:21}}
-
-  // CHECK-Darwin: {{    #0 0x.* in _?wrap_malloc.*}}
-  // CHECK-Darwin: {{    #1 0x.* in _?main .*heap-overflow.cc:21}}
-  free(x);
-  return res;
-}
diff --git a/lib/asan/lit_tests/initialization-blacklist.cc b/lib/asan/lit_tests/initialization-blacklist.cc
deleted file mode 100644
index d0f86a7..0000000
--- a/lib/asan/lit_tests/initialization-blacklist.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Test for blacklist functionality of initialization-order checker.
-
-// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN:   -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN:   -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m64 -O1 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN:   -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN:   -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m64 -O2 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN:   -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN:   -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m32 -O0 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN:   -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN:   -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m32 -O1 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN:   -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN:   -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m32 -O2 %s %p/Helpers/initialization-blacklist-extra.cc\
-// RUN:   -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \
-// RUN:   -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-
-// Function is defined in another TU.
-int readBadGlobal();
-int x = readBadGlobal();  // init-order bug.
-
-// Function is defined in another TU.
-int accessBadObject();
-int y = accessBadObject();  // init-order bug.
-
-int main(int argc, char **argv) {
-  return argc + x + y - 1;
-}
diff --git a/lib/asan/lit_tests/initialization-nobug.cc b/lib/asan/lit_tests/initialization-nobug.cc
deleted file mode 100644
index 93df993..0000000
--- a/lib/asan/lit_tests/initialization-nobug.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// A collection of various initializers which shouldn't trip up initialization
-// order checking.  If successful, this will just return 0.
-
-// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/initialization-nobug-extra.cc\
-// RUN:   --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m64 -O1 %s %p/Helpers/initialization-nobug-extra.cc\
-// RUN:   --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m64 -O2 %s %p/Helpers/initialization-nobug-extra.cc\
-// RUN:   --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m64 -O3 %s %p/Helpers/initialization-nobug-extra.cc\
-// RUN:   --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m32 -O0 %s %p/Helpers/initialization-nobug-extra.cc\
-// RUN:   --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m32 -O0 %s %p/Helpers/initialization-nobug-extra.cc\
-// RUN:   --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m32 -O1 %s %p/Helpers/initialization-nobug-extra.cc\
-// RUN:   --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m32 -O2 %s %p/Helpers/initialization-nobug-extra.cc\
-// RUN:   --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-// RUN: %clangxx_asan -m32 -O3 %s %p/Helpers/initialization-nobug-extra.cc\
-// RUN:   --std=c++11 -fsanitize=init-order -o %t
-// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1
-
-// Simple access:
-// Make sure that accessing a global in the same TU is safe
-
-bool condition = true;
-int initializeSameTU() {
-  return condition ? 0x2a : 052;
-}
-int sameTU = initializeSameTU();
-
-// Linker initialized:
-// Check that access to linker initialized globals originating from a different
-// TU's initializer is safe.
-
-int A = (1 << 1) + (1 << 3) + (1 << 5), B;
-int getAB() {
-  return A * B;
-}
-
-// Function local statics:
-// Check that access to function local statics originating from a different
-// TU's initializer is safe.
-
-int countCalls() {
-  static int calls;
-  return ++calls;
-}
-
-// Constexpr:
-// We need to check that a global variable initialized with a constexpr
-// constructor can be accessed during dynamic initialization (as a constexpr
-// constructor implies that it was initialized during constant initialization,
-// not dynamic initialization).
-
-class Integer {
-  private:
-  int value;
-
-  public:
-  constexpr Integer(int x = 0) : value(x) {}
-  int getValue() {return value;}
-};
-Integer coolestInteger(42);
-int getCoolestInteger() { return coolestInteger.getValue(); }
-
-int main() { return 0; }
diff --git a/lib/asan/lit_tests/interface_test.cc b/lib/asan/lit_tests/interface_test.cc
deleted file mode 100644
index 428a109..0000000
--- a/lib/asan/lit_tests/interface_test.cc
+++ /dev/null
@@ -1,8 +0,0 @@
-// Check that user may include ASan interface header.
-// RUN: %clang -fsanitize=address -I %p/../../../include %s -o %t && %t
-// RUN: %clang -I %p/../../../include %s -o %t && %t
-#include <sanitizer/asan_interface.h>
-
-int main() {
-  return 0;
-}
diff --git a/lib/asan/lit_tests/large_func_test.cc b/lib/asan/lit_tests/large_func_test.cc
deleted file mode 100644
index ceecc29..0000000
--- a/lib/asan/lit_tests/large_func_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-#include <stdlib.h>
-__attribute__((noinline))
-static void LargeFunction(int *x, int zero) {
-  x[0]++;
-  x[1]++;
-  x[2]++;
-  x[3]++;
-  x[4]++;
-  x[5]++;
-  x[6]++;
-  x[7]++;
-  x[8]++;
-  x[9]++;
-
-  // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
-  // CHECK:   {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
-  // CHECK: {{READ of size 4 at 0x.* thread T0}}
-  x[zero + 103]++;  // we should report this exact line
-  // atos incorrectly extracts the symbol name for the static functions on
-  // Darwin.
-  // CHECK-Linux:  {{#0 0x.* in LargeFunction.*large_func_test.cc:}}[[@LINE-3]]
-  // CHECK-Darwin: {{#0 0x.* in .*LargeFunction.*large_func_test.cc}}:[[@LINE-4]]
-
-  x[10]++;
-  x[11]++;
-  x[12]++;
-  x[13]++;
-  x[14]++;
-  x[15]++;
-  x[16]++;
-  x[17]++;
-  x[18]++;
-  x[19]++;
-}
-
-int main(int argc, char **argv) {
-  int *x = new int[100];
-  LargeFunction(x, argc - 1);
-  // CHECK: {{    #1 0x.* in _?main .*large_func_test.cc:}}[[@LINE-1]]
-  // CHECK: {{0x.* is located 12 bytes to the right of 400-byte region}}
-  // CHECK: {{allocated by thread T0 here:}}
-  // CHECK-Linux: {{    #0 0x.* in operator new.*}}
-  // CHECK-Darwin: {{    #0 0x.* in .*_Zna.*}}
-  // CHECK: {{    #1 0x.* in _?main .*large_func_test.cc:}}[[@LINE-7]]
-  delete x;
-}
diff --git a/lib/asan/lit_tests/lit.cfg b/lib/asan/lit_tests/lit.cfg
index 7875281..815452d 100644
--- a/lib/asan/lit_tests/lit.cfg
+++ b/lib/asan/lit_tests/lit.cfg
@@ -2,8 +2,16 @@
 
 import os
 
+def get_required_attr(config, attr_name):
+  attr_value = getattr(config, attr_name, None)
+  if not attr_value:
+    lit.fatal("No attribute %r in test configuration! You may need to run "
+              "tests from your build directory or add this attribute "
+              "to lit.site.cfg " % attr_name)
+  return attr_value
+
 # Setup config name.
-config.name = 'AddressSanitizer'
+config.name = 'AddressSanitizer' + config.bits
 
 # Setup source root.
 config.test_source_root = os.path.dirname(__file__)
@@ -30,14 +38,6 @@
   if not llvm_config:
     DisplayNoConfigMessage()
 
-  # Validate that llvm-config points to the same source tree.
-  llvm_src_root = lit.util.capture(["llvm-config", "--src-root"]).strip()
-  asan_test_src_root = os.path.join(llvm_src_root, "projects", "compiler-rt",
-                                    "lib", "asan", "lit_tests")
-  if (os.path.realpath(asan_test_src_root) !=
-      os.path.realpath(config.test_source_root)):
-    DisplayNoConfigMessage()
-
   # Find out the presumed location of generated site config.
   llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
   asan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
@@ -48,47 +48,40 @@
   lit.load_config(config, asan_site_cfg)
   raise SystemExit
 
-# Setup attributes common for all compiler-rt projects.
-compiler_rt_lit_cfg = os.path.join(llvm_src_root, "projects", "compiler-rt",
-                                   "lib", "lit.common.cfg")
-if (not compiler_rt_lit_cfg) or (not os.path.exists(compiler_rt_lit_cfg)):
-  lit.fatal("Can't find common compiler-rt lit config at: %r"
-            % compiler_rt_lit_cfg)
-lit.load_config(config, compiler_rt_lit_cfg)
-
 # Setup default compiler flags used with -fsanitize=address option.
 # FIXME: Review the set of required flags and check if it can be reduced.
-clang_asan_cxxflags = ("-ccc-cxx "
-                      + "-fsanitize=address "
-                      + "-mno-omit-leaf-frame-pointer "
-                      + "-fno-omit-frame-pointer "
-                      + "-fno-optimize-sibling-calls "
-                      + "-g")
+bits_cflag = " -m" + config.bits
+clang_asan_cflags = (" -fsanitize=address"
+                   + " -mno-omit-leaf-frame-pointer"
+                   + " -fno-omit-frame-pointer"
+                   + " -fno-optimize-sibling-calls"
+                   + " -g"
+                   + bits_cflag)
+clang_asan_cxxflags = " --driver-mode=g++" + clang_asan_cflags
+config.substitutions.append( ("%clang ", " " + config.clang + bits_cflag + " "))
+config.substitutions.append( ("%clangxx ", (" " + config.clang +
+                                            " --driver-mode=g++" +
+                                            bits_cflag + " ")) )
+config.substitutions.append( ("%clang_asan ", (" " + config.clang + " " +
+                                              clang_asan_cflags + " ")) )
 config.substitutions.append( ("%clangxx_asan ", (" " + config.clang + " " +
                                                 clang_asan_cxxflags + " ")) )
 
 # Setup path to external LLVM symbolizer to run AddressSanitizer output tests.
-llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
-if llvm_tools_dir:
-  config.environment['LLVM_SYMBOLIZER_PATH'] = os.path.join(
-      llvm_tools_dir, "llvm-symbolizer")
+config.environment['ASAN_SYMBOLIZER_PATH'] = config.llvm_symbolizer_path
 
-# Setup path to symbolizer script.
-# FIXME: Instead we should copy this script to the build tree and point
-#        at it there.
-asan_source_dir = os.path.join(config.test_source_root, "..")
-symbolizer = os.path.join(asan_source_dir,
-                         'scripts', 'asan_symbolize.py')
-if not os.path.exists(symbolizer):
-  lit.fatal("Can't find symbolizer script on path %r" % symbolizer)
-# Define %symbolize substitution that filters output through
-# symbolizer and c++filt (for demangling).
-config.substitutions.append( ("%symbolize ", (" " + symbolizer +
-                                              " | c++filt " )))
+# Setup path to asan_symbolize.py script.
+asan_source_dir = get_required_attr(config, "asan_source_dir")
+asan_symbolize = os.path.join(asan_source_dir, "scripts", "asan_symbolize.py")
+if not os.path.exists(asan_symbolize):
+  lit.fatal("Can't find script on path %r" % asan_symbolize)
+config.substitutions.append( ("%asan_symbolize", " " + asan_symbolize + " ") )
 
 # Define CHECK-%os to check for OS-dependent output.
 config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
 
+config.available_features.add("asan-" + config.bits + "-bits")
+
 # Default test suffixes.
 config.suffixes = ['.c', '.cc', '.cpp']
 
diff --git a/lib/asan/lit_tests/lit.site.cfg.in b/lib/asan/lit_tests/lit.site.cfg.in
deleted file mode 100644
index cf43930..0000000
--- a/lib/asan/lit_tests/lit.site.cfg.in
+++ /dev/null
@@ -1,20 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-config.target_triple = "@TARGET_TRIPLE@"
-config.host_os = "@HOST_OS@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.llvm_obj_root = "@LLVM_BINARY_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.clang = "@LLVM_BINARY_DIR@/bin/clang"
-
-# LLVM tools dir can be passed in lit parameters, so try to
-# apply substitution.
-try:
-  config.llvm_tools_dir = config.llvm_tools_dir % lit.params
-except KeyError,e:
-  key, = e.args
-  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Let the main config do the real work.
-lit.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg")
diff --git a/lib/asan/lit_tests/malloc_hook.cc b/lib/asan/lit_tests/malloc_hook.cc
deleted file mode 100644
index 6435d10..0000000
--- a/lib/asan/lit_tests/malloc_hook.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: %t 2>&1 | FileCheck %s
-#include <stdlib.h>
-#include <unistd.h>
-
-extern "C" {
-// Note: avoid calling functions that allocate memory in malloc/free
-// to avoid infinite recursion.
-void __asan_malloc_hook(void *ptr, size_t sz) {
-  write(1, "MallocHook\n", sizeof("MallocHook\n"));
-}
-void __asan_free_hook(void *ptr) {
-  write(1, "FreeHook\n", sizeof("FreeHook\n"));
-}
-}  // extern "C"
-
-int main() {
-  volatile int *x = new int;
-  // CHECK: MallocHook
-  *x = 0;
-  delete x;
-  // CHECK: FreeHook
-  return 0;
-}
diff --git a/lib/asan/lit_tests/memcmp_strict_test.cc b/lib/asan/lit_tests/memcmp_strict_test.cc
deleted file mode 100644
index 00bf921..0000000
--- a/lib/asan/lit_tests/memcmp_strict_test.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-nonstrict
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-strict
-// Default to strict_memcmp=1.
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-strict
-
-#include <stdio.h>
-#include <string.h>
-int main() {
-  char kFoo[] = "foo";
-  char kFubar[] = "fubar";
-  int res = memcmp(kFoo, kFubar, strlen(kFubar));
-  printf("res: %d\n", res);
-  // CHECK-nonstrict: {{res: -1}}
-  // CHECK-strict: AddressSanitizer: stack-buffer-overflow
-  return 0;
-}
diff --git a/lib/asan/lit_tests/memcmp_test.cc b/lib/asan/lit_tests/memcmp_test.cc
deleted file mode 100644
index ac3f7f3..0000000
--- a/lib/asan/lit_tests/memcmp_test.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-#include <string.h>
-int main(int argc, char **argv) {
-  char a1[] = {argc, 2, 3, 4};
-  char a2[] = {1, 2*argc, 3, 4};
-  int res = memcmp(a1, a2, 4 + argc);  // BOOM
-  // CHECK: AddressSanitizer: stack-buffer-overflow
-  // CHECK: {{#0.*memcmp}}
-  // CHECK: {{#1.*main}}
-  return res;
-}
diff --git a/lib/asan/lit_tests/null_deref.cc b/lib/asan/lit_tests/null_deref.cc
deleted file mode 100644
index 60a521d..0000000
--- a/lib/asan/lit_tests/null_deref.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-__attribute__((noinline))
-static void NullDeref(int *ptr) {
-  // CHECK: ERROR: AddressSanitizer: SEGV on unknown address
-  // CHECK:   {{0x0*00028 .*pc 0x.*}}
-  // CHECK: {{AddressSanitizer can not provide additional info.}}
-  ptr[10]++;  // BOOM
-  // atos on Mac cannot extract the symbol name correctly.
-  // CHECK-Linux: {{    #0 0x.* in NullDeref.*null_deref.cc:}}[[@LINE-2]]
-  // CHECK-Darwin: {{    #0 0x.* in .*NullDeref.*null_deref.cc:}}[[@LINE-3]]
-}
-int main() {
-  NullDeref((int*)0);
-  // CHECK: {{    #1 0x.* in _?main.*null_deref.cc:}}[[@LINE-1]]
-}
diff --git a/lib/asan/lit_tests/partial_right.cc b/lib/asan/lit_tests/partial_right.cc
deleted file mode 100644
index c579262..0000000
--- a/lib/asan/lit_tests/partial_right.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-#include <stdlib.h>
-int main(int argc, char **argv) {
-  volatile int *x = (int*)malloc(2*sizeof(int) + 2);
-  int res = x[2];  // BOOOM
-  // CHECK: {{READ of size 4 at 0x.* thread T0}}
-  // CHECK: [[ADDR:0x[01-9a-fa-f]+]] is located 0 bytes to the right of {{.*}}-byte region [{{.*}},{{.*}}[[ADDR]])
-  return res;
-}
diff --git a/lib/asan/lit_tests/shared-lib-test.cc b/lib/asan/lit_tests/shared-lib-test.cc
deleted file mode 100644
index 05bf3ec..0000000
--- a/lib/asan/lit_tests/shared-lib-test.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %p/SharedLibs/shared-lib-test-so.cc \
-// RUN:     -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-#include <dlfcn.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <string>
-
-using std::string;
-
-typedef void (fun_t)(int x);
-
-int main(int argc, char *argv[]) {
-  string path = string(argv[0]) + "-so.so";
-  printf("opening %s ... \n", path.c_str());
-  void *lib = dlopen(path.c_str(), RTLD_NOW);
-  if (!lib) {
-    printf("error in dlopen(): %s\n", dlerror());
-    return 1;
-  }
-  fun_t *inc = (fun_t*)dlsym(lib, "inc");
-  if (!inc) return 1;
-  printf("ok\n");
-  inc(1);
-  inc(-1);  // BOOM
-  // CHECK: {{.*ERROR: AddressSanitizer: global-buffer-overflow}}
-  // CHECK: {{READ of size 4 at 0x.* thread T0}}
-  // CHECK: {{    #0 0x.*}}
-  // CHECK: {{    #1 0x.* in _?main .*shared-lib-test.cc:}}[[@LINE-4]]
-  return 0;
-}
diff --git a/lib/asan/lit_tests/sleep_before_dying.c b/lib/asan/lit_tests/sleep_before_dying.c
deleted file mode 100644
index df9eba2..0000000
--- a/lib/asan/lit_tests/sleep_before_dying.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang -g -fsanitize=address -O2 %s -o %t
-// RUN: ASAN_OPTIONS="sleep_before_dying=1" %t 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-int main() {
-  char *x = (char*)malloc(10 * sizeof(char));
-  free(x);
-  return x[5];
-  // CHECK: Sleeping for 1 second
-}
diff --git a/lib/asan/lit_tests/stack-frame-demangle.cc b/lib/asan/lit_tests/stack-frame-demangle.cc
deleted file mode 100644
index a0de4bb..0000000
--- a/lib/asan/lit_tests/stack-frame-demangle.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Check that ASan is able to print demangled frame name even w/o
-// symbolization.
-
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
-
-#include <string.h>
-
-namespace XXX {
-struct YYY {
-  static int ZZZ(int x) {
-    char array[10];
-    memset(array, 0, 10);
-    return array[x];  // BOOOM
-    // CHECK: {{ERROR: AddressSanitizer: stack-buffer-overflow}}
-    // CHECK: {{READ of size 1 at 0x.* thread T0}}
-    // CHECK: {{Address 0x.* is .* frame <XXX::YYY::ZZZ(.*)>}}
-  }
-};
-}  // namespace XXX
-
-int main(int argc, char **argv) {
-  int res = XXX::YYY::ZZZ(argc + 10);
-  return res;
-}
diff --git a/lib/asan/lit_tests/stack-overflow.cc b/lib/asan/lit_tests/stack-overflow.cc
deleted file mode 100644
index 3deb1e9..0000000
--- a/lib/asan/lit_tests/stack-overflow.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
-
-#include <string.h>
-int main(int argc, char **argv) {
-  char x[10];
-  memset(x, 0, 10);
-  int res = x[argc * 10];  // BOOOM
-  // CHECK: {{READ of size 1 at 0x.* thread T0}}
-  // CHECK: {{    #0 0x.* in _?main .*stack-overflow.cc:}}[[@LINE-2]]
-  // CHECK: {{Address 0x.* is .* frame <main>}}
-  return res;
-}
diff --git a/lib/asan/lit_tests/stack-use-after-return.cc b/lib/asan/lit_tests/stack-use-after-return.cc
deleted file mode 100644
index f8d8a1a..0000000
--- a/lib/asan/lit_tests/stack-use-after-return.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// XFAIL: *
-// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O0 %s -o %t && \
-// RUN:   %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O1 %s -o %t && \
-// RUN:   %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O2 %s -o %t && \
-// RUN:   %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O3 %s -o %t && \
-// RUN:   %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O0 %s -o %t && \
-// RUN:   %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O1 %s -o %t && \
-// RUN:   %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O2 %s -o %t && \
-// RUN:   %t 2>&1 | %symbolize | FileCheck %s
-// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O3 %s -o %t && \
-// RUN:   %t 2>&1 | %symbolize | FileCheck %s
-
-#include <stdio.h>
-
-__attribute__((noinline))
-char *Ident(char *x) {
-  fprintf(stderr, "1: %p\n", x);
-  return x;
-}
-
-__attribute__((noinline))
-char *Func1() {
-  char local;
-  return Ident(&local);
-}
-
-__attribute__((noinline))
-void Func2(char *x) {
-  fprintf(stderr, "2: %p\n", x);
-  *x = 1;
-  // CHECK: WRITE of size 1 {{.*}} thread T0
-  // CHECK:     #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-2]]
-  // CHECK: is located {{.*}} in frame <{{.*}}Func1{{.*}}> of T0's stack
-}
-
-int main(int argc, char **argv) {
-  Func2(Func1());
-  return 0;
-}
diff --git a/lib/asan/lit_tests/strncpy-overflow.cc b/lib/asan/lit_tests/strncpy-overflow.cc
deleted file mode 100644
index 5133b5c..0000000
--- a/lib/asan/lit_tests/strncpy-overflow.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-#include <string.h>
-#include <stdlib.h>
-int main(int argc, char **argv) {
-  char *hello = (char*)malloc(6);
-  strcpy(hello, "hello");
-  char *short_buffer = (char*)malloc(9);
-  strncpy(short_buffer, hello, 10);  // BOOM
-  // CHECK: {{WRITE of size 10 at 0x.* thread T0}}
-  // CHECK-Linux: {{    #0 0x.* in .*strncpy}}
-  // CHECK-Darwin: {{    #0 0x.* in _?wrap_strncpy}}
-  // CHECK: {{    #1 0x.* in _?main .*strncpy-overflow.cc:}}[[@LINE-4]]
-  // CHECK: {{0x.* is located 0 bytes to the right of 9-byte region}}
-  // CHECK: {{allocated by thread T0 here:}}
-
-  // CHECK-Linux: {{    #0 0x.* in .*malloc}}
-  // CHECK-Linux: {{    #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-10]]
-
-  // CHECK-Darwin: {{    #0 0x.* in _?wrap_malloc.*}}
-  // CHECK-Darwin: {{    #1 0x.* in _?main .*strncpy-overflow.cc:}}[[@LINE-13]]
-  return short_buffer[8];
-}
diff --git a/lib/asan/lit_tests/use-after-free-right.cc b/lib/asan/lit_tests/use-after-free-right.cc
deleted file mode 100644
index b0de07b..0000000
--- a/lib/asan/lit_tests/use-after-free-right.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-// Test use-after-free report in the case when access is at the right border of
-//  the allocation.
-
-#include <stdlib.h>
-int main() {
-  volatile char *x = (char*)malloc(sizeof(char));
-  free((void*)x);
-  *x = 42;
-  // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
-  // CHECK:   {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
-  // CHECK: {{WRITE of size 1 at 0x.* thread T0}}
-  // CHECK: {{    #0 0x.* in _?main .*use-after-free-right.cc:25}}
-  // CHECK: {{0x.* is located 0 bytes inside of 1-byte region .0x.*,0x.*}}
-  // CHECK: {{freed by thread T0 here:}}
-
-  // CHECK-Linux: {{    #0 0x.* in .*free}}
-  // CHECK-Linux: {{    #1 0x.* in main .*use-after-free-right.cc:24}}
-
-  // CHECK-Darwin: {{    #0 0x.* in _?wrap_free}}
-  // CHECK-Darwin: {{    #1 0x.* in _?main .*use-after-free-right.cc:24}}
-
-  // CHECK: {{previously allocated by thread T0 here:}}
-
-  // CHECK-Linux: {{    #0 0x.* in .*malloc}}
-  // CHECK-Linux: {{    #1 0x.* in main .*use-after-free-right.cc:23}}
-
-  // CHECK-Darwin: {{    #0 0x.* in _?wrap_malloc.*}}
-  // CHECK-Darwin: {{    #1 0x.* in _?main .*use-after-free-right.cc:23}}
-}
diff --git a/lib/asan/lit_tests/use-after-free.cc b/lib/asan/lit_tests/use-after-free.cc
deleted file mode 100644
index aee185d..0000000
--- a/lib/asan/lit_tests/use-after-free.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
-// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
-
-#include <stdlib.h>
-int main() {
-  char *x = (char*)malloc(10 * sizeof(char));
-  free(x);
-  return x[5];
-  // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
-  // CHECK:   {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
-  // CHECK: {{READ of size 1 at 0x.* thread T0}}
-  // CHECK: {{    #0 0x.* in _?main .*use-after-free.cc:22}}
-  // CHECK: {{0x.* is located 5 bytes inside of 10-byte region .0x.*,0x.*}}
-  // CHECK: {{freed by thread T0 here:}}
-
-  // CHECK-Linux: {{    #0 0x.* in .*free}}
-  // CHECK-Linux: {{    #1 0x.* in main .*use-after-free.cc:21}}
-
-  // CHECK-Darwin: {{    #0 0x.* in _?wrap_free}}
-  // CHECK-Darwin: {{    #1 0x.* in _?main .*use-after-free.cc:21}}
-
-  // CHECK: {{previously allocated by thread T0 here:}}
-
-  // CHECK-Linux: {{    #0 0x.* in .*malloc}}
-  // CHECK-Linux: {{    #1 0x.* in main .*use-after-free.cc:20}}
-
-  // CHECK-Darwin: {{    #0 0x.* in _?wrap_malloc.*}}
-  // CHECK-Darwin: {{    #1 0x.* in _?main .*use-after-free.cc:20}}
-}
diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py
index bd3bf1e..3571468 100755
--- a/lib/asan/scripts/asan_symbolize.py
+++ b/lib/asan/scripts/asan_symbolize.py
@@ -10,14 +10,14 @@
 import bisect
 import getopt
 import os
+import pty
 import re
 import subprocess
 import sys
+import termios
 
 llvm_symbolizer = None
 symbolizers = {}
-filetypes = {}
-vmaddrs = {}
 DEBUG = False
 demangle = False;
 
@@ -137,6 +137,36 @@
     return ['%s in %s %s' % (addr, function_name, file_name)]
 
 
+class UnbufferedLineConverter(object):
+  """
+  Wrap a child process that responds to each line of input with one line of
+  output.  Uses pty to trick the child into providing unbuffered output.
+  """
+  def __init__(self, args, close_stderr=False):
+    pid, fd = pty.fork()
+    if pid == 0:
+      # We're the child. Transfer control to command.
+      if close_stderr:
+        dev_null = os.open('/dev/null', 0)
+        os.dup2(dev_null, 2)
+      os.execvp(args[0], args)
+    else:
+      # Disable echoing.
+      attr = termios.tcgetattr(fd)
+      attr[3] = attr[3] & ~termios.ECHO
+      termios.tcsetattr(fd, termios.TCSANOW, attr)
+      # Set up a file()-like interface to the child process
+      self.r = os.fdopen(fd, "r", 1)
+      self.w = os.fdopen(os.dup(fd), "w", 1)
+
+  def convert(self, line):
+    self.w.write(line + "\n")
+    return self.readline()
+
+  def readline(self):
+    return self.r.readline().rstrip()
+
+
 class DarwinSymbolizer(Symbolizer):
   def __init__(self, addr, binary):
     super(DarwinSymbolizer, self).__init__()
@@ -146,29 +176,21 @@
       self.arch = 'x86_64'
     else:
       self.arch = 'i386'
-    self.vmaddr = None
-    self.pipe = None
-
-  def write_addr_to_pipe(self, offset):
-    print >> self.pipe.stdin, '0x%x' % int(offset, 16)
+    self.open_atos()
 
   def open_atos(self):
     if DEBUG:
       print 'atos -o %s -arch %s' % (self.binary, self.arch)
     cmdline = ['atos', '-o', self.binary, '-arch', self.arch]
-    self.pipe = subprocess.Popen(cmdline,
-                                 stdin=subprocess.PIPE,
-                                 stdout=subprocess.PIPE,
-                                 stderr=subprocess.PIPE)
+    self.atos = UnbufferedLineConverter(cmdline, close_stderr=True)
 
   def symbolize(self, addr, binary, offset):
     """Overrides Symbolizer.symbolize."""
     if self.binary != binary:
       return None
-    self.open_atos()
-    self.write_addr_to_pipe(offset)
-    self.pipe.stdin.close()
-    atos_line = self.pipe.stdout.readline().rstrip()
+    atos_line = self.atos.convert('0x%x' % int(offset, 16))
+    while "got symbolicator for" in atos_line:
+      atos_line = self.atos.readline()
     # A well-formed atos response looks like this:
     #   foo(type1, type2) (in object.name) (filename.cc:80)
     match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line)
@@ -331,7 +353,10 @@
 
   def process_stdin(self):
     self.frame_no = 0
-    for line in sys.stdin:
+    while True:
+      line = sys.stdin.readline()
+      if not line:
+        break
       self.current_line = line.rstrip()
       #0 0x7f6e35cf2e45  (/blah/foo.so+0x11fe45)
       stack_trace_line_format = (
diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc
index 1681842..cab3783 100644
--- a/lib/asan/tests/asan_noinst_test.cc
+++ b/lib/asan/tests/asan_noinst_test.cc
@@ -15,7 +15,6 @@
 #include "asan_allocator.h"
 #include "asan_internal.h"
 #include "asan_mapping.h"
-#include "asan_stack.h"
 #include "asan_test_utils.h"
 
 #include <assert.h>
@@ -33,17 +32,17 @@
 
 static void MallocStress(size_t n) {
   u32 seed = my_rand();
-  __asan::StackTrace stack1;
+  StackTrace stack1;
   stack1.trace[0] = 0xa123;
   stack1.trace[1] = 0xa456;
   stack1.size = 2;
 
-  __asan::StackTrace stack2;
+  StackTrace stack2;
   stack2.trace[0] = 0xb123;
   stack2.trace[1] = 0xb456;
   stack2.size = 2;
 
-  __asan::StackTrace stack3;
+  StackTrace stack3;
   stack3.trace[0] = 0xc123;
   stack3.trace[1] = 0xc456;
   stack3.size = 2;
@@ -67,6 +66,7 @@
       size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1);
       char *ptr = (char*)__asan::asan_memalign(alignment, size,
                                                &stack2, __asan::FROM_MALLOC);
+      EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, &stack2));
       vec.push_back(ptr);
       ptr[0] = 0;
       ptr[size-1] = 0;
@@ -216,16 +216,16 @@
 
   for (size_t iter = 0; iter < n_iter; iter++) {
     std::random_shuffle(pc_array, pc_array + kNumPcs);
-    __asan::StackTrace stack0, stack1;
+    StackTrace stack0, stack1;
     stack0.CopyFrom(pc_array, kNumPcs);
     stack0.size = std::max((size_t)1, (size_t)(my_rand_r(&seed) % stack0.size));
     size_t compress_size =
       std::max((size_t)2, (size_t)my_rand_r(&seed) % (2 * kNumPcs));
     size_t n_frames =
-      __asan::StackTrace::CompressStack(&stack0, compressed, compress_size);
+      StackTrace::CompressStack(&stack0, compressed, compress_size);
     Ident(n_frames);
     assert(n_frames <= stack0.size);
-    __asan::StackTrace::UncompressStack(&stack1, compressed, compress_size);
+    StackTrace::UncompressStack(&stack1, compressed, compress_size);
     assert(stack1.size == n_frames);
     for (size_t i = 0; i < stack1.size; i++) {
       assert(stack0.trace[i] == stack1.trace[i]);
@@ -242,13 +242,13 @@
   u32 compressed[2 * kNumPcs];
   std::random_shuffle(pc_array, pc_array + kNumPcs);
 
-  __asan::StackTrace stack0;
+  StackTrace stack0;
   stack0.CopyFrom(pc_array, kNumPcs);
   stack0.size = kNumPcs;
   for (size_t iter = 0; iter < n_iter; iter++) {
     size_t compress_size = kNumPcs;
     size_t n_frames =
-      __asan::StackTrace::CompressStack(&stack0, compressed, compress_size);
+      StackTrace::CompressStack(&stack0, compressed, compress_size);
     Ident(n_frames);
   }
 }
@@ -258,7 +258,7 @@
 }
 
 TEST(AddressSanitizer, QuarantineTest) {
-  __asan::StackTrace stack;
+  StackTrace stack;
   stack.trace[0] = 0x890;
   stack.size = 1;
 
@@ -279,7 +279,7 @@
 void *ThreadedQuarantineTestWorker(void *unused) {
   (void)unused;
   u32 seed = my_rand();
-  __asan::StackTrace stack;
+  StackTrace stack;
   stack.trace[0] = 0x890;
   stack.size = 1;
 
@@ -306,7 +306,7 @@
 
 void *ThreadedOneSizeMallocStress(void *unused) {
   (void)unused;
-  __asan::StackTrace stack;
+  StackTrace stack;
   stack.trace[0] = 0x890;
   stack.size = 1;
   const size_t kNumMallocs = 1000;
@@ -348,11 +348,7 @@
 }
 
 TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
-#if ASAN_ALLOCATOR_VERSION == 1
-  EXPECT_EQ(1U, __asan_get_estimated_allocated_size(0));
-#elif ASAN_ALLOCATOR_VERSION == 2
   EXPECT_EQ(0U, __asan_get_estimated_allocated_size(0));
-#endif
   const size_t sizes[] = { 1, 30, 1<<30 };
   for (size_t i = 0; i < 3; i++) {
     EXPECT_EQ(sizes[i], __asan_get_estimated_allocated_size(sizes[i]));
@@ -426,39 +422,6 @@
   delete Ident(x);
 }
 
-#if ASAN_ALLOCATOR_VERSION == 1
-// This test is run in a separate process, so that large malloced
-// chunk won't remain in the free lists after the test.
-// Note: use ASSERT_* instead of EXPECT_* here.
-static void RunGetHeapSizeTestAndDie() {
-  size_t old_heap_size, new_heap_size, heap_growth;
-  // We unlikely have have chunk of this size in free list.
-  static const size_t kLargeMallocSize = 1 << 29;  // 512M
-  old_heap_size = __asan_get_heap_size();
-  fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
-  free(Ident(malloc(kLargeMallocSize)));
-  new_heap_size = __asan_get_heap_size();
-  heap_growth = new_heap_size - old_heap_size;
-  fprintf(stderr, "heap growth after first malloc: %zu\n", heap_growth);
-  ASSERT_GE(heap_growth, kLargeMallocSize);
-  ASSERT_LE(heap_growth, 2 * kLargeMallocSize);
-
-  // Now large chunk should fall into free list, and can be
-  // allocated without increasing heap size.
-  old_heap_size = new_heap_size;
-  free(Ident(malloc(kLargeMallocSize)));
-  heap_growth = __asan_get_heap_size() - old_heap_size;
-  fprintf(stderr, "heap growth after second malloc: %zu\n", heap_growth);
-  ASSERT_LT(heap_growth, kLargeMallocSize);
-
-  // Test passed. Now die with expected double-free.
-  DoDoubleFree();
-}
-
-TEST(AddressSanitizerInterface, GetHeapSizeTest) {
-  EXPECT_DEATH(RunGetHeapSizeTestAndDie(), "double-free");
-}
-#elif ASAN_ALLOCATOR_VERSION == 2
 TEST(AddressSanitizerInterface, GetHeapSizeTest) {
   // asan_allocator2 does not keep huge chunks in free list, but unmaps them.
   // The chunk should be greater than the quarantine size,
@@ -472,55 +435,6 @@
     EXPECT_EQ(old_heap_size, __asan_get_heap_size());
   }
 }
-#endif
-
-// Note: use ASSERT_* instead of EXPECT_* here.
-static void DoLargeMallocForGetFreeBytesTestAndDie() {
-#if ASAN_ALLOCATOR_VERSION == 1
-  // asan_allocator2 does not keep large chunks in free_lists, so this test
-  // will not work.
-  size_t old_free_bytes, new_free_bytes;
-  static const size_t kLargeMallocSize = 1 << 29;  // 512M
-  // If we malloc and free a large memory chunk, it will not fall
-  // into quarantine and will be available for future requests.
-  old_free_bytes = __asan_get_free_bytes();
-  fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
-  fprintf(stderr, "free bytes before malloc: %zu\n", old_free_bytes);
-  free(Ident(malloc(kLargeMallocSize)));
-  new_free_bytes = __asan_get_free_bytes();
-  fprintf(stderr, "free bytes after malloc and free: %zu\n", new_free_bytes);
-  ASSERT_GE(new_free_bytes, old_free_bytes + kLargeMallocSize);
-#endif  // ASAN_ALLOCATOR_VERSION
-  // Test passed.
-  DoDoubleFree();
-}
-
-TEST(AddressSanitizerInterface, GetFreeBytesTest) {
-#if ASAN_ALLOCATOR_VERSION == 1
-  // Allocate a small chunk. Now allocator probably has a lot of these
-  // chunks to fulfill future requests. So, future requests will decrease
-  // the number of free bytes. Do this only on systems where there
-  // is enough memory for such assumptions.
-  if (SANITIZER_WORDSIZE == 64 && !ASAN_LOW_MEMORY) {
-    static const size_t kNumOfChunks = 100;
-    static const size_t kChunkSize = 100;
-    char *chunks[kNumOfChunks];
-    size_t i;
-    size_t old_free_bytes, new_free_bytes;
-    chunks[0] = Ident((char*)malloc(kChunkSize));
-    old_free_bytes = __asan_get_free_bytes();
-    for (i = 1; i < kNumOfChunks; i++) {
-      chunks[i] = Ident((char*)malloc(kChunkSize));
-      new_free_bytes = __asan_get_free_bytes();
-      EXPECT_LT(new_free_bytes, old_free_bytes);
-      old_free_bytes = new_free_bytes;
-    }
-    for (i = 0; i < kNumOfChunks; i++)
-      free(chunks[i]);
-  }
-#endif
-  EXPECT_DEATH(DoLargeMallocForGetFreeBytesTestAndDie(), "double-free");
-}
 
 static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
 static const size_t kManyThreadsIterations = 250;
@@ -828,12 +742,7 @@
 TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
   std::vector<char *> pointers;
   std::vector<size_t> sizes;
-#if ASAN_ALLOCATOR_VERSION == 1
-  const size_t kNumMallocs =
-      (SANITIZER_WORDSIZE <= 32 || ASAN_LOW_MEMORY) ? 1 << 10 : 1 << 14;
-#elif ASAN_ALLOCATOR_VERSION == 2  // too slow with asan_allocator2. :(
   const size_t kNumMallocs = 1 << 9;
-#endif
   for (size_t i = 0; i < kNumMallocs; i++) {
     size_t size = i * 100 + 1;
     pointers.push_back((char*)malloc(size));
diff --git a/lib/asan/tests/asan_oob_test.cc b/lib/asan/tests/asan_oob_test.cc
index dbe272c..f8343f1 100644
--- a/lib/asan/tests/asan_oob_test.cc
+++ b/lib/asan/tests/asan_oob_test.cc
@@ -99,7 +99,6 @@
   }
 }
 
-#if ASAN_ALLOCATOR_VERSION == 2  // Broken with the asan_allocator1
 TEST(AddressSanitizer, LargeOOBRightTest) {
   size_t large_power_of_two = 1 << 19;
   for (size_t i = 16; i <= 256; i *= 2) {
@@ -109,7 +108,6 @@
     delete [] p;
   }
 }
-#endif  // ASAN_ALLOCATOR_VERSION == 2
 
 TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
   oob_test<U1>(10, -1);
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 96df29e..c87e6da 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -173,8 +173,8 @@
 TEST(AddressSanitizer, UAF_long_double) {
   if (sizeof(long double) == sizeof(double)) return;
   long double *p = Ident(new long double[10]);
-  EXPECT_DEATH(Ident(p)[12] = 0, "WRITE of size 10");
-  EXPECT_DEATH(Ident(p)[0] = Ident(p)[12], "READ of size 10");
+  EXPECT_DEATH(Ident(p)[12] = 0, "WRITE of size 1[06]");
+  EXPECT_DEATH(Ident(p)[0] = Ident(p)[12], "READ of size 1[06]");
   delete [] Ident(p);
 }
 
@@ -227,16 +227,26 @@
   delete Ident(x);
 }
 
+static size_t kOOMAllocationSize =
+  SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000);
+
 TEST(AddressSanitizer, OutOfMemoryTest) {
-  size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000);
-  EXPECT_EQ(0, realloc(0, size));
+  EXPECT_EQ(0, realloc(0, kOOMAllocationSize));
   EXPECT_EQ(0, realloc(0, ~Ident(0)));
-  EXPECT_EQ(0, malloc(size));
+  EXPECT_EQ(0, malloc(kOOMAllocationSize));
   EXPECT_EQ(0, malloc(~Ident(0)));
-  EXPECT_EQ(0, calloc(1, size));
+  EXPECT_EQ(0, calloc(1, kOOMAllocationSize));
   EXPECT_EQ(0, calloc(1, ~Ident(0)));
 }
 
+TEST(AddressSanitizer, BadReallocTest) {
+  int *a = (int*)Ident(malloc(100));
+  a[0] = 42;
+  EXPECT_EQ(0, realloc(a, kOOMAllocationSize));
+  EXPECT_EQ(42, a[0]);
+  free(a);
+}
+
 #if ASAN_NEEDS_SEGV
 namespace {
 
@@ -353,6 +363,19 @@
   free(ptr2);
 }
 
+TEST(AddressSanitizer, ReallocFreedPointerTest) {
+  void *ptr = Ident(malloc(42));
+  ASSERT_TRUE(NULL != ptr);
+  free(ptr);
+  EXPECT_DEATH(ptr = realloc(ptr, 77), "attempting double-free");
+}
+
+TEST(AddressSanitizer, ReallocInvalidPointerTest) {
+  void *ptr = Ident(malloc(42));
+  EXPECT_DEATH(ptr = realloc((int*)ptr + 1, 77), "attempting free.*not malloc");
+  free(ptr);
+}
+
 TEST(AddressSanitizer, ZeroSizeMallocTest) {
   // Test that malloc(0) and similar functions don't return NULL.
   void *ptr = Ident(malloc(0));
@@ -389,6 +412,7 @@
                kMallocUsableSizeErrorMsg);
   free(array);
   EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
+  delete int_ptr;
 }
 #endif
 
@@ -400,8 +424,10 @@
 }
 
 TEST(AddressSanitizer, WrongFreeTest) {
-  EXPECT_DEATH(WrongFree(),
-               "ERROR: AddressSanitizer: attempting free.*not malloc");
+  EXPECT_DEATH(WrongFree(), ASAN_PCRE_DOTALL
+               "ERROR: AddressSanitizer: attempting free.*not malloc"
+               ".*is located 4 bytes inside of 400-byte region"
+               ".*allocated by thread");
 }
 
 void DoubleFree() {
@@ -463,6 +489,9 @@
   EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
 }
 
+#if 0  // This test requires online symbolizer.
+// Moved to lit_tests/stack-oob-frames.cc.
+// Reenable here once we have online symbolizer by default.
 NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
   char d[4] = {0};
   char *D = Ident(d);
@@ -498,6 +527,7 @@
 TEST(AddressSanitizer, GuiltyStackFrame3Test) {
   EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3");
 }
+#endif
 
 NOINLINE void LongJmpFunc1(jmp_buf buf) {
   // create three red zones for these two stack objects.
@@ -561,7 +591,10 @@
   }
 }
 
-#if not defined(__ANDROID__)
+#if !defined(__ANDROID__) && \
+    !defined(__powerpc64__) && !defined(__powerpc__)
+// Does not work on Power:
+// https://code.google.com/p/address-sanitizer/issues/detail?id=185
 TEST(AddressSanitizer, BuiltinLongJmpTest) {
   static jmp_buf buf;
   if (!__builtin_setjmp((void**)buf)) {
@@ -868,7 +901,11 @@
 #if SANITIZER_WORDSIZE == 32
   char *addr = (char*)0x22000000;
 #else
+# if defined(__powerpc64__)
+  char *addr = (char*)0x024000800000;
+# else
   char *addr = (char*)0x0000100000080000;
+# endif
 #endif
   EXPECT_DEATH(*addr = 1, "AddressSanitizer: SEGV on unknown");
 }
@@ -1076,7 +1113,9 @@
 }
 
 // It doesn't work on Android, as calls to new/delete go through malloc/free.
-#if !defined(ANDROID) && !defined(__ANDROID__)
+// Neither it does on OS X, see
+// https://code.google.com/p/address-sanitizer/issues/detail?id=131.
+#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(__APPLE__)
 static string MismatchStr(const string &str) {
   return string("AddressSanitizer: alloc-dealloc-mismatch \\(") + str;
 }
@@ -1190,3 +1229,16 @@
   memcpy(Ident(&a), Ident(&b), sizeof(long double));
   memcpy(Ident(&c), Ident(&b), sizeof(long double));
 }
+
+TEST(AddressSanitizer, pthread_getschedparam) {
+  int policy;
+  struct sched_param param;
+  EXPECT_DEATH(
+      pthread_getschedparam(pthread_self(), &policy, Ident(&param) + 2),
+      "AddressSanitizer: stack-buffer-.*flow");
+  EXPECT_DEATH(
+      pthread_getschedparam(pthread_self(), Ident(&policy) - 1, &param),
+      "AddressSanitizer: stack-buffer-.*flow");
+  int res = pthread_getschedparam(pthread_self(), &policy, &param);
+  ASSERT_EQ(0, res);
+}
diff --git a/lib/atomic.c b/lib/atomic.c
index a291f0d..02429a6 100644
--- a/lib/atomic.c
+++ b/lib/atomic.c
@@ -30,10 +30,18 @@
 
 // Clang objects if you redefine a builtin.  This little hack allows us to
 // define a function with the same name as an intrinsic.
+#if __APPLE__
+// mach-o has extra leading underscore
+#pragma redefine_extname __atomic_load_c ___atomic_load
+#pragma redefine_extname __atomic_store_c ___atomic_store
+#pragma redefine_extname __atomic_exchange_c ___atomic_exchange
+#pragma redefine_extname __atomic_compare_exchange_c ___atomic_compare_exchange
+#else
 #pragma redefine_extname __atomic_load_c __atomic_load
 #pragma redefine_extname __atomic_store_c __atomic_store
 #pragma redefine_extname __atomic_exchange_c __atomic_exchange
 #pragma redefine_extname __atomic_compare_exchange_c __atomic_compare_exchange
+#endif
 
 /// Number of locks.  This allocates one page on 32-bit platforms, two on
 /// 64-bit.  This can be specified externally if a different trade between
@@ -70,6 +78,20 @@
 }
 /// locks for atomic operations
 static Lock locks[SPINLOCK_COUNT] = { [0 ...  SPINLOCK_COUNT-1] = {0,1,0} };
+
+#elif defined(__APPLE__)
+#include <libkern/OSAtomic.h>
+typedef OSSpinLock Lock;
+inline static void unlock(Lock *l) {
+  OSSpinLockUnlock(l);
+}
+/// Locks a lock.  In the current implementation, this is potentially
+/// unbounded in the contended case.
+inline static void lock(Lock *l) {  
+  OSSpinLockLock(l);
+}
+static Lock locks[SPINLOCK_COUNT]; // initialized to OS_SPINLOCK_INIT which is 0
+
 #else
 typedef _Atomic(uintptr_t) Lock;
 /// Unlock a lock.  This is a release operation.
diff --git a/lib/eprintf.c b/lib/eprintf.c
index b07d624..3626dbf 100644
--- a/lib/eprintf.c
+++ b/lib/eprintf.c
@@ -22,7 +22,9 @@
  * It should never be exported from a dylib, so it is marked
  * visibility hidden.
  */
+#ifndef _WIN32
 __attribute__((visibility("hidden")))
+#endif
 void __eprintf(const char* format, const char* assertion_expression,
 				const char* line, const char* file)
 {
diff --git a/lib/int_util.c b/lib/int_util.c
index 871d191..6d8922a 100644
--- a/lib/int_util.c
+++ b/lib/int_util.c
@@ -24,7 +24,9 @@
 #ifdef KERNEL_USE
 
 extern void panic(const char *, ...) __attribute__((noreturn));
+#ifndef _WIN32
 __attribute__((visibility("hidden")))
+#endif
 void compilerrt_abort_impl(const char *file, int line, const char *function) {
   panic("%s:%d: abort in %s", file, line, function);
 }
@@ -35,8 +37,10 @@
 extern void __assert_rtn(const char *func, const char *file, 
                      int line, const char * message) __attribute__((noreturn));
 
+#ifndef _WIN32
 __attribute__((weak))
 __attribute__((visibility("hidden")))
+#endif
 void compilerrt_abort_impl(const char *file, int line, const char *function) {
   __assert_rtn(function, file, line, "libcompiler_rt abort");
 }
@@ -47,8 +51,10 @@
 /* Get the system definition of abort() */
 #include <stdlib.h>
 
+#ifndef _WIN32
 __attribute__((weak))
 __attribute__((visibility("hidden")))
+#endif
 void compilerrt_abort_impl(const char *file, int line, const char *function) {
   abort();
 }
diff --git a/lib/interception/interception.h b/lib/interception/interception.h
index 2ccc903..d50af35 100644
--- a/lib/interception/interception.h
+++ b/lib/interception/interception.h
@@ -35,7 +35,8 @@
 //      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.
+//         your source file. See the notes below for cases when
+//         INTERCEPTOR_WITH_SUFFIX(...) should be used instead.
 //      2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo".
 //         INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was
 //         intercepted successfully.
@@ -58,6 +59,11 @@
 //           but instead you'll have to add
 //           DECLARE_REAL(int, foo, const char *bar, double baz) in your
 //           source file (to define a pointer to overriden function).
+//        3. Some Mac functions have symbol variants discriminated by
+//           additional suffixes, e.g. _$UNIX2003 (see
+//           https://developer.apple.com/library/mac/#releasenotes/Darwin/SymbolVariantsRelNotes/index.html
+//           for more details). To intercept such functions you need to use the
+//           INTERCEPTOR_WITH_SUFFIX(...) macro.
 
 // How it works:
 // To replace system functions on Linux we just need to declare functions
@@ -81,6 +87,7 @@
 // INTERCEPT_FUNCTION() is effectively a no-op on this system.
 
 #if defined(__APPLE__)
+#include <sys/cdefs.h>  // For __DARWIN_ALIAS_C().
 
 // Just a pair of pointers.
 struct interpose_substitution {
@@ -174,13 +181,25 @@
   extern "C" \
   INTERCEPTOR_ATTRIBUTE \
   ret_type WRAP(func)(__VA_ARGS__)
+
+// We don't need INTERCEPTOR_WITH_SUFFIX on non-Darwin for now.
+#define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \
+  INTERCEPTOR(ret_type, func, __VA_ARGS__)
+
 #else  // __APPLE__
-#define INTERCEPTOR(ret_type, func, ...) \
-  extern "C" ret_type func(__VA_ARGS__); \
+
+#define INTERCEPTOR_ZZZ(suffix, ret_type, func, ...) \
+  extern "C" ret_type func(__VA_ARGS__) suffix; \
   extern "C" ret_type WRAP(func)(__VA_ARGS__); \
   INTERPOSER(func); \
   extern "C" INTERCEPTOR_ATTRIBUTE ret_type WRAP(func)(__VA_ARGS__)
 
+#define INTERCEPTOR(ret_type, func, ...) \
+  INTERCEPTOR_ZZZ(/*no symbol variants*/, ret_type, func, __VA_ARGS__)
+
+#define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \
+  INTERCEPTOR_ZZZ(__DARWIN_ALIAS_C(func), ret_type, func, __VA_ARGS__)
+
 // Override |overridee| with |overrider|.
 #define OVERRIDE_FUNCTION(overridee, overrider) \
   INTERPOSER_2(overridee, WRAP(overrider))
diff --git a/lib/lit.common.cfg b/lib/lit.common.cfg
index 428554a..b19d687 100644
--- a/lib/lit.common.cfg
+++ b/lib/lit.common.cfg
@@ -15,8 +15,6 @@
 clang_path = getattr(config, 'clang', None)
 if (not clang_path) or (not os.path.exists(clang_path)):
   lit.fatal("Can't find Clang on path %r" % clang_path)
-if not lit.quiet:
-  lit.note("using clang: %r" % clang_path)
 
 # Clear some environment variables that might affect Clang.
 possibly_dangerous_env_vars = ['COMPILER_PATH', 'RC_DEBUG_OPTIONS',
@@ -42,13 +40,17 @@
 path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
 config.environment['PATH'] = path
 
-# Define %clang and %clangxx substitutions to use in test RUN lines.
-config.substitutions.append( ("%clang ", (" " + config.clang + " ")) )
-config.substitutions.append( ("%clangxx ", (" " + config.clang +
-                              " -ccc-cxx ")) )
+# Define path to external llvm-symbolizer tool.
+config.llvm_symbolizer_path  = os.path.join(llvm_tools_dir, "llvm-symbolizer")
 
 # Use ugly construction to explicitly prohibit "clang", "clang++" etc.
 # in RUN lines.
 config.substitutions.append(
     (' clang', """\n\n*** Do not use 'clangXXX' in tests,
      instead define '%clangXXX' substitution in lit config. ***\n\n""") )
+
+# Add supported compiler_rt architectures to a list of available features.
+compiler_rt_arch = getattr(config, 'compiler_rt_arch', None)
+if compiler_rt_arch:
+  for arch in compiler_rt_arch.split(";"):
+    config.available_features.add(arch + "-supported-target")
diff --git a/lib/lit.common.configured.in b/lib/lit.common.configured.in
new file mode 100644
index 0000000..f7c29f6
--- /dev/null
+++ b/lib/lit.common.configured.in
@@ -0,0 +1,25 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Generic config options for all compiler-rt lit tests.
+config.target_triple = "@TARGET_TRIPLE@"
+config.host_arch = "@HOST_ARCH@"
+config.host_os = "@HOST_OS@"
+config.llvm_build_mode = "@LLVM_BUILD_MODE@"
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.clang = "@LLVM_BINARY_DIR@/bin/clang"
+config.compiler_rt_arch = "@COMPILER_RT_SUPPORTED_ARCH@"
+
+# LLVM tools dir can be passed in lit parameters, so try to
+# apply substitution.
+try:
+  config.llvm_tools_dir = config.llvm_tools_dir % lit.params
+except KeyError,e:
+  key, = e.args
+  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
+
+# Setup attributes common for all compiler-rt projects.
+lit.load_config(config, "@COMPILER_RT_SOURCE_DIR@/lib/lit.common.cfg")
diff --git a/lib/lit.common.unit.configured.in b/lib/lit.common.unit.configured.in
new file mode 100644
index 0000000..1eac25b
--- /dev/null
+++ b/lib/lit.common.unit.configured.in
@@ -0,0 +1,22 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Generic config options for all compiler-rt unit tests.
+config.target_triple = "@TARGET_TRIPLE@"
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
+config.llvm_build_mode = "@LLVM_BUILD_MODE@"
+
+# LLVM tools dir and build mode can be passed in lit parameters,
+# so try to apply substitution.
+try:
+  config.llvm_tools_dir = config.llvm_tools_dir % lit.params
+  config.llvm_build_mode = config.llvm_build_mode % lit.params
+except KeyError,e:
+  key, = e.args
+  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
+
+# Setup attributes common for all compiler-rt unit tests.
+lit.load_config(config, "@COMPILER_RT_SOURCE_DIR@/lib/lit.common.unit.cfg")
diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt
new file mode 100644
index 0000000..d85f144
--- /dev/null
+++ b/lib/lsan/CMakeLists.txt
@@ -0,0 +1,56 @@
+include_directories(..)
+
+set(LSAN_CFLAGS
+  ${SANITIZER_COMMON_CFLAGS})
+
+set(LSAN_COMMON_SOURCES
+  lsan_common.cc
+  lsan_common_linux.cc)
+
+set(LSAN_SOURCES
+  lsan_interceptors.cc
+  lsan_allocator.cc
+  lsan_thread.cc
+  lsan.cc)
+
+set(LSAN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+# The common files need to build on every arch supported by ASan.
+# (Even if they build into dummy object files.)
+filter_available_targets(LSAN_COMMON_SUPPORTED_ARCH
+  x86_64 i386 powerpc64)
+
+# Architectures supported by the standalone LSan.
+filter_available_targets(LSAN_SUPPORTED_ARCH
+  x86_64)
+
+set(LSAN_RUNTIME_LIBRARIES)
+
+if(APPLE)
+  add_compiler_rt_osx_object_library(RTLSanCommon
+    ARCH ${LSAN_COMMON_SUPPORTED_ARCH}
+    SOURCES ${LSAN_COMMON_SOURCES}
+    CFLAGS ${LSAN_CFLAGS})
+elseif(NOT ANDROID)
+  foreach(arch ${LSAN_COMMON_SUPPORTED_ARCH})
+    add_compiler_rt_object_library(RTLSanCommon ${arch}
+      SOURCES ${LSAN_COMMON_SOURCES}
+      CFLAGS ${LSAN_CFLAGS})
+  endforeach()
+
+  foreach(arch ${LSAN_SUPPORTED_ARCH})
+    add_compiler_rt_static_runtime(clang_rt.lsan-${arch} ${arch}
+      SOURCES ${LSAN_SOURCES}
+              $<TARGET_OBJECTS:RTInterception.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+              $<TARGET_OBJECTS:RTLSanCommon.${arch}>
+      CFLAGS ${LSAN_CFLAGS})
+    list(APPEND LSAN_RUNTIME_LIBRARIES clang_rt.lsan-${arch})
+  endforeach()
+endif()
+
+if (LLVM_INCLUDE_TESTS)
+  add_subdirectory(tests)
+endif()
+add_subdirectory(lit_tests)
diff --git a/lib/lsan/Makefile.mk b/lib/lsan/Makefile.mk
new file mode 100644
index 0000000..aae5c32
--- /dev/null
+++ b/lib/lsan/Makefile.mk
@@ -0,0 +1,23 @@
+#===- lib/lsan/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 := lsan_common
+SubDirs := 
+
+Sources := $(foreach file,$(wildcard $(Dir)/lsan_common*.cc),$(notdir $(file)))
+ObjNames := $(Sources:%.cc=%.o)
+
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
+Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
+
+# Define a convenience variable for all the asan functions.
+LsanCommonFunctions := $(Sources:%.cc=%)
diff --git a/lib/lsan/lit_tests/AsanConfig/lit.cfg b/lib/lsan/lit_tests/AsanConfig/lit.cfg
new file mode 100644
index 0000000..eb24244
--- /dev/null
+++ b/lib/lsan/lit_tests/AsanConfig/lit.cfg
@@ -0,0 +1,27 @@
+# -*- Python -*-
+
+import os
+
+def get_required_attr(config, attr_name):
+  attr_value = getattr(config, attr_name, None)
+  if not attr_value:
+    lit.fatal("No attribute %r in test configuration! You may need to run "
+              "tests from your build directory or add this attribute "
+              "to lit.site.cfg " % attr_name)
+  return attr_value
+
+lsan_lit_src_root = get_required_attr(config, "lsan_lit_src_root")
+lsan_lit_cfg = os.path.join(lsan_lit_src_root, "lit.common.cfg")
+if not os.path.exists(lsan_lit_cfg):
+  lit.fatal("Can't find common LSan lit config at: %r" % lsan_lit_cfg)
+lit.load_config(config, lsan_lit_cfg)
+
+config.name = 'LeakSanitizer-AddressSanitizer'
+
+clang_lsan_cxxflags = config.clang_cxxflags + " -fsanitize=address "
+
+config.substitutions.append( ("%clangxx_lsan ", (" " + config.clang + " " +
+                                                clang_lsan_cxxflags + " ")) )
+
+config.environment['ASAN_OPTIONS'] = 'detect_leaks=1'
+config.environment['ASAN_SYMBOLIZER_PATH'] = config.llvm_symbolizer_path
diff --git a/lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in b/lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in
new file mode 100644
index 0000000..4557d79
--- /dev/null
+++ b/lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in
@@ -0,0 +1,8 @@
+# Load common config for all compiler-rt lit tests.
+lit.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
+
+# Tool-specific config options.
+config.lsan_lit_src_root = "@LSAN_LIT_SOURCE_DIR@"
+
+# Load tool-specific config that would do the real work.
+lit.load_config(config, "@LSAN_LIT_SOURCE_DIR@/AsanConfig/lit.cfg")
diff --git a/lib/lsan/lit_tests/CMakeLists.txt b/lib/lsan/lit_tests/CMakeLists.txt
new file mode 100644
index 0000000..526d71b
--- /dev/null
+++ b/lib/lsan/lit_tests/CMakeLists.txt
@@ -0,0 +1,37 @@
+set(LSAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
+set(LSAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..)
+
+set(LSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/LsanConfig/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/LsanConfig/lit.site.cfg
+  )
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/AsanConfig/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig/lit.site.cfg
+  )
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+  )
+
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT APPLE AND NOT ANDROID)
+  set(LSAN_TEST_DEPS
+    ${SANITIZER_COMMON_LIT_TEST_DEPS}
+    ${LSAN_RUNTIME_LIBRARIES})
+  foreach(arch ${LSAN_SUPPORTED_ARCH})
+    list(APPEND LSAN_TEST_DEPS clang_rt.asan-${arch})
+  endforeach()
+  if(LLVM_INCLUDE_TESTS)
+    list(APPEND LSAN_TEST_DEPS LsanUnitTests)
+  endif()
+  add_lit_testsuite(check-lsan "Running the LeakSanitizer tests"
+    ${CMAKE_CURRENT_BINARY_DIR}/LsanConfig
+    ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig
+    ${CMAKE_CURRENT_BINARY_DIR}/Unit
+    DEPENDS ${LSAN_TEST_DEPS})
+  set_target_properties(check-lsan PROPERTIES FOLDER "LSan tests")
+endif()
diff --git a/lib/lsan/lit_tests/LsanConfig/lit.cfg b/lib/lsan/lit_tests/LsanConfig/lit.cfg
new file mode 100644
index 0000000..bc1d548
--- /dev/null
+++ b/lib/lsan/lit_tests/LsanConfig/lit.cfg
@@ -0,0 +1,26 @@
+# -*- Python -*-
+
+import os
+
+def get_required_attr(config, attr_name):
+  attr_value = getattr(config, attr_name, None)
+  if not attr_value:
+    lit.fatal("No attribute %r in test configuration! You may need to run "
+              "tests from your build directory or add this attribute "
+              "to lit.site.cfg " % attr_name)
+  return attr_value
+
+lsan_lit_src_root = get_required_attr(config, "lsan_lit_src_root")
+lsan_lit_cfg = os.path.join(lsan_lit_src_root, "lit.common.cfg")
+if not os.path.exists(lsan_lit_cfg):
+  lit.fatal("Can't find common LSan lit config at: %r" % lsan_lit_cfg)
+lit.load_config(config, lsan_lit_cfg)
+
+config.name = 'LeakSanitizer-Standalone'
+
+clang_lsan_cxxflags = config.clang_cxxflags + " -fsanitize=leak "
+
+config.substitutions.append( ("%clangxx_lsan ", (" " + config.clang + " " +
+                                                clang_lsan_cxxflags + " ")) )
+
+config.environment['LSAN_SYMBOLIZER_PATH'] = config.llvm_symbolizer_path
diff --git a/lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in b/lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in
new file mode 100644
index 0000000..8bc5c41
--- /dev/null
+++ b/lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in
@@ -0,0 +1,8 @@
+# Load common config for all compiler-rt lit tests.
+lit.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
+
+# Tool-specific config options.
+config.lsan_lit_src_root = "@LSAN_LIT_SOURCE_DIR@"
+
+# Load tool-specific config that would do the real work.
+lit.load_config(config, "@LSAN_LIT_SOURCE_DIR@/LsanConfig/lit.cfg")
diff --git a/lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc b/lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc
new file mode 100644
index 0000000..475a66e
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc
@@ -0,0 +1,12 @@
+// A loadable module with a large thread local section, which would require
+// allocation of a new TLS storage chunk when loaded with dlopen(). We use it
+// to test the reachability of such chunks in LSan tests.
+
+// This must be large enough that it doesn't fit into preallocated static TLS
+// space (see STATIC_TLS_SURPLUS in glibc).
+__thread void *huge_thread_local_array[(1 << 20) / sizeof(void *)]; // NOLINT
+
+extern "C" void **StoreToTLS(void *p) {
+  huge_thread_local_array[0] = p;
+  return &huge_thread_local_array[0];
+}
diff --git a/lib/asan/lit_tests/SharedLibs/lit.local.cfg b/lib/lsan/lit_tests/TestCases/SharedLibs/lit.local.cfg
similarity index 100%
copy from lib/asan/lit_tests/SharedLibs/lit.local.cfg
copy to lib/lsan/lit_tests/TestCases/SharedLibs/lit.local.cfg
diff --git a/lib/lsan/lit_tests/TestCases/disabler.cc b/lib/lsan/lit_tests/TestCases/disabler.cc
new file mode 100644
index 0000000..aef9e11
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/disabler.cc
@@ -0,0 +1,23 @@
+// Test for ScopedDisabler.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+int main() {
+  void **p;
+  {
+    __lsan::ScopedDisabler d;
+    p = new void *;
+  }
+  *reinterpret_cast<void **>(p) = malloc(666);
+  void *q = malloc(1337);
+  // Break optimization.
+  fprintf(stderr, "Test alloc: %p.\n", q);
+  return 0;
+}
+// CHECK: SUMMARY: LeakSanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc b/lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc
new file mode 100644
index 0000000..94e4fc3
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc
@@ -0,0 +1,38 @@
+// Regression test. Disabler should not depend on TSD validity.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=1"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE %t
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+pthread_key_t key;
+
+void key_destructor(void *arg) {
+  __lsan::ScopedDisabler d;
+  void *p = malloc(1337);
+  // Break optimization.
+  fprintf(stderr, "Test alloc: %p.\n", p);
+  pthread_setspecific(key, 0);
+}
+
+void *thread_func(void *arg) {
+  int res = pthread_setspecific(key, (void*)1);
+  assert(res == 0);
+  return 0;
+}
+
+int main() {
+  int res = pthread_key_create(&key, &key_destructor);
+  assert(res == 0);
+  pthread_t thread_id;
+  res = pthread_create(&thread_id, 0, thread_func, 0);
+  assert(res == 0);
+  res = pthread_join(thread_id, 0);
+  assert(res == 0);
+  return 0;
+}
diff --git a/lib/lsan/lit_tests/TestCases/do_leak_check_override.cc b/lib/lsan/lit_tests/TestCases/do_leak_check_override.cc
new file mode 100644
index 0000000..213d260
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/do_leak_check_override.cc
@@ -0,0 +1,36 @@
+// Test for __lsan_do_leak_check(). We test it by making the leak check run
+// before global destructors, which also tests compatibility with HeapChecker's
+// "normal" mode (LSan runs in "strict" mode by default).
+// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %t foo 2>&1 | FileCheck --check-prefix=CHECK-normal %s
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sanitizer/lsan_interface.h>
+
+struct LeakyGlobal {
+  LeakyGlobal() {
+    p = malloc(1337);
+  }
+  ~LeakyGlobal() {
+    p = 0;
+  }
+  void *p;
+};
+
+LeakyGlobal leaky_global;
+
+int main(int argc, char *argv[]) {
+  // Register leak check to run before global destructors.
+  if (argc > 1)
+    atexit(&__lsan_do_leak_check);
+  void *p = malloc(666);
+  printf("Test alloc: %p\n", p);
+  printf("Test alloc in leaky global: %p\n", leaky_global.p);
+  return 0;
+}
+
+// CHECK-strict: SUMMARY: LeakSanitizer: 2003 byte(s) leaked in 2 allocation(s)
+// CHECK-normal: SUMMARY: LeakSanitizer: 666 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/fork.cc b/lib/lsan/lit_tests/TestCases/fork.cc
new file mode 100644
index 0000000..69258d9
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/fork.cc
@@ -0,0 +1,24 @@
+// Test that thread local data is handled correctly after forking without exec().
+// RUN: %clangxx_lsan %s -o %t
+// RUN: %t 2>&1
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+__thread void *thread_local_var;
+
+int main() {
+  int status = 0;
+  thread_local_var = malloc(1337);
+  pid_t pid = fork();
+  assert(pid >= 0);
+  if (pid > 0) {
+    waitpid(pid, &status, 0);
+    assert(WIFEXITED(status));
+    return WEXITSTATUS(status);
+  }
+  return 0;
+}
diff --git a/lib/lsan/lit_tests/TestCases/fork_threaded.cc b/lib/lsan/lit_tests/TestCases/fork_threaded.cc
new file mode 100644
index 0000000..24a5861
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/fork_threaded.cc
@@ -0,0 +1,43 @@
+// Test that thread local data is handled correctly after forking without
+// exec(). In this test leak checking is initiated from a non-main thread.
+// RUN: %clangxx_lsan %s -o %t
+// RUN: %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+__thread void *thread_local_var;
+
+void *exit_thread_func(void *arg) {
+  exit(0);
+}
+
+void ExitFromThread() {
+  pthread_t tid;
+  int res;
+  res = pthread_create(&tid, 0, exit_thread_func, 0);
+  assert(res == 0);
+  pthread_join(tid, 0);
+}
+
+int main() {
+  int status = 0;
+  thread_local_var = malloc(1337);
+  pid_t pid = fork();
+  assert(pid >= 0);
+  if (pid > 0) {
+    waitpid(pid, &status, 0);
+    assert(WIFEXITED(status));
+    return WEXITSTATUS(status);
+  } else {
+    // Spawn a thread and call exit() from there, to check that we track main
+    // thread's pid correctly even if leak checking is initiated from another
+    // thread.
+    ExitFromThread();
+  }
+  return 0;
+}
diff --git a/lib/lsan/lit_tests/TestCases/ignore_object.cc b/lib/lsan/lit_tests/TestCases/ignore_object.cc
new file mode 100644
index 0000000..43744e4
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/ignore_object.cc
@@ -0,0 +1,30 @@
+// Test for __lsan_ignore_object().
+// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0:verbosity=3"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+int main() {
+  {
+    // The first malloc call can cause an allocation in libdl. Ignore it here so
+    // it doesn't show up in our output.
+    __lsan::ScopedDisabler d;
+    malloc(1);
+  }
+  // Explicitly ignored object.
+  void **p = new void *;
+  // Transitively ignored object.
+  *p = malloc(666);
+  // Non-ignored object.
+  volatile void *q = malloc(1337);
+  fprintf(stderr, "Test alloc: %p.\n", p);
+  __lsan_ignore_object(p);
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: ignoring heap object at [[ADDR]]
+// CHECK: SUMMARY: LeakSanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/ignore_object_errors.cc b/lib/lsan/lit_tests/TestCases/ignore_object_errors.cc
new file mode 100644
index 0000000..2a6c725
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/ignore_object_errors.cc
@@ -0,0 +1,22 @@
+// Test for incorrect use of __lsan_ignore_object().
+// RUN: LSAN_BASE="verbosity=2"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+int main() {
+  void *p = malloc(1337);
+  fprintf(stderr, "Test alloc: %p.\n", p);
+  __lsan_ignore_object(p);
+  __lsan_ignore_object(p);
+  free(p);
+  __lsan_ignore_object(p);
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: heap object at [[ADDR]] is already being ignored
+// CHECK: no heap object found at [[ADDR]]
diff --git a/lib/lsan/lit_tests/TestCases/large_allocation_leak.cc b/lib/lsan/lit_tests/TestCases/large_allocation_leak.cc
new file mode 100644
index 0000000..28e38ca
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/large_allocation_leak.cc
@@ -0,0 +1,18 @@
+// Test that LargeMmapAllocator's chunks aren't reachable via some internal data structure.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+  // maxsize in primary allocator is always less than this (1 << 25).
+  void *large_alloc = malloc(33554432);
+  fprintf(stderr, "Test alloc: %p.\n", large_alloc);
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: Directly leaked 33554432 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc b/lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc
new file mode 100644
index 0000000..441012a
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc
@@ -0,0 +1,19 @@
+// Test for the leak_check_at_exit flag.
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS="verbosity=1" %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
+// RUN: LSAN_OPTIONS="verbosity=1" %t 2>&1 | FileCheck %s --check-prefix=CHECK-do
+// RUN: LSAN_OPTIONS="verbosity=1:leak_check_at_exit=0" ASAN_OPTIONS="$ASAN_OPTIONS:leak_check_at_exit=0" %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
+// RUN: LSAN_OPTIONS="verbosity=1:leak_check_at_exit=0" ASAN_OPTIONS="$ASAN_OPTIONS:leak_check_at_exit=0" %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont
+
+#include <stdio.h>
+#include <sanitizer/lsan_interface.h>
+
+int main(int argc, char *argv[]) {
+  printf("printf to break optimization\n");
+  if (argc > 1)
+    __lsan_do_leak_check();
+  return 0;
+}
+
+// CHECK-do: SUMMARY: LeakSanitizer:
+// CHECK-dont-NOT: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/link_turned_off.cc b/lib/lsan/lit_tests/TestCases/link_turned_off.cc
new file mode 100644
index 0000000..6db7a18
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/link_turned_off.cc
@@ -0,0 +1,24 @@
+// Test for disabling LSan at link-time.
+// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %t foo 2>&1 | FileCheck %s
+
+#include <sanitizer/lsan_interface.h>
+
+int argc_copy;
+
+extern "C" {
+int __lsan_is_turned_off() {
+  return (argc_copy == 1);
+}
+}
+
+int main(int argc, char *argv[]) {
+  volatile int *x = new int;
+  *x = 42;
+  argc_copy = argc;
+  return 0;
+}
+
+// CHECK: SUMMARY: LeakSanitizer: 4 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/stale_stack_leak.cc b/lib/lsan/lit_tests/TestCases/stale_stack_leak.cc
new file mode 100644
index 0000000..4f2b26c
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/stale_stack_leak.cc
@@ -0,0 +1,42 @@
+// Test that out-of-scope local variables are ignored by LSan.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=1"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE":exitcode=0" %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void **pp;
+
+// Put pointer far enough on the stack that LSan has space to run in without
+// overwriting it.
+// Hopefully the argument p will be passed on a register, saving us from false
+// negatives.
+__attribute__((noinline))
+void *PutPointerOnStaleStack(void *p) {
+  void *locals[2048];
+  locals[0] = p;
+  pp = &locals[0];
+  fprintf(stderr, "Test alloc: %p.\n", locals[0]);
+  return 0;
+}
+
+int main() {
+  PutPointerOnStaleStack(malloc(1337));
+  return 0;
+}
+
+// This must run after LSan, to ensure LSan didn't overwrite the pointer before
+// it had a chance to see it. If LSan is invoked with atexit(), this works.
+// Otherwise, we need a different method.
+__attribute__((destructor))
+void ConfirmPointerHasSurvived() {
+  fprintf(stderr, "Value after LSan: %p.\n", *pp);
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK-sanity: Test alloc: [[ADDR:.*]].
+// CHECK: Directly leaked 1337 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
+// CHECK-sanity: Value after LSan: [[ADDR]].
diff --git a/lib/lsan/lit_tests/TestCases/suppressions_default.cc b/lib/lsan/lit_tests/TestCases/suppressions_default.cc
new file mode 100644
index 0000000..e8e0921
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/suppressions_default.cc
@@ -0,0 +1,29 @@
+// Test for ScopedDisabler.
+// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+extern "C"
+const char *__lsan_default_suppressions() {
+  return "leak:*LSanTestLeakingFunc*";
+}
+
+void LSanTestLeakingFunc() {
+  void *p = malloc(666);
+  fprintf(stderr, "Test alloc: %p.\n", p);
+}
+
+int main() {
+  LSanTestLeakingFunc();
+  void *q = malloc(1337);
+  fprintf(stderr, "Test alloc: %p.\n", q);
+  return 0;
+}
+// CHECK: Suppressions used:
+// CHECK: 1 666 *LSanTestLeakingFunc*
+// CHECK: SUMMARY: LeakSanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/suppressions_file.cc b/lib/lsan/lit_tests/TestCases/suppressions_file.cc
new file mode 100644
index 0000000..e8e0921
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/suppressions_file.cc
@@ -0,0 +1,29 @@
+// Test for ScopedDisabler.
+// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+extern "C"
+const char *__lsan_default_suppressions() {
+  return "leak:*LSanTestLeakingFunc*";
+}
+
+void LSanTestLeakingFunc() {
+  void *p = malloc(666);
+  fprintf(stderr, "Test alloc: %p.\n", p);
+}
+
+int main() {
+  LSanTestLeakingFunc();
+  void *q = malloc(1337);
+  fprintf(stderr, "Test alloc: %p.\n", q);
+  return 0;
+}
+// CHECK: Suppressions used:
+// CHECK: 1 666 *LSanTestLeakingFunc*
+// CHECK: SUMMARY: LeakSanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp b/lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp
new file mode 100644
index 0000000..8d8e560
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp
@@ -0,0 +1 @@
+leak:*LSanTestLeakingFunc*
diff --git a/lib/lsan/lit_tests/TestCases/use_globals_initialized.cc b/lib/lsan/lit_tests/TestCases/use_globals_initialized.cc
new file mode 100644
index 0000000..2849495
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_globals_initialized.cc
@@ -0,0 +1,21 @@
+// Test that initialized globals are included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=0" not %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %t 2>&1
+// RUN: LSAN_OPTIONS="" %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void *data_var = (void *)1;
+
+int main() {
+  data_var = malloc(1337);
+  fprintf(stderr, "Test alloc: %p.\n", data_var);
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: Directly leaked 1337 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc b/lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc
new file mode 100644
index 0000000..f48d08f
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc
@@ -0,0 +1,21 @@
+// Test that uninitialized globals are included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=0" not %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %t 2>&1
+// RUN: LSAN_OPTIONS="" %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void *bss_var;
+
+int main() {
+  bss_var = malloc(1337);
+  fprintf(stderr, "Test alloc: %p.\n", bss_var);
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: Directly leaked 1337 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_registers.cc b/lib/lsan/lit_tests/TestCases/use_registers.cc
new file mode 100644
index 0000000..636fac8
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_registers.cc
@@ -0,0 +1,51 @@
+// Test that registers of running threads are included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0"
+// RUN: %clangxx_lsan -pthread %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_registers=0" not %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_registers=1" %t 2>&1
+// RUN: LSAN_OPTIONS="" %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C"
+void *registers_thread_func(void *arg) {
+  int *sync = reinterpret_cast<int *>(arg);
+  void *p = malloc(1337);
+  // To store the pointer, choose a register which is unlikely to be reused by
+  // a function call.
+#if defined(__i386__)
+  asm ( "mov %0, %%esi"
+      :
+      : "r" (p)
+      );
+#elif defined(__x86_64__)
+  asm ( "mov %0, %%r15"
+      :
+      : "r" (p)
+      );
+#else
+#error "Test is not supported on this architecture."
+#endif
+  fprintf(stderr, "Test alloc: %p.\n", p);
+  fflush(stderr);
+  __sync_fetch_and_xor(sync, 1);
+  while (true)
+    pthread_yield();
+}
+
+int main() {
+  int sync = 0;
+  pthread_t thread_id;
+  int res = pthread_create(&thread_id, 0, registers_thread_func, &sync);
+  assert(res == 0);
+  while (!__sync_fetch_and_xor(&sync, 0))
+    pthread_yield();
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: Directly leaked 1337 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_stacks.cc b/lib/lsan/lit_tests/TestCases/use_stacks.cc
new file mode 100644
index 0000000..06a058e
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_stacks.cc
@@ -0,0 +1,20 @@
+// Test that stack of main thread is included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %t 2>&1
+// RUN: LSAN_OPTIONS="" %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+  void *stack_var = malloc(1337);
+  fprintf(stderr, "Test alloc: %p.\n", stack_var);
+  // Do not return from main to prevent the pointer from going out of scope.
+  exit(0);
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: Directly leaked 1337 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc b/lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc
new file mode 100644
index 0000000..9e1b1cf
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc
@@ -0,0 +1,36 @@
+// Test that stacks of non-main threads are included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0"
+// RUN: %clangxx_lsan -pthread %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %t 2>&1
+// RUN: LSAN_OPTIONS="" %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C"
+void *stacks_thread_func(void *arg) {
+  int *sync = reinterpret_cast<int *>(arg);
+  void *p = malloc(1337);
+  fprintf(stderr, "Test alloc: %p.\n", p);
+  fflush(stderr);
+  __sync_fetch_and_xor(sync, 1);
+  while (true)
+    pthread_yield();
+}
+
+int main() {
+  int sync = 0;
+  pthread_t thread_id;
+  int res = pthread_create(&thread_id, 0, stacks_thread_func, &sync);
+  assert(res == 0);
+  while (!__sync_fetch_and_xor(&sync, 0))
+    pthread_yield();
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: Directly leaked 1337 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc b/lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc
new file mode 100644
index 0000000..3e45e1a
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc
@@ -0,0 +1,33 @@
+// Test that dynamically allocated TLS space is included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx %p/SharedLibs/huge_tls_lib_so.cc -fPIC -shared -o %t-so.so
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1
+// RUN: LSAN_OPTIONS="" %t 2>&1
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+
+int main(int argc, char *argv[]) {
+  std::string path = std::string(argv[0]) + "-so.so";
+
+  void *handle = dlopen(path.c_str(), RTLD_LAZY);
+  assert(handle != 0);
+  typedef void **(* store_t)(void *p);
+  store_t StoreToTLS = (store_t)dlsym(handle, "StoreToTLS");
+  assert(dlerror() == 0);
+
+  void *p = malloc(1337);
+  void **p_in_tls = StoreToTLS(p);
+  assert(*p_in_tls == p);
+  fprintf(stderr, "Test alloc: %p.\n", p);
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: leaked 1337 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc
new file mode 100644
index 0000000..032def7
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc
@@ -0,0 +1,37 @@
+// Test that dynamically allocated thread-specific storage is included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1
+// RUN: LSAN_OPTIONS="" %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// From glibc: this many keys are stored in the thread descriptor directly.
+const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32;
+
+int main() {
+  static const unsigned kDummyKeysCount = PTHREAD_KEY_2NDLEVEL_SIZE;
+  int res;
+  pthread_key_t dummy_keys[kDummyKeysCount];
+  for (unsigned i = 0; i < kDummyKeysCount; i++) {
+    res = pthread_key_create(&dummy_keys[i], NULL);
+    assert(res == 0);
+  }
+  pthread_key_t key;
+  res = pthread_key_create(&key, NULL);
+  assert(key >= PTHREAD_KEY_2NDLEVEL_SIZE);
+  assert(res == 0);
+  void *p  = malloc(1337);
+  res = pthread_setspecific(key, p);
+  assert(res == 0);
+  fprintf(stderr, "Test alloc: %p.\n", p);
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: leaked 1337 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc
new file mode 100644
index 0000000..86e2b29
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc
@@ -0,0 +1,31 @@
+// Test that statically allocated thread-specific storage is included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1
+// RUN: LSAN_OPTIONS="" %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// From glibc: this many keys are stored in the thread descriptor directly.
+const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32;
+
+int main() {
+  pthread_key_t key;
+  int res;
+  res = pthread_key_create(&key, NULL);
+  assert(res == 0);
+  assert(key < PTHREAD_KEY_2NDLEVEL_SIZE);
+  void *p = malloc(1337);
+  res = pthread_setspecific(key, p);
+  assert(res == 0);
+  fprintf(stderr, "Test alloc: %p.\n", p);
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: Directly leaked 1337 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_tls_static.cc b/lib/lsan/lit_tests/TestCases/use_tls_static.cc
new file mode 100644
index 0000000..460aee4
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_tls_static.cc
@@ -0,0 +1,21 @@
+// Test that statically allocated TLS space is included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1
+// RUN: LSAN_OPTIONS="" %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+__thread void *tls_var;
+
+int main() {
+  tls_var = malloc(1337);
+  fprintf(stderr, "Test alloc: %p.\n", tls_var);
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: Directly leaked 1337 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/TestCases/use_unaligned.cc b/lib/lsan/lit_tests/TestCases/use_unaligned.cc
new file mode 100644
index 0000000..851d249
--- /dev/null
+++ b/lib/lsan/lit_tests/TestCases/use_unaligned.cc
@@ -0,0 +1,23 @@
+// Test that unaligned pointers are detected correctly.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_unaligned=0" not %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_unaligned=1" %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void *arr[2];
+
+int main() {
+  void *p = malloc(1337);
+  fprintf(stderr, "Test alloc: %p.\n", p);
+  char *char_arr = (char *)arr;
+  memcpy(char_arr + 1, &p, sizeof(p));
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: Directly leaked 1337 byte object at [[ADDR]]
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: SUMMARY: LeakSanitizer:
diff --git a/lib/lsan/lit_tests/Unit/lit.site.cfg.in b/lib/lsan/lit_tests/Unit/lit.site.cfg.in
new file mode 100644
index 0000000..efe8049
--- /dev/null
+++ b/lib/lsan/lit_tests/Unit/lit.site.cfg.in
@@ -0,0 +1,12 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Load common config for all compiler-rt unit tests.
+lit.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
+
+# Setup config name.
+config.name = 'LeakSanitizer-Unit'
+# Setup test source and exec root. For unit tests, we define
+# it as build directory with LSan unit tests.
+config.test_exec_root = "@LSAN_BINARY_DIR@/tests"
+config.test_source_root = config.test_exec_root
diff --git a/lib/lsan/lit_tests/lit.common.cfg b/lib/lsan/lit_tests/lit.common.cfg
new file mode 100644
index 0000000..d52f64c
--- /dev/null
+++ b/lib/lsan/lit_tests/lit.common.cfg
@@ -0,0 +1,33 @@
+# -*- Python -*-
+
+# Common configuration for running leak detection tests under LSan/ASan.
+
+import os
+
+def get_required_attr(config, attr_name):
+  attr_value = getattr(config, attr_name, None)
+  if not attr_value:
+    lit.fatal("No attribute %r in test configuration! You may need to run "
+              "tests from your build directory or add this attribute "
+              "to lit.site.cfg " % attr_name)
+  return attr_value
+
+# Setup source root.
+lsan_lit_src_root = get_required_attr(config, 'lsan_lit_src_root')
+config.test_source_root = os.path.join(lsan_lit_src_root, 'TestCases')
+
+clang_cxxflags = ("--driver-mode=g++ "
+                      + "-g "
+                      + "-O0 "
+                      + "-m64 ")
+
+config.clang_cxxflags = clang_cxxflags
+
+config.substitutions.append( ("%clangxx ", (" " + config.clang + " " +
+                                                clang_cxxflags + " ")) )
+
+# LeakSanitizer tests are currently supported on x86-64 Linux only.
+if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64']:
+  config.unsupported = True
+
+config.suffixes = ['.c', '.cc', '.cpp']
diff --git a/lib/lsan/lsan.cc b/lib/lsan/lsan.cc
new file mode 100644
index 0000000..22e18e2
--- /dev/null
+++ b/lib/lsan/lsan.cc
@@ -0,0 +1,67 @@
+//=-- lsan.cc -------------------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// Standalone LSan RTL.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan.h"
+
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "lsan_allocator.h"
+#include "lsan_common.h"
+#include "lsan_thread.h"
+
+namespace __lsan {
+
+static void InitializeCommonFlags() {
+  CommonFlags *cf = common_flags();
+  cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
+  cf->symbolize = (cf->external_symbolizer_path &&
+      cf->external_symbolizer_path[0]);
+  cf->strip_path_prefix = "";
+  cf->fast_unwind_on_malloc = true;
+  cf->malloc_context_size = 30;
+  cf->detect_leaks = true;
+  cf->leak_check_at_exit = true;
+
+  ParseCommonFlagsFromString(GetEnv("LSAN_OPTIONS"));
+}
+
+void Init() {
+  static bool inited;
+  if (inited)
+    return;
+  inited = true;
+  SanitizerToolName = "LeakSanitizer";
+  InitializeCommonFlags();
+  InitializeAllocator();
+  InitTlsSize();
+  InitializeInterceptors();
+  InitializeThreadRegistry();
+  u32 tid = ThreadCreate(0, 0, true);
+  CHECK_EQ(tid, 0);
+  ThreadStart(tid, GetTid());
+  SetCurrentThread(tid);
+
+  // Start symbolizer process if necessary.
+  const char* external_symbolizer = common_flags()->external_symbolizer_path;
+  if (common_flags()->symbolize && external_symbolizer &&
+      external_symbolizer[0]) {
+    InitializeExternalSymbolizer(external_symbolizer);
+  }
+
+  InitCommonLsan();
+  if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
+    Atexit(DoLeakCheck);
+}
+
+}  // namespace __lsan
diff --git a/lib/lsan/lsan.h b/lib/lsan/lsan.h
new file mode 100644
index 0000000..d89a6ab
--- /dev/null
+++ b/lib/lsan/lsan.h
@@ -0,0 +1,23 @@
+//=-- lsan.h --------------------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// Private header for standalone LSan RTL.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+namespace __lsan {
+
+void Init();
+void InitializeInterceptors();
+
+}  // namespace __lsan
diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc
new file mode 100644
index 0000000..1512c2e
--- /dev/null
+++ b/lib/lsan/lsan_allocator.cc
@@ -0,0 +1,193 @@
+//=-- lsan_allocator.cc ---------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// See lsan_allocator.h for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan_allocator.h"
+
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "lsan_common.h"
+
+namespace __lsan {
+
+static const uptr kMaxAllowedMallocSize = 8UL << 30;
+static const uptr kAllocatorSpace = 0x600000000000ULL;
+static const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
+
+struct ChunkMetadata {
+  bool allocated : 8;  // Must be first.
+  ChunkTag tag : 2;
+  uptr requested_size : 54;
+  u32 stack_trace_id;
+};
+
+typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
+        sizeof(ChunkMetadata), CompactSizeClassMap> PrimaryAllocator;
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+          SecondaryAllocator> Allocator;
+
+static Allocator allocator;
+static THREADLOCAL AllocatorCache cache;
+
+void InitializeAllocator() {
+  allocator.Init();
+}
+
+void AllocatorThreadFinish() {
+  allocator.SwallowCache(&cache);
+}
+
+static ChunkMetadata *Metadata(void *p) {
+  return reinterpret_cast<ChunkMetadata *>(allocator.GetMetaData(p));
+}
+
+static void RegisterAllocation(const StackTrace &stack, void *p, uptr size) {
+  if (!p) return;
+  ChunkMetadata *m = Metadata(p);
+  CHECK(m);
+  m->tag = DisabledInThisThread() ? kIgnored : kDirectlyLeaked;
+  m->stack_trace_id = StackDepotPut(stack.trace, stack.size);
+  m->requested_size = size;
+  atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 1, memory_order_relaxed);
+}
+
+static void RegisterDeallocation(void *p) {
+  if (!p) return;
+  ChunkMetadata *m = Metadata(p);
+  CHECK(m);
+  atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 0, memory_order_relaxed);
+}
+
+void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
+               bool cleared) {
+  if (size == 0)
+    size = 1;
+  if (size > kMaxAllowedMallocSize) {
+    Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
+    return 0;
+  }
+  void *p = allocator.Allocate(&cache, size, alignment, cleared);
+  RegisterAllocation(stack, p, size);
+  return p;
+}
+
+void Deallocate(void *p) {
+  RegisterDeallocation(p);
+  allocator.Deallocate(&cache, p);
+}
+
+void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
+                 uptr alignment) {
+  RegisterDeallocation(p);
+  if (new_size > kMaxAllowedMallocSize) {
+    Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);
+    allocator.Deallocate(&cache, p);
+    return 0;
+  }
+  p = allocator.Reallocate(&cache, p, new_size, alignment);
+  RegisterAllocation(stack, p, new_size);
+  return p;
+}
+
+void GetAllocatorCacheRange(uptr *begin, uptr *end) {
+  *begin = (uptr)&cache;
+  *end = *begin + sizeof(cache);
+}
+
+uptr GetMallocUsableSize(void *p) {
+  ChunkMetadata *m = Metadata(p);
+  if (!m) return 0;
+  return m->requested_size;
+}
+
+///// Interface to the common LSan module. /////
+
+void LockAllocator() {
+  allocator.ForceLock();
+}
+
+void UnlockAllocator() {
+  allocator.ForceUnlock();
+}
+
+void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
+  *begin = (uptr)&allocator;
+  *end = *begin + sizeof(allocator);
+}
+
+uptr PointsIntoChunk(void* p) {
+  uptr addr = reinterpret_cast<uptr>(p);
+  uptr chunk = reinterpret_cast<uptr>(allocator.GetBlockBeginFastLocked(p));
+  if (!chunk) return 0;
+  // LargeMmapAllocator considers pointers to the meta-region of a chunk to be
+  // valid, but we don't want that.
+  if (addr < chunk) return 0;
+  ChunkMetadata *m = Metadata(reinterpret_cast<void *>(chunk));
+  CHECK(m);
+  if (m->allocated && addr < chunk + m->requested_size)
+    return chunk;
+  return 0;
+}
+
+uptr GetUserBegin(uptr chunk) {
+  return chunk;
+}
+
+LsanMetadata::LsanMetadata(uptr chunk) {
+  metadata_ = Metadata(reinterpret_cast<void *>(chunk));
+  CHECK(metadata_);
+}
+
+bool LsanMetadata::allocated() const {
+  return reinterpret_cast<ChunkMetadata *>(metadata_)->allocated;
+}
+
+ChunkTag LsanMetadata::tag() const {
+  return reinterpret_cast<ChunkMetadata *>(metadata_)->tag;
+}
+
+void LsanMetadata::set_tag(ChunkTag value) {
+  reinterpret_cast<ChunkMetadata *>(metadata_)->tag = value;
+}
+
+uptr LsanMetadata::requested_size() const {
+  return reinterpret_cast<ChunkMetadata *>(metadata_)->requested_size;
+}
+
+u32 LsanMetadata::stack_trace_id() const {
+  return reinterpret_cast<ChunkMetadata *>(metadata_)->stack_trace_id;
+}
+
+void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+  allocator.ForEachChunk(callback, arg);
+}
+
+IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+  void *chunk = allocator.GetBlockBegin(p);
+  if (!chunk || p < chunk) return kIgnoreObjectInvalid;
+  ChunkMetadata *m = Metadata(chunk);
+  CHECK(m);
+  if (m->allocated && (uptr)p < (uptr)chunk + m->requested_size) {
+    if (m->tag == kIgnored)
+      return kIgnoreObjectAlreadyIgnored;
+    m->tag = kIgnored;
+    return kIgnoreObjectSuccess;
+  } else {
+    return kIgnoreObjectInvalid;
+  }
+}
+}  // namespace __lsan
diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h
new file mode 100644
index 0000000..00c55ae
--- /dev/null
+++ b/lib/lsan/lsan_allocator.h
@@ -0,0 +1,39 @@
+//=-- lsan_allocator.h ----------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// Allocator for standalone LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LSAN_ALLOCATOR_H
+#define LSAN_ALLOCATOR_H
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __lsan {
+
+void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
+               bool cleared);
+void Deallocate(void *p);
+void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
+                 uptr alignment);
+uptr GetMallocUsableSize(void *p);
+
+template<typename Callable>
+void ForEachChunk(const Callable &callback);
+
+void GetAllocatorCacheRange(uptr *begin, uptr *end);
+void AllocatorThreadFinish();
+void InitializeAllocator();
+
+}  // namespace __lsan
+
+#endif  // LSAN_ALLOCATOR_H
diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc
new file mode 100644
index 0000000..265b1ce
--- /dev/null
+++ b/lib/lsan/lsan_common.cc
@@ -0,0 +1,564 @@
+//=-- lsan_common.cc ------------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// Implementation of common leak checking functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan_common.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_stoptheworld.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+
+#if CAN_SANITIZE_LEAKS
+namespace __lsan {
+
+// This mutex is used to prevent races between DoLeakCheck and IgnoreObject.
+BlockingMutex global_mutex(LINKER_INITIALIZED);
+
+THREADLOCAL int disable_counter;
+bool DisabledInThisThread() { return disable_counter > 0; }
+
+Flags lsan_flags;
+
+static void InitializeFlags() {
+  Flags *f = flags();
+  // Default values.
+  f->report_objects = false;
+  f->resolution = 0;
+  f->max_leaks = 0;
+  f->exitcode = 23;
+  f->suppressions="";
+  f->use_registers = true;
+  f->use_globals = true;
+  f->use_stacks = true;
+  f->use_tls = true;
+  f->use_unaligned = false;
+  f->verbosity = 0;
+  f->log_pointers = false;
+  f->log_threads = false;
+
+  const char *options = GetEnv("LSAN_OPTIONS");
+  if (options) {
+    ParseFlag(options, &f->use_registers, "use_registers");
+    ParseFlag(options, &f->use_globals, "use_globals");
+    ParseFlag(options, &f->use_stacks, "use_stacks");
+    ParseFlag(options, &f->use_tls, "use_tls");
+    ParseFlag(options, &f->use_unaligned, "use_unaligned");
+    ParseFlag(options, &f->report_objects, "report_objects");
+    ParseFlag(options, &f->resolution, "resolution");
+    CHECK_GE(&f->resolution, 0);
+    ParseFlag(options, &f->max_leaks, "max_leaks");
+    CHECK_GE(&f->max_leaks, 0);
+    ParseFlag(options, &f->verbosity, "verbosity");
+    ParseFlag(options, &f->log_pointers, "log_pointers");
+    ParseFlag(options, &f->log_threads, "log_threads");
+    ParseFlag(options, &f->exitcode, "exitcode");
+    ParseFlag(options, &f->suppressions, "suppressions");
+  }
+}
+
+SuppressionContext *suppression_ctx;
+
+void InitializeSuppressions() {
+  CHECK(!suppression_ctx);
+  ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
+  suppression_ctx = new(placeholder_) SuppressionContext;
+  char *suppressions_from_file;
+  uptr buffer_size;
+  if (ReadFileToBuffer(flags()->suppressions, &suppressions_from_file,
+                       &buffer_size, 1 << 26 /* max_len */))
+    suppression_ctx->Parse(suppressions_from_file);
+  if (flags()->suppressions[0] && !buffer_size) {
+    Printf("LeakSanitizer: failed to read suppressions file '%s'\n",
+           flags()->suppressions);
+    Die();
+  }
+  if (&__lsan_default_suppressions)
+    suppression_ctx->Parse(__lsan_default_suppressions());
+}
+
+void InitCommonLsan() {
+  InitializeFlags();
+  InitializeSuppressions();
+  InitializePlatformSpecificModules();
+}
+
+static inline bool CanBeAHeapPointer(uptr p) {
+  // Since our heap is located in mmap-ed memory, we can assume a sensible lower
+  // bound on heap addresses.
+  const uptr kMinAddress = 4 * 4096;
+  if (p < kMinAddress) return false;
+#ifdef __x86_64__
+  // Accept only canonical form user-space addresses.
+  return ((p >> 47) == 0);
+#else
+  return true;
+#endif
+}
+
+// Scans the memory range, looking for byte patterns that point into allocator
+// chunks. Marks those chunks with |tag| and adds them to |frontier|.
+// There are two usage modes for this function: finding reachable or ignored
+// chunks (|tag| = kReachable or kIgnored) and finding indirectly leaked chunks
+// (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill,
+// so |frontier| = 0.
+void ScanRangeForPointers(uptr begin, uptr end,
+                          Frontier *frontier,
+                          const char *region_type, ChunkTag tag) {
+  const uptr alignment = flags()->pointer_alignment();
+  if (flags()->log_pointers)
+    Report("Scanning %s range %p-%p.\n", region_type, begin, end);
+  uptr pp = begin;
+  if (pp % alignment)
+    pp = pp + alignment - pp % alignment;
+  for (; pp + sizeof(void *) <= end; pp += alignment) {  // NOLINT
+    void *p = *reinterpret_cast<void **>(pp);
+    if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue;
+    uptr chunk = PointsIntoChunk(p);
+    if (!chunk) continue;
+    LsanMetadata m(chunk);
+    // Reachable beats ignored beats leaked.
+    if (m.tag() == kReachable) continue;
+    if (m.tag() == kIgnored && tag != kReachable) continue;
+    m.set_tag(tag);
+    if (flags()->log_pointers)
+      Report("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p,
+             chunk, chunk + m.requested_size(), m.requested_size());
+    if (frontier)
+      frontier->push_back(chunk);
+  }
+}
+
+// Scans thread data (stacks and TLS) for heap pointers.
+static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
+                           Frontier *frontier) {
+  InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount());
+  uptr registers_begin = reinterpret_cast<uptr>(registers.data());
+  uptr registers_end = registers_begin + registers.size();
+  for (uptr i = 0; i < suspended_threads.thread_count(); i++) {
+    uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i));
+    if (flags()->log_threads) Report("Processing thread %d.\n", os_id);
+    uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
+    bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end,
+                                              &tls_begin, &tls_end,
+                                              &cache_begin, &cache_end);
+    if (!thread_found) {
+      // If a thread can't be found in the thread registry, it's probably in the
+      // process of destruction. Log this event and move on.
+      if (flags()->log_threads)
+        Report("Thread %d not found in registry.\n", os_id);
+      continue;
+    }
+    uptr sp;
+    bool have_registers =
+        (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0);
+    if (!have_registers) {
+      Report("Unable to get registers from thread %d.\n");
+      // If unable to get SP, consider the entire stack to be reachable.
+      sp = stack_begin;
+    }
+
+    if (flags()->use_registers && have_registers)
+      ScanRangeForPointers(registers_begin, registers_end, frontier,
+                           "REGISTERS", kReachable);
+
+    if (flags()->use_stacks) {
+      if (flags()->log_threads)
+        Report("Stack at %p-%p, SP = %p.\n", stack_begin, stack_end, sp);
+      if (sp < stack_begin || sp >= stack_end) {
+        // SP is outside the recorded stack range (e.g. the thread is running a
+        // signal handler on alternate stack). Again, consider the entire stack
+        // range to be reachable.
+        if (flags()->log_threads)
+          Report("WARNING: stack pointer not in stack range.\n");
+      } else {
+        // Shrink the stack range to ignore out-of-scope values.
+        stack_begin = sp;
+      }
+      ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK",
+                           kReachable);
+    }
+
+    if (flags()->use_tls) {
+      if (flags()->log_threads) Report("TLS at %p-%p.\n", tls_begin, tls_end);
+      if (cache_begin == cache_end) {
+        ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
+      } else {
+        // Because LSan should not be loaded with dlopen(), we can assume
+        // that allocator cache will be part of static TLS image.
+        CHECK_LE(tls_begin, cache_begin);
+        CHECK_GE(tls_end, cache_end);
+        if (tls_begin < cache_begin)
+          ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
+                               kReachable);
+        if (tls_end > cache_end)
+          ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable);
+      }
+    }
+  }
+}
+
+static void FloodFillTag(Frontier *frontier, ChunkTag tag) {
+  while (frontier->size()) {
+    uptr next_chunk = frontier->back();
+    frontier->pop_back();
+    LsanMetadata m(next_chunk);
+    ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier,
+                         "HEAP", tag);
+  }
+}
+
+// ForEachChunk callback. If the chunk is marked as leaked, marks all chunks
+// which are reachable from it as indirectly leaked.
+static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) {
+  chunk = GetUserBegin(chunk);
+  LsanMetadata m(chunk);
+  if (m.allocated() && m.tag() != kReachable) {
+    ScanRangeForPointers(chunk, chunk + m.requested_size(),
+                         /* frontier */ 0, "HEAP", kIndirectlyLeaked);
+  }
+}
+
+// ForEachChunk callback. If chunk is marked as ignored, adds its address to
+// frontier.
+static void CollectIgnoredCb(uptr chunk, void *arg) {
+  CHECK(arg);
+  chunk = GetUserBegin(chunk);
+  LsanMetadata m(chunk);
+  if (m.allocated() && m.tag() == kIgnored)
+    reinterpret_cast<Frontier *>(arg)->push_back(chunk);
+}
+
+// Sets the appropriate tag on each chunk.
+static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
+  // Holds the flood fill frontier.
+  Frontier frontier(GetPageSizeCached());
+
+  if (flags()->use_globals)
+    ProcessGlobalRegions(&frontier);
+  ProcessThreads(suspended_threads, &frontier);
+  FloodFillTag(&frontier, kReachable);
+  // The check here is relatively expensive, so we do this in a separate flood
+  // fill. That way we can skip the check for chunks that are reachable
+  // otherwise.
+  ProcessPlatformSpecificAllocations(&frontier);
+  FloodFillTag(&frontier, kReachable);
+
+  if (flags()->log_pointers)
+    Report("Scanning ignored chunks.\n");
+  CHECK_EQ(0, frontier.size());
+  ForEachChunk(CollectIgnoredCb, &frontier);
+  FloodFillTag(&frontier, kIgnored);
+
+  // Iterate over leaked chunks and mark those that are reachable from other
+  // leaked chunks.
+  if (flags()->log_pointers)
+    Report("Scanning leaked chunks.\n");
+  ForEachChunk(MarkIndirectlyLeakedCb, 0 /* arg */);
+}
+
+static void PrintStackTraceById(u32 stack_trace_id) {
+  CHECK(stack_trace_id);
+  uptr size = 0;
+  const uptr *trace = StackDepotGet(stack_trace_id, &size);
+  StackTrace::PrintStack(trace, size, common_flags()->symbolize,
+                         common_flags()->strip_path_prefix, 0);
+}
+
+// ForEachChunk callback. Aggregates unreachable chunks into a LeakReport.
+static void CollectLeaksCb(uptr chunk, void *arg) {
+  CHECK(arg);
+  LeakReport *leak_report = reinterpret_cast<LeakReport *>(arg);
+  chunk = GetUserBegin(chunk);
+  LsanMetadata m(chunk);
+  if (!m.allocated()) return;
+  if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) {
+    uptr resolution = flags()->resolution;
+    if (resolution > 0) {
+      uptr size = 0;
+      const uptr *trace = StackDepotGet(m.stack_trace_id(), &size);
+      size = Min(size, resolution);
+      leak_report->Add(StackDepotPut(trace, size), m.requested_size(), m.tag());
+    } else {
+      leak_report->Add(m.stack_trace_id(), m.requested_size(), m.tag());
+    }
+  }
+}
+
+// ForEachChunkCallback. Prints addresses of unreachable chunks.
+static void PrintLeakedCb(uptr chunk, void *arg) {
+  chunk = GetUserBegin(chunk);
+  LsanMetadata m(chunk);
+  if (!m.allocated()) return;
+  if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) {
+    Printf("%s leaked %zu byte object at %p.\n",
+           m.tag() == kDirectlyLeaked ? "Directly" : "Indirectly",
+           m.requested_size(), chunk);
+  }
+}
+
+static void PrintMatchedSuppressions() {
+  InternalMmapVector<Suppression *> matched(1);
+  suppression_ctx->GetMatched(&matched);
+  if (!matched.size())
+    return;
+  const char *line = "-----------------------------------------------------";
+  Printf("%s\n", line);
+  Printf("Suppressions used:\n");
+  Printf("  count      bytes template\n");
+  for (uptr i = 0; i < matched.size(); i++)
+    Printf("%7zu %10zu %s\n", static_cast<uptr>(matched[i]->hit_count),
+           matched[i]->weight, matched[i]->templ);
+  Printf("%s\n\n", line);
+}
+
+static void PrintLeaked() {
+  Printf("\n");
+  Printf("Reporting individual objects:\n");
+  ForEachChunk(PrintLeakedCb, 0 /* arg */);
+}
+
+struct DoLeakCheckParam {
+  bool success;
+  LeakReport leak_report;
+};
+
+static void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads,
+                                void *arg) {
+  DoLeakCheckParam *param = reinterpret_cast<DoLeakCheckParam *>(arg);
+  CHECK(param);
+  CHECK(!param->success);
+  CHECK(param->leak_report.IsEmpty());
+  ClassifyAllChunks(suspended_threads);
+  ForEachChunk(CollectLeaksCb, &param->leak_report);
+  if (!param->leak_report.IsEmpty() && flags()->report_objects)
+    PrintLeaked();
+  param->success = true;
+}
+
+void DoLeakCheck() {
+  EnsureMainThreadIDIsCorrect();
+  BlockingMutexLock l(&global_mutex);
+  static bool already_done;
+  if (already_done) return;
+  already_done = true;
+  if (&__lsan_is_turned_off && __lsan_is_turned_off())
+    return;
+
+  DoLeakCheckParam param;
+  param.success = false;
+  LockThreadRegistry();
+  LockAllocator();
+  StopTheWorld(DoLeakCheckCallback, &param);
+  UnlockAllocator();
+  UnlockThreadRegistry();
+
+  if (!param.success) {
+    Report("LeakSanitizer has encountered a fatal error.\n");
+    Die();
+  }
+  uptr have_unsuppressed = param.leak_report.ApplySuppressions();
+  if (have_unsuppressed) {
+    Printf("\n"
+           "================================================================="
+           "\n");
+    Report("ERROR: LeakSanitizer: detected memory leaks\n");
+    param.leak_report.PrintLargest(flags()->max_leaks);
+  }
+  if (have_unsuppressed || (flags()->verbosity >= 1)) {
+    PrintMatchedSuppressions();
+    param.leak_report.PrintSummary();
+  }
+  if (have_unsuppressed && flags()->exitcode)
+    internal__exit(flags()->exitcode);
+}
+
+static Suppression *GetSuppressionForAddr(uptr addr) {
+  static const uptr kMaxAddrFrames = 16;
+  InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
+  for (uptr i = 0; i < kMaxAddrFrames; i++) new (&addr_frames[i]) AddressInfo();
+  uptr addr_frames_num = __sanitizer::SymbolizeCode(addr, addr_frames.data(),
+                                                    kMaxAddrFrames);
+  for (uptr i = 0; i < addr_frames_num; i++) {
+    Suppression* s;
+    if (suppression_ctx->Match(addr_frames[i].function, SuppressionLeak, &s) ||
+        suppression_ctx->Match(addr_frames[i].file, SuppressionLeak, &s) ||
+        suppression_ctx->Match(addr_frames[i].module, SuppressionLeak, &s))
+      return s;
+  }
+  return 0;
+}
+
+static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
+  uptr size = 0;
+  const uptr *trace = StackDepotGet(stack_trace_id, &size);
+  for (uptr i = 0; i < size; i++) {
+    Suppression *s =
+        GetSuppressionForAddr(StackTrace::GetPreviousInstructionPc(trace[i]));
+    if (s) return s;
+  }
+  return 0;
+}
+
+///// LeakReport implementation. /////
+
+// A hard limit on the number of distinct leaks, to avoid quadratic complexity
+// in LeakReport::Add(). We don't expect to ever see this many leaks in
+// real-world applications.
+// FIXME: Get rid of this limit by changing the implementation of LeakReport to
+// use a hash table.
+const uptr kMaxLeaksConsidered = 5000;
+
+void LeakReport::Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag) {
+  CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked);
+  bool is_directly_leaked = (tag == kDirectlyLeaked);
+  for (uptr i = 0; i < leaks_.size(); i++)
+    if (leaks_[i].stack_trace_id == stack_trace_id &&
+        leaks_[i].is_directly_leaked == is_directly_leaked) {
+      leaks_[i].hit_count++;
+      leaks_[i].total_size += leaked_size;
+      return;
+    }
+  if (leaks_.size() == kMaxLeaksConsidered) return;
+  Leak leak = { /* hit_count */ 1, leaked_size, stack_trace_id,
+                is_directly_leaked, /* is_suppressed */ false };
+  leaks_.push_back(leak);
+}
+
+static bool LeakComparator(const Leak &leak1, const Leak &leak2) {
+  if (leak1.is_directly_leaked == leak2.is_directly_leaked)
+    return leak1.total_size > leak2.total_size;
+  else
+    return leak1.is_directly_leaked;
+}
+
+void LeakReport::PrintLargest(uptr num_leaks_to_print) {
+  CHECK(leaks_.size() <= kMaxLeaksConsidered);
+  Printf("\n");
+  if (leaks_.size() == kMaxLeaksConsidered)
+    Printf("Too many leaks! Only the first %zu leaks encountered will be "
+           "reported.\n",
+           kMaxLeaksConsidered);
+
+  uptr unsuppressed_count = 0;
+  for (uptr i = 0; i < leaks_.size(); i++)
+    if (!leaks_[i].is_suppressed) unsuppressed_count++;
+  if (num_leaks_to_print > 0 && num_leaks_to_print < unsuppressed_count)
+    Printf("The %zu largest leak(s):\n", num_leaks_to_print);
+  InternalSort(&leaks_, leaks_.size(), LeakComparator);
+  uptr leaks_printed = 0;
+  for (uptr i = 0; i < leaks_.size(); i++) {
+    if (leaks_[i].is_suppressed) continue;
+    Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n",
+           leaks_[i].is_directly_leaked ? "Direct" : "Indirect",
+           leaks_[i].total_size, leaks_[i].hit_count);
+    PrintStackTraceById(leaks_[i].stack_trace_id);
+    Printf("\n");
+    leaks_printed++;
+    if (leaks_printed == num_leaks_to_print) break;
+  }
+  if (leaks_printed < unsuppressed_count) {
+    uptr remaining = unsuppressed_count - leaks_printed;
+    Printf("Omitting %zu more leak(s).\n", remaining);
+  }
+}
+
+void LeakReport::PrintSummary() {
+  CHECK(leaks_.size() <= kMaxLeaksConsidered);
+  uptr bytes = 0, allocations = 0;
+  for (uptr i = 0; i < leaks_.size(); i++) {
+      if (leaks_[i].is_suppressed) continue;
+      bytes += leaks_[i].total_size;
+      allocations += leaks_[i].hit_count;
+  }
+  const int kMaxSummaryLength = 128;
+  InternalScopedBuffer<char> summary(kMaxSummaryLength);
+  internal_snprintf(summary.data(), kMaxSummaryLength,
+                    "LeakSanitizer: %zu byte(s) leaked in %zu allocation(s).",
+                    bytes, allocations);
+  __sanitizer_report_error_summary(summary.data());
+}
+
+uptr LeakReport::ApplySuppressions() {
+  uptr unsuppressed_count = 0;
+  for (uptr i = 0; i < leaks_.size(); i++) {
+    Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id);
+    if (s) {
+      s->weight += leaks_[i].total_size;
+      s->hit_count += leaks_[i].hit_count;
+      leaks_[i].is_suppressed = true;
+    } else {
+    unsuppressed_count++;
+    }
+  }
+  return unsuppressed_count;
+}
+}  // namespace __lsan
+#endif  // CAN_SANITIZE_LEAKS
+
+using namespace __lsan;  // NOLINT
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_ignore_object(const void *p) {
+#if CAN_SANITIZE_LEAKS
+  // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not
+  // locked.
+  BlockingMutexLock l(&global_mutex);
+  IgnoreObjectResult res = IgnoreObjectLocked(p);
+  if (res == kIgnoreObjectInvalid && flags()->verbosity >= 2)
+    Report("__lsan_ignore_object(): no heap object found at %p", p);
+  if (res == kIgnoreObjectAlreadyIgnored && flags()->verbosity >= 2)
+    Report("__lsan_ignore_object(): "
+           "heap object at %p is already being ignored\n", p);
+  if (res == kIgnoreObjectSuccess && flags()->verbosity >= 3)
+    Report("__lsan_ignore_object(): ignoring heap object at %p\n", p);
+#endif  // CAN_SANITIZE_LEAKS
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_disable() {
+#if CAN_SANITIZE_LEAKS
+  __lsan::disable_counter++;
+#endif
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_enable() {
+#if CAN_SANITIZE_LEAKS
+  if (!__lsan::disable_counter) {
+    Report("Unmatched call to __lsan_enable().\n");
+    Die();
+  }
+  __lsan::disable_counter--;
+#endif
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_do_leak_check() {
+#if CAN_SANITIZE_LEAKS
+  if (common_flags()->detect_leaks)
+    __lsan::DoLeakCheck();
+#endif  // CAN_SANITIZE_LEAKS
+}
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+int __lsan_is_turned_off() {
+  return 0;
+}
+#endif
+}  // extern "C"
diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h
new file mode 100644
index 0000000..926dea8
--- /dev/null
+++ b/lib/lsan/lsan_common.h
@@ -0,0 +1,175 @@
+//=-- lsan_common.h -------------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// Private LSan header.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LSAN_COMMON_H
+#define LSAN_COMMON_H
+
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_platform.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+#if SANITIZER_LINUX && defined(__x86_64__)
+#define CAN_SANITIZE_LEAKS 1
+#else
+#define CAN_SANITIZE_LEAKS 0
+#endif
+
+namespace __lsan {
+
+// Chunk tags.
+enum ChunkTag {
+  kDirectlyLeaked = 0,  // default
+  kIndirectlyLeaked = 1,
+  kReachable = 2,
+  kIgnored = 3
+};
+
+struct Flags {
+  uptr pointer_alignment() const {
+    return use_unaligned ? 1 : sizeof(uptr);
+  }
+
+  // Print addresses of leaked objects after main leak report.
+  bool report_objects;
+  // Aggregate two objects into one leak if this many stack frames match. If
+  // zero, the entire stack trace must match.
+  int resolution;
+  // The number of leaks reported.
+  int max_leaks;
+  // If nonzero kill the process with this exit code upon finding leaks.
+  int exitcode;
+  // Suppressions file name.
+  const char* suppressions;
+
+  // Flags controlling the root set of reachable memory.
+  // Global variables (.data and .bss).
+  bool use_globals;
+  // Thread stacks.
+  bool use_stacks;
+  // Thread registers.
+  bool use_registers;
+  // TLS and thread-specific storage.
+  bool use_tls;
+
+  // Consider unaligned pointers valid.
+  bool use_unaligned;
+
+  // User-visible verbosity.
+  int verbosity;
+
+  // Debug logging.
+  bool log_pointers;
+  bool log_threads;
+};
+
+extern Flags lsan_flags;
+inline Flags *flags() { return &lsan_flags; }
+
+struct Leak {
+  uptr hit_count;
+  uptr total_size;
+  u32 stack_trace_id;
+  bool is_directly_leaked;
+  bool is_suppressed;
+};
+
+// Aggregates leaks by stack trace prefix.
+class LeakReport {
+ public:
+  LeakReport() : leaks_(1) {}
+  void Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag);
+  void PrintLargest(uptr max_leaks);
+  void PrintSummary();
+  bool IsEmpty() { return leaks_.size() == 0; }
+  uptr ApplySuppressions();
+ private:
+  InternalMmapVector<Leak> leaks_;
+};
+
+typedef InternalMmapVector<uptr> Frontier;
+
+// Platform-specific functions.
+void InitializePlatformSpecificModules();
+void ProcessGlobalRegions(Frontier *frontier);
+void ProcessPlatformSpecificAllocations(Frontier *frontier);
+
+void ScanRangeForPointers(uptr begin, uptr end,
+                          Frontier *frontier,
+                          const char *region_type, ChunkTag tag);
+
+enum IgnoreObjectResult {
+  kIgnoreObjectSuccess,
+  kIgnoreObjectAlreadyIgnored,
+  kIgnoreObjectInvalid
+};
+
+// Functions called from the parent tool.
+void InitCommonLsan();
+void DoLeakCheck();
+bool DisabledInThisThread();
+
+// The following must be implemented in the parent tool.
+
+void ForEachChunk(ForEachChunkCallback callback, void *arg);
+// Returns the address range occupied by the global allocator object.
+void GetAllocatorGlobalRange(uptr *begin, uptr *end);
+// Wrappers for allocator's ForceLock()/ForceUnlock().
+void LockAllocator();
+void UnlockAllocator();
+// Wrappers for ThreadRegistry access.
+void LockThreadRegistry();
+void UnlockThreadRegistry();
+bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+                           uptr *tls_begin, uptr *tls_end,
+                           uptr *cache_begin, uptr *cache_end);
+// If called from the main thread, updates the main thread's TID in the thread
+// registry. We need this to handle processes that fork() without a subsequent
+// exec(), which invalidates the recorded TID. To update it, we must call
+// gettid() from the main thread. Our solution is to call this function before
+// leak checking and also before every call to pthread_create() (to handle cases
+// where leak checking is initiated from a non-main thread).
+void EnsureMainThreadIDIsCorrect();
+// If p points into a chunk that has been allocated to the user, returns its
+// user-visible address. Otherwise, returns 0.
+uptr PointsIntoChunk(void *p);
+// Returns address of user-visible chunk contained in this allocator chunk.
+uptr GetUserBegin(uptr chunk);
+// Helper for __lsan_ignore_object().
+IgnoreObjectResult IgnoreObjectLocked(const void *p);
+// Wrapper for chunk metadata operations.
+class LsanMetadata {
+ public:
+  // Constructor accepts address of user-visible chunk.
+  explicit LsanMetadata(uptr chunk);
+  bool allocated() const;
+  ChunkTag tag() const;
+  void set_tag(ChunkTag value);
+  uptr requested_size() const;
+  u32 stack_trace_id() const;
+ private:
+  void *metadata_;
+};
+
+}  // namespace __lsan
+
+extern "C" {
+int __lsan_is_turned_off() SANITIZER_WEAK_ATTRIBUTE
+    SANITIZER_INTERFACE_ATTRIBUTE;
+const char *__lsan_default_suppressions() SANITIZER_WEAK_ATTRIBUTE
+    SANITIZER_INTERFACE_ATTRIBUTE;
+}  // extern "C"
+
+#endif  // LSAN_COMMON_H
diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc
new file mode 100644
index 0000000..08a0595
--- /dev/null
+++ b/lib/lsan/lsan_common_linux.cc
@@ -0,0 +1,126 @@
+//=-- lsan_common_linux.cc ------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// Implementation of common leak checking functionality. Linux-specific code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#include "lsan_common.h"
+
+#if CAN_SANITIZE_LEAKS && SANITIZER_LINUX
+#include <link.h>
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __lsan {
+
+static const char kLinkerName[] = "ld";
+// We request 2 modules matching "ld", so we can print a warning if there's more
+// than one match. But only the first one is actually used.
+static char linker_placeholder[2 * sizeof(LoadedModule)] ALIGNED(64);
+static LoadedModule *linker = 0;
+
+static bool IsLinker(const char* full_name) {
+  return LibraryNameIs(full_name, kLinkerName);
+}
+
+void InitializePlatformSpecificModules() {
+  internal_memset(linker_placeholder, 0, sizeof(linker_placeholder));
+  uptr num_matches = GetListOfModules(
+      reinterpret_cast<LoadedModule *>(linker_placeholder), 2, IsLinker);
+  if (num_matches == 1) {
+    linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
+    return;
+  }
+  if (num_matches == 0)
+    Report("LeakSanitizer: Dynamic linker not found. "
+           "TLS will not be handled correctly.\n");
+  else if (num_matches > 1)
+    Report("LeakSanitizer: Multiple modules match \"%s\". "
+           "TLS will not be handled correctly.\n", kLinkerName);
+  linker = 0;
+}
+
+static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
+                                        void *data) {
+  Frontier *frontier = reinterpret_cast<Frontier *>(data);
+  for (uptr j = 0; j < info->dlpi_phnum; j++) {
+    const ElfW(Phdr) *phdr = &(info->dlpi_phdr[j]);
+    // We're looking for .data and .bss sections, which reside in writeable,
+    // loadable segments.
+    if (!(phdr->p_flags & PF_W) || (phdr->p_type != PT_LOAD) ||
+        (phdr->p_memsz == 0))
+      continue;
+    uptr begin = info->dlpi_addr + phdr->p_vaddr;
+    uptr end = begin + phdr->p_memsz;
+    uptr allocator_begin = 0, allocator_end = 0;
+    GetAllocatorGlobalRange(&allocator_begin, &allocator_end);
+    if (begin <= allocator_begin && allocator_begin < end) {
+      CHECK_LE(allocator_begin, allocator_end);
+      CHECK_LT(allocator_end, end);
+      if (begin < allocator_begin)
+        ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL",
+                             kReachable);
+      if (allocator_end < end)
+        ScanRangeForPointers(allocator_end, end, frontier, "GLOBAL",
+                             kReachable);
+    } else {
+      ScanRangeForPointers(begin, end, frontier, "GLOBAL", kReachable);
+    }
+  }
+  return 0;
+}
+
+// Scans global variables for heap pointers.
+void ProcessGlobalRegions(Frontier *frontier) {
+  // FIXME: dl_iterate_phdr acquires a linker lock, so we run a risk of
+  // deadlocking by running this under StopTheWorld. However, the lock is
+  // reentrant, so we should be able to fix this by acquiring the lock before
+  // suspending threads.
+  dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier);
+}
+
+static uptr GetCallerPC(u32 stack_id) {
+  CHECK(stack_id);
+  uptr size = 0;
+  const uptr *trace = StackDepotGet(stack_id, &size);
+  // The top frame is our malloc/calloc/etc. The next frame is the caller.
+  if (size >= 2)
+    return trace[1];
+  return 0;
+}
+
+// ForEachChunk callback. Identifies unreachable chunks which must be treated as
+// reachable. Marks them as reachable and adds them to the frontier.
+static void ProcessPlatformSpecificAllocationsCb(uptr chunk, void *arg) {
+  CHECK(arg);
+  chunk = GetUserBegin(chunk);
+  LsanMetadata m(chunk);
+  if (m.allocated() && m.tag() != kReachable) {
+    if (linker->containsAddress(GetCallerPC(m.stack_trace_id()))) {
+      m.set_tag(kReachable);
+      reinterpret_cast<Frontier *>(arg)->push_back(chunk);
+    }
+  }
+}
+
+// Handles dynamically allocated TLS blocks by treating all chunks allocated
+// from ld-linux.so as reachable.
+void ProcessPlatformSpecificAllocations(Frontier *frontier) {
+  if (!flags()->use_tls) return;
+  if (!linker) return;
+  ForEachChunk(ProcessPlatformSpecificAllocationsCb, frontier);
+}
+
+}  // namespace __lsan
+#endif  // CAN_SANITIZE_LEAKS && SANITIZER_LINUX
diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc
new file mode 100644
index 0000000..454b556
--- /dev/null
+++ b/lib/lsan/lsan_interceptors.cc
@@ -0,0 +1,281 @@
+//=-- lsan_interceptors.cc ------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// Interceptors for standalone LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "lsan.h"
+#include "lsan_allocator.h"
+#include "lsan_thread.h"
+
+using namespace __lsan;
+
+extern "C" {
+int pthread_attr_init(void *attr);
+int pthread_attr_destroy(void *attr);
+int pthread_attr_getdetachstate(void *attr, int *v);
+int pthread_key_create(unsigned *key, void (*destructor)(void* v));
+int pthread_setspecific(unsigned key, const void *v);
+}
+
+#define GET_STACK_TRACE                                                      \
+  StackTrace stack;                                                          \
+  {                                                                          \
+    uptr stack_top = 0, stack_bottom = 0;                                    \
+    ThreadContext *t;                                                        \
+    bool fast = common_flags()->fast_unwind_on_malloc;                       \
+    if (fast && (t = CurrentThreadContext())) {                              \
+      stack_top = t->stack_end();                                            \
+      stack_bottom = t->stack_begin();                                       \
+    }                                                                        \
+    GetStackTrace(&stack, __sanitizer::common_flags()->malloc_context_size,  \
+                  StackTrace::GetCurrentPc(),                                \
+                  GET_CURRENT_FRAME(), stack_top, stack_bottom, fast);       \
+  }
+
+///// Malloc/free interceptors. /////
+
+const bool kAlwaysClearMemory = true;
+
+namespace std {
+  struct nothrow_t;
+}
+
+INTERCEPTOR(void*, malloc, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  return Allocate(stack, size, 1, kAlwaysClearMemory);
+}
+
+INTERCEPTOR(void, free, void *p) {
+  Init();
+  Deallocate(p);
+}
+
+INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+  if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
+  Init();
+  GET_STACK_TRACE;
+  size *= nmemb;
+  return Allocate(stack, size, 1, true);
+}
+
+INTERCEPTOR(void*, realloc, void *q, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  return Reallocate(stack, q, size, 1);
+}
+
+INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  return Allocate(stack, size, alignment, kAlwaysClearMemory);
+}
+
+INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
+  // FIXME: Return ENOMEM if user requested more than max alloc size.
+  return 0;
+}
+
+INTERCEPTOR(void*, valloc, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  if (size == 0)
+    size = GetPageSizeCached();
+  return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
+}
+
+INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+  Init();
+  return GetMallocUsableSize(ptr);
+}
+
+struct fake_mallinfo {
+  int x[10];
+};
+
+INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
+  struct fake_mallinfo res;
+  internal_memset(&res, 0, sizeof(res));
+  return res;
+}
+
+INTERCEPTOR(int, mallopt, int cmd, int value) {
+  return -1;
+}
+
+INTERCEPTOR(void*, pvalloc, uptr size) {
+  Init();
+  GET_STACK_TRACE;
+  uptr PageSize = GetPageSizeCached();
+  size = RoundUpTo(size, PageSize);
+  if (size == 0) {
+    // pvalloc(0) should allocate one page.
+    size = PageSize;
+  }
+  return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
+}
+
+INTERCEPTOR(void, cfree, void *p) ALIAS("free");
+
+#define OPERATOR_NEW_BODY                              \
+  Init();                                              \
+  GET_STACK_TRACE;                                     \
+  return Allocate(stack, size, 1, kAlwaysClearMemory);
+
+INTERCEPTOR_ATTRIBUTE
+void *operator new(uptr size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](uptr size) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new(uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+
+#define OPERATOR_DELETE_BODY \
+  Init();                    \
+  Deallocate(ptr);
+
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr, std::nothrow_t const &) {
+  OPERATOR_DELETE_BODY;
+}
+
+// We need this to intercept the __libc_memalign calls that are used to
+// allocate dynamic TLS space in ld-linux.so.
+INTERCEPTOR(void *, __libc_memalign, uptr align, uptr s) ALIAS("memalign");
+
+///// Thread initialization and finalization. /////
+
+static unsigned g_thread_finalize_key;
+
+static void thread_finalize(void *v) {
+  uptr iter = (uptr)v;
+  if (iter > 1) {
+    if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
+      Report("LeakSanitizer: failed to set thread key.\n");
+      Die();
+    }
+    return;
+  }
+  ThreadFinish();
+}
+
+struct ThreadParam {
+  void *(*callback)(void *arg);
+  void *param;
+  atomic_uintptr_t tid;
+};
+
+// PTHREAD_DESTRUCTOR_ITERATIONS from glibc.
+const uptr kPthreadDestructorIterations = 4;
+
+extern "C" void *__lsan_thread_start_func(void *arg) {
+  ThreadParam *p = (ThreadParam*)arg;
+  void* (*callback)(void *arg) = p->callback;
+  void *param = p->param;
+  // Wait until the last iteration to maximize the chance that we are the last
+  // destructor to run.
+  if (pthread_setspecific(g_thread_finalize_key,
+                          (void*)kPthreadDestructorIterations)) {
+    Report("LeakSanitizer: failed to set thread key.\n");
+    Die();
+  }
+  int tid = 0;
+  while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
+    internal_sched_yield();
+  atomic_store(&p->tid, 0, memory_order_release);
+  SetCurrentThread(tid);
+  ThreadStart(tid, GetTid());
+  return callback(param);
+}
+
+INTERCEPTOR(int, pthread_create, void *th, void *attr,
+            void *(*callback)(void *), void *param) {
+  Init();
+  EnsureMainThreadIDIsCorrect();
+  __sanitizer_pthread_attr_t myattr;
+  if (attr == 0) {
+    pthread_attr_init(&myattr);
+    attr = &myattr;
+  }
+  AdjustStackSizeLinux(attr, 0);
+  int detached = 0;
+  pthread_attr_getdetachstate(attr, &detached);
+  ThreadParam p;
+  p.callback = callback;
+  p.param = param;
+  atomic_store(&p.tid, 0, memory_order_relaxed);
+  int res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
+  if (res == 0) {
+    int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached);
+    CHECK_NE(tid, 0);
+    atomic_store(&p.tid, tid, memory_order_release);
+    while (atomic_load(&p.tid, memory_order_acquire) != 0)
+      internal_sched_yield();
+  }
+  if (attr == &myattr)
+    pthread_attr_destroy(&myattr);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_join, void *th, void **ret) {
+  Init();
+  int tid = ThreadTid((uptr)th);
+  int res = REAL(pthread_join)(th, ret);
+  if (res == 0)
+    ThreadJoin(tid);
+  return res;
+}
+
+namespace __lsan {
+
+void InitializeInterceptors() {
+  INTERCEPT_FUNCTION(malloc);
+  INTERCEPT_FUNCTION(free);
+  INTERCEPT_FUNCTION(cfree);
+  INTERCEPT_FUNCTION(calloc);
+  INTERCEPT_FUNCTION(realloc);
+  INTERCEPT_FUNCTION(memalign);
+  INTERCEPT_FUNCTION(posix_memalign);
+  INTERCEPT_FUNCTION(__libc_memalign);
+  INTERCEPT_FUNCTION(valloc);
+  INTERCEPT_FUNCTION(pvalloc);
+  INTERCEPT_FUNCTION(malloc_usable_size);
+  INTERCEPT_FUNCTION(mallinfo);
+  INTERCEPT_FUNCTION(mallopt);
+  INTERCEPT_FUNCTION(pthread_create);
+  INTERCEPT_FUNCTION(pthread_join);
+
+  if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
+    Report("LeakSanitizer: failed to create thread key.\n");
+    Die();
+  }
+}
+
+}  // namespace __lsan
diff --git a/lib/lsan/lsan_thread.cc b/lib/lsan/lsan_thread.cc
new file mode 100644
index 0000000..3bfccdf
--- /dev/null
+++ b/lib/lsan/lsan_thread.cc
@@ -0,0 +1,156 @@
+//=-- lsan_thread.cc ------------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// See lsan_thread.h for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan_thread.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
+#include "lsan_allocator.h"
+
+namespace __lsan {
+
+const u32 kInvalidTid = (u32) -1;
+
+static ThreadRegistry *thread_registry;
+static THREADLOCAL u32 current_thread_tid = kInvalidTid;
+
+static ThreadContextBase *CreateThreadContext(u32 tid) {
+  void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
+  return new(mem) ThreadContext(tid);
+}
+
+static const uptr kMaxThreads = 1 << 13;
+static const uptr kThreadQuarantineSize = 64;
+
+void InitializeThreadRegistry() {
+  static char thread_registry_placeholder[sizeof(ThreadRegistry)] ALIGNED(64);
+  thread_registry = new(thread_registry_placeholder)
+    ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
+}
+
+u32 GetCurrentThread() {
+  return current_thread_tid;
+}
+
+void SetCurrentThread(u32 tid) {
+  current_thread_tid = tid;
+}
+
+ThreadContext::ThreadContext(int tid)
+  : ThreadContextBase(tid),
+    stack_begin_(0),
+    stack_end_(0),
+    cache_begin_(0),
+    cache_end_(0),
+    tls_begin_(0),
+    tls_end_(0) {}
+
+struct OnStartedArgs {
+  uptr stack_begin, stack_end,
+       cache_begin, cache_end,
+       tls_begin, tls_end;
+};
+
+void ThreadContext::OnStarted(void *arg) {
+  OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg);
+  stack_begin_ = args->stack_begin;
+  stack_end_ = args->stack_end;
+  tls_begin_ = args->tls_begin;
+  tls_end_ = args->tls_end;
+  cache_begin_ = args->cache_begin;
+  cache_end_ = args->cache_end;
+}
+
+void ThreadContext::OnFinished() {
+  AllocatorThreadFinish();
+}
+
+u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) {
+  return thread_registry->CreateThread(user_id, detached, parent_tid,
+                                       /* arg */ 0);
+}
+
+void ThreadStart(u32 tid, uptr os_id) {
+  OnStartedArgs args;
+  uptr stack_size = 0;
+  uptr tls_size = 0;
+  GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
+                       &args.tls_begin, &tls_size);
+  args.stack_end = args.stack_begin + stack_size;
+  args.tls_end = args.tls_begin + tls_size;
+  GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
+  thread_registry->StartThread(tid, os_id, &args);
+}
+
+void ThreadFinish() {
+  thread_registry->FinishThread(GetCurrentThread());
+}
+
+ThreadContext *CurrentThreadContext() {
+  if (!thread_registry) return 0;
+  if (GetCurrentThread() == kInvalidTid)
+    return 0;
+  // No lock needed when getting current thread.
+  return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread());
+}
+
+static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
+  uptr uid = (uptr)arg;
+  if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
+    return true;
+  }
+  return false;
+}
+
+u32 ThreadTid(uptr uid) {
+  return thread_registry->FindThread(FindThreadByUid, (void*)uid);
+}
+
+void ThreadJoin(u32 tid) {
+  CHECK_NE(tid, kInvalidTid);
+  thread_registry->JoinThread(tid, /* arg */0);
+}
+
+void EnsureMainThreadIDIsCorrect() {
+  if (GetCurrentThread() == 0)
+    CurrentThreadContext()->os_id = GetTid();
+}
+
+///// Interface to the common LSan module. /////
+
+bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+                           uptr *tls_begin, uptr *tls_end,
+                           uptr *cache_begin, uptr *cache_end) {
+  ThreadContext *context = static_cast<ThreadContext *>(
+      thread_registry->FindThreadContextByOsIDLocked(os_id));
+  if (!context) return false;
+  *stack_begin = context->stack_begin();
+  *stack_end = context->stack_end();
+  *tls_begin = context->tls_begin();
+  *tls_end = context->tls_end();
+  *cache_begin = context->cache_begin();
+  *cache_end = context->cache_end();
+  return true;
+}
+
+void LockThreadRegistry() {
+  thread_registry->Lock();
+}
+
+void UnlockThreadRegistry() {
+  thread_registry->Unlock();
+}
+
+}  // namespace __lsan
diff --git a/lib/lsan/lsan_thread.h b/lib/lsan/lsan_thread.h
new file mode 100644
index 0000000..4641b32
--- /dev/null
+++ b/lib/lsan/lsan_thread.h
@@ -0,0 +1,53 @@
+//=-- lsan_thread.h -------------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// Thread registry for standalone LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LSAN_THREAD_H
+#define LSAN_THREAD_H
+
+#include "sanitizer_common/sanitizer_thread_registry.h"
+
+namespace __lsan {
+
+class ThreadContext : public ThreadContextBase {
+ public:
+  explicit ThreadContext(int tid);
+  void OnStarted(void *arg);
+  void OnFinished();
+  uptr stack_begin() { return stack_begin_; }
+  uptr stack_end() { return stack_end_; }
+  uptr tls_begin() { return tls_begin_; }
+  uptr tls_end() { return tls_end_; }
+  uptr cache_begin() { return cache_begin_; }
+  uptr cache_end() { return cache_end_; }
+ private:
+  uptr stack_begin_, stack_end_,
+       cache_begin_, cache_end_,
+       tls_begin_, tls_end_;
+};
+
+void InitializeThreadRegistry();
+
+void ThreadStart(u32 tid, uptr os_id);
+void ThreadFinish();
+u32 ThreadCreate(u32 tid, uptr uid, bool detached);
+void ThreadJoin(u32 tid);
+u32 ThreadTid(uptr uid);
+
+u32 GetCurrentThread();
+void SetCurrentThread(u32 tid);
+ThreadContext *CurrentThreadContext();
+void EnsureMainThreadIDIsCorrect();
+}  // namespace __lsan
+
+#endif  // LSAN_THREAD_H
diff --git a/lib/lsan/tests/CMakeLists.txt b/lib/lsan/tests/CMakeLists.txt
new file mode 100644
index 0000000..38a5556
--- /dev/null
+++ b/lib/lsan/tests/CMakeLists.txt
@@ -0,0 +1,58 @@
+include(CheckCXXCompilerFlag)
+include(CompilerRTCompile)
+include(CompilerRTLink)
+
+include_directories(..)
+include_directories(../..)
+
+set(LSAN_TESTS_SRC
+  lsan_dummy_unittest.cc)
+
+set(LSAN_TESTS_CFLAGS
+  ${LSAN_CFLAGS}
+  ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
+  -I${COMPILER_RT_SOURCE_DIR}/lib
+  -I${LSAN_SRC_DIR})
+
+set(LSAN_TEST_LINK_FLAGS_COMMON
+  -lstdc++ -ldl -lpthread -lm)
+
+add_custom_target(LsanUnitTests)
+set_target_properties(LsanUnitTests PROPERTIES
+  FOLDER "LSan unit tests")
+
+# Compile source for the given architecture, using compiler
+# options in ${ARGN}, and add it to the object list.
+macro(lsan_compile obj_list source arch)
+  get_filename_component(basename ${source} NAME)
+  set(output_obj "${basename}.${arch}.o")
+  get_target_flags_for_arch(${arch} TARGET_CFLAGS)
+  clang_compile(${output_obj} ${source}
+                CFLAGS ${ARGN} ${TARGET_CFLAGS}
+                DEPS gtest ${LSAN_RUNTIME_LIBRARIES})
+  list(APPEND ${obj_list} ${output_obj})
+endmacro()
+
+function(add_lsan_test test_suite test_name arch)
+  get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
+  add_compiler_rt_test(${test_suite} ${test_name}
+                       OBJECTS ${ARGN}
+                       DEPS ${LSAN_RUNTIME_LIBRARIES} ${ARGN}
+                       LINK_FLAGS ${LSAN_TEST_LINK_FLAGS_COMMON}
+                                  ${TARGET_LINK_FLAGS})
+endfunction()
+
+macro(add_lsan_tests_for_arch arch)
+  set(LSAN_TESTS_OBJ)
+  set(LSAN_TEST_SOURCES ${LSAN_TESTS_SRC}
+                        ${COMPILER_RT_GTEST_SOURCE})
+  foreach(source ${LSAN_TEST_SOURCES})
+    lsan_compile(LSAN_TESTS_OBJ ${source} ${arch} ${LSAN_TESTS_CFLAGS})
+  endforeach()
+  add_lsan_test(LsanUnitTests Lsan-${arch}-Test ${arch} ${LSAN_TESTS_OBJ})
+endmacro()
+
+# Build tests for 64-bit Linux only.
+if(UNIX AND NOT APPLE AND CAN_TARGET_x86_64)
+  add_lsan_tests_for_arch(x86_64)
+endif()
diff --git a/lib/lsan/tests/lsan_dummy_unittest.cc b/lib/lsan/tests/lsan_dummy_unittest.cc
new file mode 100644
index 0000000..5468400
--- /dev/null
+++ b/lib/lsan/tests/lsan_dummy_unittest.cc
@@ -0,0 +1,22 @@
+//===-- lsan_dummy_unittest.cc --------------------------------------------===//
+//
+//                     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 LeakSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "gtest/gtest.h"
+
+TEST(LeakSanitizer, EmptyTest) {
+  // Empty test to suppress LIT warnings about lack of tests.
+}
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/lib/lsan/tests/lsan_testlib.cc b/lib/lsan/tests/lsan_testlib.cc
new file mode 100644
index 0000000..363cc14
--- /dev/null
+++ b/lib/lsan/tests/lsan_testlib.cc
@@ -0,0 +1,25 @@
+//===-- lsan_testlib.cc ---------------------------------------------------===//
+//
+//                     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 LeakSanitizer.
+// Standalone LSan tool as a shared library, to be used with LD_PRELOAD.
+//
+//===----------------------------------------------------------------------===//
+/* Usage:
+clang++ ../sanitizer_common/sanitizer_*.cc ../interception/interception_*.cc \
+ lsan*.cc tests/lsan_testlib.cc -I. -I.. -g -ldl -lpthread -fPIC -shared -O2 \
+ -o lsan.so
+LD_PRELOAD=./lsan.so /your/app
+*/
+#include "lsan.h"
+
+__attribute__((constructor))
+void constructor() {
+  __lsan::Init();
+}
diff --git a/lib/msan/CMakeLists.txt b/lib/msan/CMakeLists.txt
index 6f10942..b3e88ea 100644
--- a/lib/msan/CMakeLists.txt
+++ b/lib/msan/CMakeLists.txt
@@ -24,10 +24,22 @@
     SOURCES ${MSAN_RTL_SOURCES}
             $<TARGET_OBJECTS:RTInterception.${arch}>
             $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
-    CFLAGS ${MSAN_RTL_CFLAGS})
+            $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+    CFLAGS ${MSAN_RTL_CFLAGS}
+    SYMS msan.syms)
   list(APPEND MSAN_RUNTIME_LIBRARIES clang_rt.msan-${arch})
 endif()
 
+add_compiler_rt_resource_file(msan_blacklist msan_blacklist.txt)
+
+# We should only build MSan unit tests if we can build instrumented libcxx.
+set(MSAN_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx)
+if(EXISTS ${MSAN_LIBCXX_PATH}/)
+  set(MSAN_CAN_INSTRUMENT_LIBCXX TRUE)
+else()
+  set(MSAN_CAN_INSTRUMENT_LIBCXX FALSE)
+endif()
+
 if(LLVM_INCLUDE_TESTS)
   add_subdirectory(tests)
 endif()
diff --git a/lib/msan/lit_tests/CMakeLists.txt b/lib/msan/lit_tests/CMakeLists.txt
index 62b2101..3fcb348 100644
--- a/lib/msan/lit_tests/CMakeLists.txt
+++ b/lib/msan/lit_tests/CMakeLists.txt
@@ -3,24 +3,23 @@
 
 configure_lit_site_cfg(
   ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
-  )
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
 
-configure_lit_site_cfg(
-  ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
-  ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
-  )
+if(MSAN_CAN_INSTRUMENT_LIBCXX)
+  configure_lit_site_cfg(
+    ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+    ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)
+endif()
 
 if(COMPILER_RT_CAN_EXECUTE_TESTS)
   # Run MSan tests only if we're sure we may produce working binaries.
   set(MSAN_TEST_DEPS
-    clang clang-headers FileCheck count not llvm-nm llvm-symbolizer
+    ${SANITIZER_COMMON_LIT_TEST_DEPS}
     ${MSAN_RUNTIME_LIBRARIES}
-    )
+    msan_blacklist)
   set(MSAN_TEST_PARAMS
-    msan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
-    )
-  if(LLVM_INCLUDE_TESTS)
+    msan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+  if(LLVM_INCLUDE_TESTS AND MSAN_CAN_INSTRUMENT_LIBCXX)
     list(APPEND MSAN_TEST_DEPS MsanUnitTests)
   endif()
   add_lit_testsuite(check-msan "Running the MemorySanitizer tests"
diff --git a/lib/msan/lit_tests/Linux/glob.cc b/lib/msan/lit_tests/Linux/glob.cc
new file mode 100644
index 0000000..387ce3c
--- /dev/null
+++ b/lib/msan/lit_tests/Linux/glob.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+int main(int argc, char *argv[]) {
+  assert(argc == 2);
+  char buf[1024];
+  snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*a");
+
+  glob_t globbuf;
+  int res = glob(buf, 0, 0, &globbuf);
+
+  printf("%d %s\n", errno, strerror(errno));
+  assert(res == 0);
+  assert(globbuf.gl_pathc == 2);
+  printf("%zu\n", strlen(globbuf.gl_pathv[0]));
+  printf("%zu\n", strlen(globbuf.gl_pathv[1]));
+  printf("PASS\n");
+  // CHECK: PASS
+  return 0;
+}
diff --git a/lib/msan/lit_tests/Linux/glob_altdirfunc.cc b/lib/msan/lit_tests/Linux/glob_altdirfunc.cc
new file mode 100644
index 0000000..b8200c3
--- /dev/null
+++ b/lib/msan/lit_tests/Linux/glob_altdirfunc.cc
@@ -0,0 +1,78 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+static void my_gl_closedir(void *dir) {
+  if (!dir)
+    exit(1);
+  closedir((DIR *)dir);
+}
+
+static struct dirent *my_gl_readdir(void *dir) {
+  if (!dir)
+    exit(1);
+  struct dirent *d = readdir((DIR *)dir);
+  if (d) __msan_poison(d, d->d_reclen); // hehe
+  return d;
+}
+
+static void *my_gl_opendir(const char *s) {
+  assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
+  return opendir(s);
+}
+
+static int my_gl_lstat(const char *s, struct stat *st) {
+  assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
+  if (!st)
+    exit(1);
+  return lstat(s, st);
+}
+
+static int my_gl_stat(const char *s, struct stat *st) {
+  assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
+  if (!st)
+    exit(1);
+  return lstat(s, st);
+}
+
+int main(int argc, char *argv[]) {
+  assert(argc == 2);
+  char buf[1024];
+  snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*a");
+
+  glob_t globbuf;
+  globbuf.gl_closedir = my_gl_closedir;
+  globbuf.gl_readdir = my_gl_readdir;
+  globbuf.gl_opendir = my_gl_opendir;
+  globbuf.gl_lstat = my_gl_lstat;
+  globbuf.gl_stat = my_gl_stat;
+  for (int i = 0; i < 10000; ++i) {
+    int res = glob(buf, GLOB_ALTDIRFUNC | GLOB_MARK, 0, &globbuf);
+    assert(res == 0);
+    printf("%d %s\n", errno, strerror(errno));
+    assert(globbuf.gl_pathc == 2);
+    printf("%zu\n", strlen(globbuf.gl_pathv[0]));
+    printf("%zu\n", strlen(globbuf.gl_pathv[1]));
+    __msan_poison(globbuf.gl_pathv[0], strlen(globbuf.gl_pathv[0]) + 1);
+    __msan_poison(globbuf.gl_pathv[1], strlen(globbuf.gl_pathv[1]) + 1);
+    globfree(&globbuf);
+  }
+
+  printf("PASS\n");
+  // CHECK: PASS
+  return 0;
+}
diff --git a/lib/msan/lit_tests/Linux/glob_nomatch.cc b/lib/msan/lit_tests/Linux/glob_nomatch.cc
new file mode 100644
index 0000000..0262034
--- /dev/null
+++ b/lib/msan/lit_tests/Linux/glob_nomatch.cc
@@ -0,0 +1,21 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+  assert(argc == 2);
+  char buf[1024];
+  snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*c");
+
+  glob_t globbuf;
+  int res = glob(buf, 0, 0, &globbuf);
+  assert(res == GLOB_NOMATCH);
+  assert(globbuf.gl_pathc == 0);
+  if (globbuf.gl_pathv == 0)
+    exit(0);
+  return 0;
+}
diff --git a/lib/msan/lit_tests/Linux/glob_test_root/aa b/lib/msan/lit_tests/Linux/glob_test_root/aa
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/msan/lit_tests/Linux/glob_test_root/aa
diff --git a/lib/msan/lit_tests/Linux/glob_test_root/ab b/lib/msan/lit_tests/Linux/glob_test_root/ab
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/msan/lit_tests/Linux/glob_test_root/ab
diff --git a/lib/msan/lit_tests/Linux/glob_test_root/ba b/lib/msan/lit_tests/Linux/glob_test_root/ba
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/msan/lit_tests/Linux/glob_test_root/ba
diff --git a/lib/asan/lit_tests/Linux/lit.local.cfg b/lib/msan/lit_tests/Linux/lit.local.cfg
similarity index 100%
rename from lib/asan/lit_tests/Linux/lit.local.cfg
rename to lib/msan/lit_tests/Linux/lit.local.cfg
diff --git a/lib/msan/lit_tests/Linux/syscalls.cc b/lib/msan/lit_tests/Linux/syscalls.cc
new file mode 100644
index 0000000..afab18d
--- /dev/null
+++ b/lib/msan/lit_tests/Linux/syscalls.cc
@@ -0,0 +1,68 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t 2>&1
+
+#include <assert.h>
+#include <errno.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sanitizer/linux_syscall_hooks.h>
+#include <sanitizer/msan_interface.h>
+
+/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general
+   sanity of their behaviour. */
+
+int main(int argc, char *argv[]) {
+  char buf[1000];
+  const int kTen = 10;
+  memset(buf, 0, sizeof(buf));
+  __msan_unpoison(buf, sizeof(buf));
+  __sanitizer_syscall_pre_recvmsg(0, buf, 0);
+  __sanitizer_syscall_pre_rt_sigpending(buf, kTen);
+  __sanitizer_syscall_pre_getdents(0, buf, kTen);
+  __sanitizer_syscall_pre_getdents64(0, buf, kTen);
+
+  __msan_unpoison(buf, sizeof(buf));
+  __sanitizer_syscall_post_recvmsg(0, 0, buf, 0);
+  __sanitizer_syscall_post_rt_sigpending(-1, buf, kTen);
+  __sanitizer_syscall_post_getdents(0, 0, buf, kTen);
+  __sanitizer_syscall_post_getdents64(0, 0, buf, kTen);
+  assert(__msan_test_shadow(buf, sizeof(buf)) == -1);
+
+  __msan_unpoison(buf, sizeof(buf));
+  __sanitizer_syscall_post_recvmsg(kTen, 0, buf, 0);
+
+  // Tell the kernel that the output struct size is 10 bytes, verify that those
+  // bytes are unpoisoned, and the next byte is not.
+  __msan_poison(buf, kTen + 1);
+  __sanitizer_syscall_post_rt_sigpending(0, buf, kTen);
+  assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
+
+  __msan_poison(buf, kTen + 1);
+  __sanitizer_syscall_post_getdents(kTen, 0, buf, kTen);
+  assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
+
+  __msan_poison(buf, kTen + 1);
+  __sanitizer_syscall_post_getdents64(kTen, 0, buf, kTen);
+  assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
+
+  __msan_poison(buf, sizeof(buf));
+  __sanitizer_syscall_post_clock_getres(0, 0, buf);
+  assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(long) * 2);
+
+  __msan_poison(buf, sizeof(buf));
+  __sanitizer_syscall_post_clock_gettime(0, 0, buf);
+  assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(long) * 2);
+
+  // Failed syscall does not write to the buffer.
+  __msan_poison(buf, sizeof(buf));
+  __sanitizer_syscall_post_clock_gettime(-1, 0, buf);
+  assert(__msan_test_shadow(buf, sizeof(buf)) == 0);
+
+  __msan_poison(buf, sizeof(buf));
+  __sanitizer_syscall_post_read(5, 42, buf, 10);
+  assert(__msan_test_shadow(buf, sizeof(buf)) == 5);
+  
+  return 0;
+}
diff --git a/lib/msan/lit_tests/Linux/tcgetattr.cc b/lib/msan/lit_tests/Linux/tcgetattr.cc
new file mode 100644
index 0000000..e6e101d
--- /dev/null
+++ b/lib/msan/lit_tests/Linux/tcgetattr.cc
@@ -0,0 +1,21 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[]) {
+  int fd = getpt();
+  assert(fd >= 0);
+  
+  struct termios t;
+  int res = tcgetattr(fd, &t);
+  assert(!res);
+
+  if (t.c_iflag == 0)
+    exit(0);
+  return 0;
+}
diff --git a/lib/msan/lit_tests/SharedLibs/dso-origin-so.cc b/lib/msan/lit_tests/SharedLibs/dso-origin-so.cc
new file mode 100644
index 0000000..8930a71
--- /dev/null
+++ b/lib/msan/lit_tests/SharedLibs/dso-origin-so.cc
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+
+#include "dso-origin.h"
+
+void my_access(int *p) {
+  volatile int tmp;
+  // Force initialize-ness check.
+  if (*p)
+    tmp = 1;
+}
+
+void *my_alloc(unsigned sz) {
+  return malloc(sz);
+}
diff --git a/lib/msan/lit_tests/SharedLibs/dso-origin.h b/lib/msan/lit_tests/SharedLibs/dso-origin.h
new file mode 100644
index 0000000..ff926b3
--- /dev/null
+++ b/lib/msan/lit_tests/SharedLibs/dso-origin.h
@@ -0,0 +1,4 @@
+extern "C" {
+void my_access(int *p);
+void *my_alloc(unsigned sz);
+}
diff --git a/lib/asan/lit_tests/SharedLibs/lit.local.cfg b/lib/msan/lit_tests/SharedLibs/lit.local.cfg
similarity index 100%
rename from lib/asan/lit_tests/SharedLibs/lit.local.cfg
rename to lib/msan/lit_tests/SharedLibs/lit.local.cfg
diff --git a/lib/msan/lit_tests/Unit/lit.cfg b/lib/msan/lit_tests/Unit/lit.cfg
deleted file mode 100644
index afb30e0..0000000
--- a/lib/msan/lit_tests/Unit/lit.cfg
+++ /dev/null
@@ -1,27 +0,0 @@
-# -*- Python -*-
-
-import os
-
-def get_required_attr(config, attr_name):
-  attr_value = getattr(config, attr_name, None)
-  if not attr_value:
-    lit.fatal("No attribute %r in test configuration! You may need to run "
-              "tests from your build directory or add this attribute "
-              "to lit.site.cfg " % attr_name)
-  return attr_value
-
-# Setup attributes common for all compiler-rt projects.
-llvm_src_root = get_required_attr(config, 'llvm_src_root')
-compiler_rt_lit_unit_cfg = os.path.join(llvm_src_root, "projects",
-                                        "compiler-rt", "lib",
-                                        "lit.common.unit.cfg")
-lit.load_config(config, compiler_rt_lit_unit_cfg)
-
-# Setup config name.
-config.name = 'MemorySanitizer-Unit'
-
-# Setup test source and exec root. For unit tests, we define
-# it as build directory with MSan unit tests.
-msan_binary_dir = get_required_attr(config, "msan_binary_dir")
-config.test_exec_root = os.path.join(msan_binary_dir, "tests")
-config.test_source_root = config.test_exec_root
diff --git a/lib/msan/lit_tests/Unit/lit.site.cfg.in b/lib/msan/lit_tests/Unit/lit.site.cfg.in
index 4ae84c4..52e1713 100644
--- a/lib/msan/lit_tests/Unit/lit.site.cfg.in
+++ b/lib/msan/lit_tests/Unit/lit.site.cfg.in
@@ -1,16 +1,13 @@
 ## Autogenerated by LLVM/Clang configuration.
 # Do not edit!
 
-config.target_triple = "@TARGET_TRIPLE@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.llvm_build_mode = "@LLVM_BUILD_MODE@"
-config.msan_binary_dir = "@MSAN_BINARY_DIR@"
+# Load common config for all compiler-rt unit tests.
+lit.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
 
-try:
-  config.llvm_build_mode = config.llvm_build_mode % lit.params
-except KeyError,e:
-  key, = e.args
-  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
+# Setup config name.
+config.name = 'MemorySanitizer-Unit'
 
-# Let the main config do the real work.
-lit.load_config(config, "@MSAN_SOURCE_DIR@/lit_tests/Unit/lit.cfg")
+# Setup test source and exec root. For unit tests, we define
+# it as build directory with MSan unit tests.
+config.test_exec_root = "@MSAN_BINARY_DIR@/tests"
+config.test_source_root = config.test_exec_root
diff --git a/lib/msan/lit_tests/default_blacklist.cc b/lib/msan/lit_tests/default_blacklist.cc
new file mode 100644
index 0000000..32cc022
--- /dev/null
+++ b/lib/msan/lit_tests/default_blacklist.cc
@@ -0,0 +1,3 @@
+// Test that MSan uses the default blacklist from resource directory.
+// RUN: %clangxx_msan -### %s 2>&1 | FileCheck %s
+// CHECK: fsanitize-blacklist={{.*}}msan_blacklist.txt
diff --git a/lib/msan/lit_tests/dso-origin.cc b/lib/msan/lit_tests/dso-origin.cc
new file mode 100644
index 0000000..13661c6
--- /dev/null
+++ b/lib/msan/lit_tests/dso-origin.cc
@@ -0,0 +1,25 @@
+// Build a library with origin tracking and an executable w/o origin tracking.
+// Test that origin tracking is enabled at runtime.
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %p/SharedLibs/dso-origin-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// RUN: %clangxx_msan -m64 -O0 %s %t-so.so -o %t && not %t 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+
+#include "SharedLibs/dso-origin.h"
+
+int main(int argc, char **argv) {
+  int *x = (int *)my_alloc(sizeof(int));
+  my_access(x);
+  delete x;
+
+  // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+  // CHECK: {{#0 0x.* in my_access .*dso-origin-so.cc:}}
+  // CHECK: {{#1 0x.* in main .*dso-origin.cc:}}[[@LINE-5]]
+  // CHECK: Uninitialized value was created by a heap allocation
+  // CHECK: {{#0 0x.* in .*malloc}}
+  // CHECK: {{#1 0x.* in my_alloc .*dso-origin-so.cc:}}
+  // CHECK: {{#2 0x.* in main .*dso-origin.cc:}}[[@LINE-10]]
+  // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*dso-origin-so.cc:.* my_access}}
+  return 0;
+}
diff --git a/lib/msan/lit_tests/getaddrinfo-positive.cc b/lib/msan/lit_tests/getaddrinfo-positive.cc
new file mode 100644
index 0000000..7fde1fd
--- /dev/null
+++ b/lib/msan/lit_tests/getaddrinfo-positive.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdlib.h>
+
+volatile int z;
+
+int main(void) {
+  struct addrinfo *ai;
+  struct addrinfo hint;
+  int res = getaddrinfo("localhost", NULL, NULL, &ai);
+  if (ai) z = 1; // OK
+  res = getaddrinfo("localhost", NULL, &hint, &ai);
+  // CHECK: UMR in __interceptor_getaddrinfo at offset 0 inside
+  // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+  // CHECK: #0 {{.*}} in main {{.*}}getaddrinfo-positive.cc:[[@LINE-3]]
+  return 0;
+}
diff --git a/lib/msan/lit_tests/getaddrinfo.cc b/lib/msan/lit_tests/getaddrinfo.cc
new file mode 100644
index 0000000..0518cf4
--- /dev/null
+++ b/lib/msan/lit_tests/getaddrinfo.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdlib.h>
+
+void poison_stack_ahead() {
+  char buf[100000];
+  // With -O0 this poisons a large chunk of stack.
+}
+
+int main(void) {
+  poison_stack_ahead();
+
+  struct addrinfo *ai;
+
+  // This should trigger loading of libnss_dns and friends.
+  // Those libraries are typically uninstrumented.They will call strlen() on a
+  // stack-allocated buffer, which is very likely to be poisoned. Test that we
+  // don't report this as an UMR.
+  int res = getaddrinfo("not-in-etc-hosts", NULL, NULL, &ai);
+  return 0;
+}
diff --git a/lib/msan/lit_tests/heap-origin.cc b/lib/msan/lit_tests/heap-origin.cc
index 54e2c31..2985f5a 100644
--- a/lib/msan/lit_tests/heap-origin.cc
+++ b/lib/msan/lit_tests/heap-origin.cc
@@ -21,7 +21,7 @@
   char *volatile x = (char*)malloc(5 * sizeof(char));
   if (*x)
     exit(0);
-  // CHECK: WARNING: Use of uninitialized value
+  // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
   // CHECK: {{#0 0x.* in main .*heap-origin.cc:}}[[@LINE-3]]
 
   // CHECK-ORIGINS: Uninitialized value was created by a heap allocation
diff --git a/lib/msan/lit_tests/ioctl.cc b/lib/msan/lit_tests/ioctl.cc
new file mode 100644
index 0000000..caff80c
--- /dev/null
+++ b/lib/msan/lit_tests/ioctl.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %t
+// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %t
+
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+  int fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+  unsigned int z;
+  int res = ioctl(fd, FIOGETOWN, &z);
+  assert(res == 0);
+  close(fd);
+  if (z)
+    exit(0);
+  return 0;
+}
diff --git a/lib/msan/lit_tests/ioctl_custom.cc b/lib/msan/lit_tests/ioctl_custom.cc
new file mode 100644
index 0000000..94ed528
--- /dev/null
+++ b/lib/msan/lit_tests/ioctl_custom.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %t
+// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %t
+
+// RUN: %clangxx_msan -DPOSITIVE -m64 -O0 -g %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -DPOSITIVE -m64 -O3 -g %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdlib.h>
+#include <net/if.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+  int fd = socket(AF_INET, SOCK_STREAM, 0);
+
+  struct ifreq ifreqs[20];
+  struct ifconf ifc;
+  ifc.ifc_ifcu.ifcu_req = ifreqs;
+#ifndef POSITIVE
+  ifc.ifc_len = sizeof(ifreqs);
+#endif
+  int res = ioctl(fd, SIOCGIFCONF, (void *)&ifc);
+  // CHECK: UMR in ioctl{{.*}} at offset 0
+  // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+  // CHECK: #{{.*}} in main {{.*}}ioctl_custom.cc:[[@LINE-3]]
+  assert(res == 0);
+  for (int i = 0; i < ifc.ifc_len / sizeof(*ifc.ifc_ifcu.ifcu_req); ++i)
+    printf("%d  %zu  %s\n", i, strlen(ifreqs[i].ifr_name), ifreqs[i].ifr_name);
+  return 0;
+}
diff --git a/lib/msan/lit_tests/keep-going-dso.cc b/lib/msan/lit_tests/keep-going-dso.cc
new file mode 100644
index 0000000..6d00675
--- /dev/null
+++ b/lib/msan/lit_tests/keep-going-dso.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && not %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+
+// Test how -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going affect reports
+// from interceptors.
+// -mllvm -msan-keep-going provides the default value of keep_going flag, but is
+// always overwritten by MSAN_OPTIONS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+  char *volatile x = (char*)malloc(5 * sizeof(char));
+  x[4] = 0;
+  if (strlen(x) < 3)
+    exit(0);
+  fprintf(stderr, "Done\n");
+  // CHECK-NOT: Done
+  // CHECK-KEEP-GOING: Done
+  return 0;
+}
diff --git a/lib/msan/lit_tests/keep-going.cc b/lib/msan/lit_tests/keep-going.cc
new file mode 100644
index 0000000..3cafa84
--- /dev/null
+++ b/lib/msan/lit_tests/keep-going.cc
@@ -0,0 +1,30 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %t >%t.out 2>&1
+// FileCheck %s <%t.out
+
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && not %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+
+// Test behaviour of -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going.
+// -mllvm -msan-keep-going provides the default value of keep_going flag; value
+// of 1 can be overwritten by MSAN_OPTIONS, value of 0 can not.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+  char *volatile x = (char*)malloc(5 * sizeof(char));
+  if (x[0])
+    exit(0);
+  fprintf(stderr, "Done\n");
+  // CHECK-NOT: Done
+  // CHECK-KEEP-GOING: Done
+  return 0;
+}
diff --git a/lib/msan/lit_tests/lit.cfg b/lib/msan/lit_tests/lit.cfg
index 07b5cbe..bc19b74 100644
--- a/lib/msan/lit_tests/lit.cfg
+++ b/lib/msan/lit_tests/lit.cfg
@@ -2,6 +2,14 @@
 
 import os
 
+def get_required_attr(config, attr_name):
+  attr_value = getattr(config, attr_name, None)
+  if not attr_value:
+    lit.fatal("No attribute %r in test configuration! You may need to run "
+              "tests from your build directory or add this attribute "
+              "to lit.site.cfg " % attr_name)
+  return attr_value
+
 # Setup config name.
 config.name = 'MemorySanitizer'
 
@@ -30,14 +38,6 @@
   if not llvm_config:
     DisplayNoConfigMessage()
 
-  # Validate that llvm-config points to the same source tree.
-  llvm_src_root = lit.util.capture(["llvm-config", "--src-root"]).strip()
-  msan_test_src_root = os.path.join(llvm_src_root, "projects", "compiler-rt",
-                                    "lib", "msan", "lit_tests")
-  if (os.path.realpath(msan_test_src_root) !=
-      os.path.realpath(config.test_source_root)):
-    DisplayNoConfigMessage()
-
   # Find out the presumed location of generated site config.
   llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
   msan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
@@ -48,23 +48,13 @@
   lit.load_config(config, msan_site_cfg)
   raise SystemExit
 
-# Setup attributes common for all compiler-rt projects.
-compiler_rt_lit_cfg = os.path.join(llvm_src_root, "projects", "compiler-rt",
-                                   "lib", "lit.common.cfg")
-if (not compiler_rt_lit_cfg) or (not os.path.exists(compiler_rt_lit_cfg)):
-  lit.fatal("Can't find common compiler-rt lit config at: %r"
-            % compiler_rt_lit_cfg)
-lit.load_config(config, compiler_rt_lit_cfg)
-
 # Setup default compiler flags used with -fsanitize=memory option.
 clang_msan_cflags = ["-fsanitize=memory",
                      "-mno-omit-leaf-frame-pointer",
                      "-fno-omit-frame-pointer",
                      "-fno-optimize-sibling-calls",
-                     "-g",
-                     "-fPIE",
-                     "-pie"]
-clang_msan_cxxflags = ["-ccc-cxx "] + clang_msan_cflags
+                     "-g"]
+clang_msan_cxxflags = ["--driver-mode=g++ "] + clang_msan_cflags
 config.substitutions.append( ("%clang_msan ",
                               " ".join([config.clang] + clang_msan_cflags) + 
                               " ") )
@@ -73,10 +63,7 @@
                               " ") )
 
 # Setup path to external LLVM symbolizer to run MemorySanitizer output tests.
-llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
-if llvm_tools_dir:
-  llvm_symbolizer_path = os.path.join(llvm_tools_dir, "llvm-symbolizer")
-  config.environment['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer_path
+config.environment['MSAN_SYMBOLIZER_PATH'] = config.llvm_symbolizer_path
 
 # Default test suffixes.
 config.suffixes = ['.c', '.cc', '.cpp']
diff --git a/lib/msan/lit_tests/lit.site.cfg.in b/lib/msan/lit_tests/lit.site.cfg.in
index cc7c7a0..25d378f 100644
--- a/lib/msan/lit_tests/lit.site.cfg.in
+++ b/lib/msan/lit_tests/lit.site.cfg.in
@@ -1,17 +1,5 @@
-config.target_triple = "@TARGET_TRIPLE@"
-config.host_os = "@HOST_OS@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.llvm_obj_root = "@LLVM_BINARY_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.clang = "@LLVM_BINARY_DIR@/bin/clang"
+# Load common config for all compiler-rt lit tests.
+lit.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
 
-# LLVM tools dir can be passed in lit parameters, so try to
-# apply substitution.
-try:
-  config.llvm_tools_dir = config.llvm_tools_dir % lit.params
-except KeyError,e:
-  key, = e.args
-  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Let the main config do the real work.
+# Load tool-specific config that would do the real work.
 lit.load_config(config, "@MSAN_SOURCE_DIR@/lit_tests/lit.cfg")
diff --git a/lib/msan/lit_tests/malloc_hook.cc b/lib/msan/lit_tests/malloc_hook.cc
new file mode 100644
index 0000000..5e7e7dc
--- /dev/null
+++ b/lib/msan/lit_tests/malloc_hook.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_msan -O2 %s -o %t
+// RUN: %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <unistd.h>
+
+extern "C" {
+bool __msan_get_ownership(const void *p);
+
+void *global_ptr;
+
+// Note: avoid calling functions that allocate memory in malloc/free
+// to avoid infinite recursion.
+void __msan_malloc_hook(void *ptr, size_t sz) {
+  if (__msan_get_ownership(ptr)) {
+    write(1, "MallocHook\n", sizeof("MallocHook\n"));
+    global_ptr = ptr;
+  }
+}
+void __msan_free_hook(void *ptr) {
+  if (__msan_get_ownership(ptr) && ptr == global_ptr)
+    write(1, "FreeHook\n", sizeof("FreeHook\n"));
+}
+}  // extern "C"
+
+int main() {
+  volatile int *x = new int;
+  // CHECK: MallocHook
+  // Check that malloc hook was called with correct argument.
+  if (global_ptr != (void*)x) {
+    _exit(1);
+  }
+  *x = 0;
+  delete x;
+  // CHECK: FreeHook
+  return 0;
+}
diff --git a/lib/msan/lit_tests/no_sanitize_memory_prop.cc b/lib/msan/lit_tests/no_sanitize_memory_prop.cc
index c74ca6b..3551524 100644
--- a/lib/msan/lit_tests/no_sanitize_memory_prop.cc
+++ b/lib/msan/lit_tests/no_sanitize_memory_prop.cc
@@ -25,7 +25,7 @@
   int x;
   int * volatile p = &x;
   int y = f(*p);
-  // CHECK: WARNING: Use of uninitialized value
+  // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
   // CHECK: {{#0 0x.* in main .*no_sanitize_memory_prop.cc:}}[[@LINE+1]]
   if (y)
     exit(0);
diff --git a/lib/msan/lit_tests/ptrace.cc b/lib/msan/lit_tests/ptrace.cc
new file mode 100644
index 0000000..d0e83ea
--- /dev/null
+++ b/lib/msan/lit_tests/ptrace.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int main(void) {
+  pid_t pid;
+  pid = fork();
+  if (pid == 0) { // child
+    ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+    execl("/bin/true", "true", NULL);
+  } else {
+    wait(NULL);
+    user_regs_struct regs;
+    int res;
+    res = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
+    assert(!res);
+    if (regs.rip)
+      printf("%zx\n", regs.rip);
+
+    user_fpregs_struct fpregs;
+    res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs);
+    assert(!res);
+    if (fpregs.mxcsr)
+      printf("%x\n", fpregs.mxcsr);
+
+    ptrace(PTRACE_CONT, pid, NULL, NULL);
+    wait(NULL);
+  }
+  return 0;
+}
diff --git a/lib/msan/lit_tests/setlocale.cc b/lib/msan/lit_tests/setlocale.cc
new file mode 100644
index 0000000..a22b744
--- /dev/null
+++ b/lib/msan/lit_tests/setlocale.cc
@@ -0,0 +1,13 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
+
+#include <assert.h>
+#include <locale.h>
+#include <stdlib.h>
+
+int main(void) {
+  char *locale = setlocale (LC_ALL, "");
+  assert(locale);
+  if (locale[0])
+    exit(0);
+  return 0;
+}
diff --git a/lib/msan/lit_tests/stack-origin.cc b/lib/msan/lit_tests/stack-origin.cc
index 90f5273..30cfb47 100644
--- a/lib/msan/lit_tests/stack-origin.cc
+++ b/lib/msan/lit_tests/stack-origin.cc
@@ -22,7 +22,7 @@
   int *volatile p = &x;
   if (*p)
     exit(0);
-  // CHECK: WARNING: Use of uninitialized value
+  // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
   // CHECK: {{#0 0x.* in main .*stack-origin.cc:}}[[@LINE-3]]
 
   // CHECK-ORIGINS: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main'
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc
index a1f8d0f..eb53e7b 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -61,16 +61,19 @@
 static THREADLOCAL bool is_in_symbolizer;
 static THREADLOCAL bool is_in_loader;
 
-extern "C" const int __msan_track_origins;
+extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins;
+
 int __msan_get_track_origins() {
-  return __msan_track_origins;
+  return &__msan_track_origins ? __msan_track_origins : 0;
 }
 
+extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_keep_going;
+
 namespace __msan {
 
 static bool IsRunningUnderDr() {
   bool result = false;
-  MemoryMappingLayout proc_maps;
+  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
   const sptr kBufSize = 4095;
   char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
   while (proc_maps.Next(/* start */0, /* end */0, /* file_offset */0,
@@ -114,6 +117,7 @@
 static atomic_uint32_t NumStackOriginDescrs;
 
 static void ParseFlagsFromString(Flags *f, const char *str) {
+  ParseCommonFlagsFromString(str);
   ParseFlag(str, &f->poison_heap_with_zeroes, "poison_heap_with_zeroes");
   ParseFlag(str, &f->poison_stack_with_zeroes, "poison_stack_with_zeroes");
   ParseFlag(str, &f->poison_in_malloc, "poison_in_malloc");
@@ -123,27 +127,31 @@
     f->exit_code = 1;
     Die();
   }
-  ParseFlag(str, &f->num_callers, "num_callers");
   ParseFlag(str, &f->report_umrs, "report_umrs");
   ParseFlag(str, &f->verbosity, "verbosity");
-  ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
-  ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal");
-  ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc");
+  ParseFlag(str, &f->wrap_signals, "wrap_signals");
+  ParseFlag(str, &f->keep_going, "keep_going");
 }
 
 static void InitializeFlags(Flags *f, const char *options) {
-  internal_memset(f, 0, sizeof(*f));
+  CommonFlags *cf = common_flags();
+  cf->external_symbolizer_path = GetEnv("MSAN_SYMBOLIZER_PATH");
+  cf->strip_path_prefix = "";
+  cf->fast_unwind_on_fatal = false;
+  cf->fast_unwind_on_malloc = true;
+  cf->malloc_context_size = 20;
+  cf->handle_ioctl = true;
+  cf->log_path = 0;
 
+  internal_memset(f, 0, sizeof(*f));
   f->poison_heap_with_zeroes = false;
   f->poison_stack_with_zeroes = false;
   f->poison_in_malloc = true;
   f->exit_code = 77;
-  f->num_callers = 20;
   f->report_umrs = true;
   f->verbosity = 0;
-  f->strip_path_prefix = "";
-  f->fast_unwind_on_fatal = false;
-  f->fast_unwind_on_malloc = true;
+  f->wrap_signals = true;
+  f->keep_going = !!&__msan_keep_going;
 
   // Override from user-specified string.
   if (__msan_default_options)
@@ -199,19 +207,24 @@
   ++msan_report_count;
 
   StackTrace stack;
-  GetStackTrace(&stack, kStackTraceMax, pc, bp, flags()->fast_unwind_on_fatal);
+  GetStackTrace(&stack, kStackTraceMax, pc, bp,
+                common_flags()->fast_unwind_on_fatal);
 
   u32 report_origin =
-    (__msan_track_origins && OriginIsValid(origin)) ? origin : 0;
+    (__msan_get_track_origins() && OriginIsValid(origin)) ? origin : 0;
   ReportUMR(&stack, report_origin);
 
-  if (__msan_track_origins && !OriginIsValid(origin)) {
+  if (__msan_get_track_origins() && !OriginIsValid(origin)) {
     Printf("  ORIGIN: invalid (%x). Might be a bug in MemorySanitizer, "
            "please report to MemorySanitizer developers.\n",
            origin);
   }
 }
 
+void UnpoisonParam(uptr n) {
+  internal_memset(__msan_param_tls, 0, n * sizeof(*__msan_param_tls));
+}
+
 }  // namespace __msan
 
 // Interface.
@@ -222,6 +235,10 @@
   GET_CALLER_PC_BP_SP;
   (void)sp;
   PrintWarning(pc, bp);
+  if (!__msan::flags()->keep_going) {
+    Printf("Exiting\n");
+    Die();
+  }
 }
 
 void __msan_warning_noreturn() {
@@ -242,9 +259,11 @@
   InitTlsSize();
   InitializeInterceptors();
 
-  ReplaceOperatorsNewAndDelete();
+  if (MSAN_REPLACE_OPERATORS_NEW_AND_DELETE)
+    ReplaceOperatorsNewAndDelete();
   const char *msan_options = GetEnv("MSAN_OPTIONS");
   InitializeFlags(&msan_flags, msan_options);
+  __sanitizer_set_report_path(common_flags()->log_path);
   if (StackSizeIsUnlimited()) {
     if (flags()->verbosity)
       Printf("Unlimited stack, doing reexec\n");
@@ -259,10 +278,10 @@
 
   msan_running_under_dr = IsRunningUnderDr();
   __msan_clear_on_return();
-  if (__msan_track_origins && flags()->verbosity > 0)
+  if (__msan_get_track_origins() && flags()->verbosity > 0)
     Printf("msan_track_origins\n");
-  if (!InitShadow(/* prot1 */false, /* prot2 */true, /* map_shadow */true,
-                  __msan_track_origins)) {
+  if (!InitShadow(/* prot1 */ false, /* prot2 */ true, /* map_shadow */ true,
+                  __msan_get_track_origins())) {
     // FIXME: prot1 = false is only required when running under DR.
     Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
     Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
@@ -273,7 +292,7 @@
     Die();
   }
 
-  const char *external_symbolizer = GetEnv("MSAN_SYMBOLIZER_PATH");
+  const char *external_symbolizer = common_flags()->external_symbolizer_path;
   if (external_symbolizer && external_symbolizer[0]) {
     CHECK(InitializeExternalSymbolizer(external_symbolizer));
   }
@@ -291,6 +310,10 @@
   flags()->exit_code = exit_code;
 }
 
+void __msan_set_keep_going(int keep_going) {
+  flags()->keep_going = keep_going;
+}
+
 void __msan_set_expect_umr(int expect_umr) {
   if (expect_umr) {
     msan_expected_umr_found = 0;
@@ -299,7 +322,7 @@
     (void)sp;
     StackTrace stack;
     GetStackTrace(&stack, kStackTraceMax, pc, bp,
-                  flags()->fast_unwind_on_fatal);
+                  common_flags()->fast_unwind_on_fatal);
     ReportExpectedUMRNotFound(&stack);
     Die();
   }
@@ -313,7 +336,7 @@
     Printf("%x%x ", s[i] >> 4, s[i] & 0xf);
   }
   Printf("\n");
-  if (__msan_track_origins) {
+  if (__msan_get_track_origins()) {
     for (uptr i = 0; i < size / 4; i++) {
       Printf(" o: %x ", o[i]);
     }
@@ -376,7 +399,7 @@
   return param_tls_p - tls_base_p;
 }
 
-void __msan_partial_poison(void* data, void* shadow, uptr size) {
+void __msan_partial_poison(const void* data, void* shadow, uptr size) {
   internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size);
 }
 
@@ -385,11 +408,11 @@
   __msan_unpoison(dst, size);
 }
 
-void __msan_set_origin(void *a, uptr size, u32 origin) {
+void __msan_set_origin(const void *a, uptr size, u32 origin) {
   // Origin mapping is 4 bytes per 4 bytes of application memory.
   // Here we extend the range such that its left and right bounds are both
   // 4 byte aligned.
-  if (!__msan_track_origins) return;
+  if (!__msan_get_track_origins()) return;
   uptr x = MEM_TO_ORIGIN((uptr)a);
   uptr beg = x & ~3UL;  // align down.
   uptr end = (x + size + 3) & ~3UL;  // align up.
@@ -439,8 +462,8 @@
 }
 
 
-u32 __msan_get_origin(void *a) {
-  if (!__msan_track_origins) return 0;
+u32 __msan_get_origin(const void *a) {
+  if (!__msan_get_track_origins()) return 0;
   uptr x = (uptr)a;
   uptr aligned = x & ~3ULL;
   uptr origin_ptr = MEM_TO_ORIGIN(aligned);
@@ -451,6 +474,31 @@
   return __msan_origin_tls;
 }
 
+u16 __sanitizer_unaligned_load16(const uu16 *p) {
+  __msan_retval_tls[0] = *(uu16 *)MEM_TO_SHADOW((uptr)p);
+  return *p;
+}
+u32 __sanitizer_unaligned_load32(const uu32 *p) {
+  __msan_retval_tls[0] = *(uu32 *)MEM_TO_SHADOW((uptr)p);
+  return *p;
+}
+u64 __sanitizer_unaligned_load64(const uu64 *p) {
+  __msan_retval_tls[0] = *(uu64 *)MEM_TO_SHADOW((uptr)p);
+  return *p;
+}
+void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
+  *(uu16 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
+  *p = x;
+}
+void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
+  *(uu32 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
+  *p = x;
+}
+void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
+  *(uu64 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
+  *p = x;
+}
+
 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
 extern "C" {
 SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
diff --git a/lib/msan/msan.h b/lib/msan/msan.h
index 1880b8e..b4bf642 100644
--- a/lib/msan/msan.h
+++ b/lib/msan/msan.h
@@ -15,19 +15,22 @@
 #ifndef MSAN_H
 #define MSAN_H
 
+#include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
 #include "msan_interface_internal.h"
 #include "msan_flags.h"
 
+#ifndef MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
+# define MSAN_REPLACE_OPERATORS_NEW_AND_DELETE 1
+#endif
+
 #define MEM_TO_SHADOW(mem) (((uptr)mem)       & ~0x400000000000ULL)
 #define MEM_TO_ORIGIN(mem) (MEM_TO_SHADOW(mem) + 0x200000000000ULL)
 #define MEM_IS_APP(mem)    ((uptr)mem >=         0x600000000000ULL)
 #define MEM_IS_SHADOW(mem) ((uptr)mem >=         0x200000000000ULL && \
                             (uptr)mem <=         0x400000000000ULL)
 
-struct link_map;  // Opaque type returned by dlopen().
-
 const int kMsanParamTlsSizeInWords = 100;
 const int kMsanRetvalTlsSizeInWords = 100;
 
@@ -71,16 +74,22 @@
 void ReportExpectedUMRNotFound(StackTrace *stack);
 void ReportAtExitStatistics();
 
-void UnpoisonMappedDSO(struct link_map *map);
+// Unpoison first n function arguments.
+void UnpoisonParam(uptr n);
 
 #define GET_MALLOC_STACK_TRACE                                     \
   StackTrace stack;                                                \
   stack.size = 0;                                                  \
   if (__msan_get_track_origins() && msan_inited)                   \
-    GetStackTrace(&stack, flags()->num_callers,                    \
+    GetStackTrace(&stack, common_flags()->malloc_context_size,     \
         StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),           \
-        flags()->fast_unwind_on_malloc)
+        common_flags()->fast_unwind_on_malloc)
 
 }  // namespace __msan
 
+#define MSAN_MALLOC_HOOK(ptr, size) \
+  if (&__msan_malloc_hook) __msan_malloc_hook(ptr, size)
+#define MSAN_FREE_HOOK(ptr) \
+  if (&__msan_free_hook) __msan_free_hook(ptr)
+
 #endif  // MSAN_H
diff --git a/lib/msan/msan.syms b/lib/msan/msan.syms
new file mode 100644
index 0000000..24bbaba
--- /dev/null
+++ b/lib/msan/msan.syms
@@ -0,0 +1,5 @@
+{
+  __msan_*;
+  __sanitizer_syscall_pre_*;
+  __sanitizer_syscall_post_*;
+};
diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc
index 7435843..7b989de 100644
--- a/lib/msan/msan_allocator.cc
+++ b/lib/msan/msan_allocator.cc
@@ -61,14 +61,17 @@
     CHECK_EQ((stack_id >> 31), 0);  // Higher bit is occupied by stack origins.
     __msan_set_origin(res, size, stack_id);
   }
+  MSAN_MALLOC_HOOK(res, size);
   return res;
 }
 
 void MsanDeallocate(void *p) {
   CHECK(p);
   Init();
+  MSAN_FREE_HOOK(p);
   Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(p));
   uptr size = meta->requested_size;
+  meta->requested_size = 0;
   // This memory will not be reused by anyone else, so we are free to keep it
   // poisoned.
   __msan_poison(p, size);
@@ -104,4 +107,52 @@
   return new_p;
 }
 
+static uptr AllocationSize(const void *p) {
+  if (p == 0)
+    return 0;
+  const void *beg = allocator.GetBlockBegin(p);
+  if (beg != p)
+    return 0;
+  Metadata *b = (Metadata*)allocator.GetMetaData(p);
+  return b->requested_size;
+}
+
 }  // namespace __msan
+
+using namespace __msan;
+
+uptr __msan_get_current_allocated_bytes() {
+  u64 stats[AllocatorStatCount];
+  allocator.GetStats(stats);
+  u64 m = stats[AllocatorStatMalloced];
+  u64 f = stats[AllocatorStatFreed];
+  return m >= f ? m - f : 1;
+}
+
+uptr __msan_get_heap_size() {
+  u64 stats[AllocatorStatCount];
+  allocator.GetStats(stats);
+  u64 m = stats[AllocatorStatMmapped];
+  u64 f = stats[AllocatorStatUnmapped];
+  return m >= f ? m - f : 1;
+}
+
+uptr __msan_get_free_bytes() {
+  return 1;
+}
+
+uptr __msan_get_unmapped_bytes() {
+  return 1;
+}
+
+uptr __msan_get_estimated_allocated_size(uptr size) {
+  return size;
+}
+
+bool __msan_get_ownership(const void *p) {
+  return AllocationSize(p) != 0;
+}
+
+uptr __msan_get_allocated_size(const void *p) {
+  return AllocationSize(p);
+}
diff --git a/lib/msan/msan_blacklist.txt b/lib/msan/msan_blacklist.txt
new file mode 100644
index 0000000..44a5680
--- /dev/null
+++ b/lib/msan/msan_blacklist.txt
@@ -0,0 +1,7 @@
+# Blacklist for MemorySanitizer. Turns off instrumentation of particular
+# functions or sources. Use with care. You may set location of blacklist
+# at compile-time using -fsanitize-blacklist=<path> flag.
+
+# Example usage:
+# fun:*bad_function_name*
+# src:file_with_tricky_code.cc
diff --git a/lib/msan/msan_flags.h b/lib/msan/msan_flags.h
index cfaf963..e046617 100644
--- a/lib/msan/msan_flags.h
+++ b/lib/msan/msan_flags.h
@@ -19,17 +19,13 @@
 // Flags.
 struct Flags {
   int exit_code;
-  int num_callers;
   int verbosity;
   bool poison_heap_with_zeroes;  // default: false
   bool poison_stack_with_zeroes;  // default: false
   bool poison_in_malloc;  // default: true
   bool report_umrs;
-  const char *strip_path_prefix;
-  // Use fast (frame-pointer-based) unwinder on fatal errors (if available).
-  bool fast_unwind_on_fatal;
-  // Use fast (frame-pointer-based) unwinder on malloc/free (if available).
-  bool fast_unwind_on_malloc;
+  bool wrap_signals;
+  bool keep_going;
 };
 
 Flags *flags();
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index 287d2d2..2ae9a8a 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -22,15 +22,26 @@
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_linux.h"
 
 #include <stdarg.h>
 // ACHTUNG! No other system header includes in this file.
 // Ideally, we should get rid of stdarg.h as well.
 
-extern "C" const int __msan_keep_going;
-
 using namespace __msan;
 
+// True if this is a nested interceptor.
+static THREADLOCAL int in_interceptor_scope;
+
+struct InterceptorScope {
+  InterceptorScope() { ++in_interceptor_scope; }
+  ~InterceptorScope() { --in_interceptor_scope; }
+};
+
+bool IsInInterceptorScope() {
+  return in_interceptor_scope;
+}
+
 #define ENSURE_MSAN_INITED() do { \
   CHECK(!msan_init_is_running); \
   if (!msan_inited) { \
@@ -38,24 +49,32 @@
   } \
 } while (0)
 
-#define CHECK_UNPOISONED(x, n) \
-  do { \
-    sptr offset = __msan_test_shadow(x, n);                 \
-    if (__msan::IsInSymbolizer()) break;                    \
-    if (offset >= 0 && flags()->report_umrs) {              \
-      GET_CALLER_PC_BP_SP;                                  \
-      (void)sp;                                             \
-      Printf("UMR in %s at offset %d inside [%p, +%d) \n",  \
-             __FUNCTION__, offset, x, n);                   \
-      __msan::PrintWarningWithOrigin(                       \
-        pc, bp, __msan_get_origin((char*)x + offset));      \
-      if (!__msan_keep_going) {                             \
-        Printf("Exiting\n");                                \
-        Die();                                              \
-      }                                                     \
-    }                                                       \
+// Check that [x, x+n) range is unpoisoned.
+#define CHECK_UNPOISONED_0(x, n)                                             \
+  do {                                                                       \
+    sptr offset = __msan_test_shadow(x, n);                                  \
+    if (__msan::IsInSymbolizer()) break;                                     \
+    if (offset >= 0 && __msan::flags()->report_umrs) {                       \
+      GET_CALLER_PC_BP_SP;                                                   \
+      (void) sp;                                                             \
+      Printf("UMR in %s at offset %d inside [%p, +%d) \n", __FUNCTION__,     \
+             offset, x, n);                                                  \
+      __msan::PrintWarningWithOrigin(pc, bp,                                 \
+                                     __msan_get_origin((char *)x + offset)); \
+      if (!__msan::flags()->keep_going) {                                    \
+        Printf("Exiting\n");                                                 \
+        Die();                                                               \
+      }                                                                      \
+    }                                                                        \
   } while (0)
 
+// Check that [x, x+n) range is unpoisoned unless we are in a nested
+// interceptor.
+#define CHECK_UNPOISONED(x, n)                             \
+  do {                                                     \
+    if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
+  } while (0);
+
 static void *fast_memset(void *ptr, int c, SIZE_T n);
 static void *fast_memcpy(void *dst, const void *src, SIZE_T n);
 
@@ -84,24 +103,14 @@
   return res;
 }
 
-INTERCEPTOR(void *, readdir, void *a) {
-  ENSURE_MSAN_INITED();
-  void *res = REAL(readdir)(a);
-  __msan_unpoison(res, __sanitizer::struct_dirent_sz);
-  return res;
-}
-
-INTERCEPTOR(void *, readdir64, void *a) {
-  ENSURE_MSAN_INITED();
-  void *res = REAL(readdir)(a);
-  __msan_unpoison(res, __sanitizer::struct_dirent64_sz);
-  return res;
-}
-
 INTERCEPTOR(void *, memcpy, void *dest, const void *src, SIZE_T n) {
   return __msan_memcpy(dest, src, n);
 }
 
+INTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) {
+  return (char *)__msan_memcpy(dest, src, n) + n;
+}
+
 INTERCEPTOR(void *, memmove, void *dest, const void *src, SIZE_T n) {
   return __msan_memmove(dest, src, n);
 }
@@ -110,11 +119,17 @@
   return __msan_memset(s, c, n);
 }
 
+INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) {
+  return __msan_memmove(dest, src, n);
+}
+
 INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
   GET_MALLOC_STACK_TRACE;
   CHECK_EQ(alignment & (alignment - 1), 0);
-  *memptr = MsanReallocate(&stack, 0, size, alignment, false);
   CHECK_NE(memptr, 0);
+  *memptr = MsanReallocate(&stack, 0, size, alignment, false);
+  CHECK_NE(*memptr, 0);
+  __msan_unpoison(memptr, sizeof(*memptr));
   return 0;
 }
 
@@ -160,6 +175,14 @@
   return res;
 }
 
+INTERCEPTOR(char *, stpcpy, char *dest, const char *src) {  // NOLINT
+  ENSURE_MSAN_INITED();
+  SIZE_T n = REAL(strlen)(src);
+  char *res = REAL(stpcpy)(dest, src);  // NOLINT
+  __msan_copy_poison(dest, src, n + 1);
+  return res;
+}
+
 INTERCEPTOR(char *, strdup, char *src) {
   ENSURE_MSAN_INITED();
   SIZE_T n = REAL(strlen)(src);
@@ -292,11 +315,30 @@
   return res;
 }
 
+INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap) {
+  ENSURE_MSAN_INITED();
+  int res = REAL(vasprintf)(strp, format, ap);
+  if (res >= 0 && !__msan_has_dynamic_component()) {
+    __msan_unpoison(strp, sizeof(*strp));
+    __msan_unpoison(*strp, res + 1);
+  }
+  return res;
+}
+
+INTERCEPTOR(int, asprintf, char **strp, const char *format, ...) {  // NOLINT
+  ENSURE_MSAN_INITED();
+  va_list ap;
+  va_start(ap, format);
+  int res = vasprintf(strp, format, ap);  // NOLINT
+  va_end(ap);
+  return res;
+}
+
 INTERCEPTOR(int, vsnprintf, char *str, uptr size,
             const char *format, va_list ap) {
   ENSURE_MSAN_INITED();
   int res = REAL(vsnprintf)(str, size, format, ap);
-  if (!__msan_has_dynamic_component()) {
+  if (res >= 0 && !__msan_has_dynamic_component()) {
     __msan_unpoison(str, res + 1);
   }
   return res;
@@ -305,7 +347,7 @@
 INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap) {
   ENSURE_MSAN_INITED();
   int res = REAL(vsprintf)(str, format, ap);
-  if (!__msan_has_dynamic_component()) {
+  if (res >= 0 && !__msan_has_dynamic_component()) {
     __msan_unpoison(str, res + 1);
   }
   return res;
@@ -314,7 +356,7 @@
 INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
   ENSURE_MSAN_INITED();
   int res = REAL(vswprintf)(str, size, format, ap);
-  if (!__msan_has_dynamic_component()) {
+  if (res >= 0 && !__msan_has_dynamic_component()) {
     __msan_unpoison(str, 4 * (res + 1));
   }
   return res;
@@ -356,18 +398,17 @@
   return res;
 }
 
-INTERCEPTOR(SIZE_T, wcstombs, void *dest, void *src, SIZE_T size) {
+INTERCEPTOR(int, mbtowc, wchar_t *dest, const char *src, SIZE_T n) {
   ENSURE_MSAN_INITED();
-  SIZE_T res = REAL(wcstombs)(dest, src, size);
-  if (res != (SIZE_T)-1) __msan_unpoison(dest, res + 1);
+  int res = REAL(mbtowc)(dest, src, n);
+  if (res != -1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
   return res;
 }
 
-// SIZE_T mbstowcs(wchar_t *dest, const char *src, SIZE_T n);
-INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T n) {
+INTERCEPTOR(int, mbrtowc, wchar_t *dest, const char *src, SIZE_T n, void *ps) {
   ENSURE_MSAN_INITED();
-  SIZE_T res = REAL(mbstowcs)(dest, src, n);
-  if (res != (SIZE_T)-1) __msan_unpoison(dest, (res + 1) * sizeof(wchar_t));
+  SIZE_T res = REAL(mbrtowc)(dest, src, n, ps);
+  if (res != (SIZE_T)-1 && dest) __msan_unpoison(dest, sizeof(wchar_t));
   return res;
 }
 
@@ -401,6 +442,13 @@
   return res;
 }
 
+INTERCEPTOR(wchar_t *, wmempcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
+  ENSURE_MSAN_INITED();
+  wchar_t *res = REAL(wmempcpy)(dest, src, n);
+  __msan_copy_poison(dest, src, n * sizeof(wchar_t));
+  return res;
+}
+
 INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
   CHECK(MEM_IS_APP(s));
   ENSURE_MSAN_INITED();
@@ -481,6 +529,32 @@
   return res;
 }
 
+extern char **environ;
+
+static void UnpoisonEnviron() {
+  char **envp = environ;
+  for (; *envp; ++envp) {
+    __msan_unpoison(envp, sizeof(*envp));
+    __msan_unpoison(*envp, REAL(strlen)(*envp) + 1);
+  }
+  // Trailing NULL pointer.
+  __msan_unpoison(envp, sizeof(*envp));
+}
+
+INTERCEPTOR(int, setenv, const char *name, const char *value, int overwrite) {
+  ENSURE_MSAN_INITED();
+  int res = REAL(setenv)(name, value, overwrite);
+  if (!res) UnpoisonEnviron();
+  return res;
+}
+
+INTERCEPTOR(int, putenv, char *string) {
+  ENSURE_MSAN_INITED();
+  int res = REAL(putenv)(string);
+  if (!res) UnpoisonEnviron();
+  return res;
+}
+
 INTERCEPTOR(int, __fxstat, int magic, int fd, void *buf) {
   ENSURE_MSAN_INITED();
   int res = REAL(__fxstat)(magic, fd, buf);
@@ -539,21 +613,19 @@
   return res;
 }
 
-INTERCEPTOR(int, wait, int *status) {
+INTERCEPTOR(int, pipe2, int pipefd[2], int flags) {
   ENSURE_MSAN_INITED();
-  int res = REAL(wait)(status);
-  if (status)
-    __msan_unpoison(status, sizeof(*status));
+  int res = REAL(pipe2)(pipefd, flags);
+  if (!res)
+    __msan_unpoison(pipefd, sizeof(int[2]));
   return res;
 }
 
-INTERCEPTOR(int, waitpid, int pid, int *status, int options) {
-  if (msan_init_is_running)
-    return REAL(waitpid)(pid, status, options);
+INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int sv[2]) {
   ENSURE_MSAN_INITED();
-  int res = REAL(waitpid)(pid, status, options);
-  if (status)
-    __msan_unpoison(status, sizeof(*status));
+  int res = REAL(socketpair)(domain, type, protocol, sv);
+  if (!res)
+    __msan_unpoison(sv, sizeof(int[2]));
   return res;
 }
 
@@ -573,22 +645,6 @@
   return res;
 }
 
-INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
-  ENSURE_MSAN_INITED();
-  char *res = REAL(getcwd)(buf, size);
-  if (res)
-    __msan_unpoison(res, REAL(strlen)(res) + 1);
-  return res;
-}
-
-INTERCEPTOR(char *, realpath, char *path, char *abspath) {
-  ENSURE_MSAN_INITED();
-  char *res = REAL(realpath)(path, abspath);
-  if (res)
-    __msan_unpoison(abspath, REAL(strlen)(abspath) + 1);
-  return res;
-}
-
 INTERCEPTOR(int, getrlimit, int resource, void *rlim) {
   if (msan_init_is_running)
     return REAL(getrlimit)(resource, rlim);
@@ -691,33 +747,21 @@
 }
 
 INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
-    void *srcaddr, void *addrlen) {
+            void *srcaddr, int *addrlen) {
   ENSURE_MSAN_INITED();
   SIZE_T srcaddr_sz;
-  if (srcaddr)
-    srcaddr_sz = __sanitizer_get_socklen_t(addrlen);
+  if (srcaddr) srcaddr_sz = *addrlen;
   SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
   if (res > 0) {
     __msan_unpoison(buf, res);
     if (srcaddr) {
-      SIZE_T sz = __sanitizer_get_socklen_t(addrlen);
+      SIZE_T sz = *addrlen;
       __msan_unpoison(srcaddr, (sz < srcaddr_sz) ? sz : srcaddr_sz);
     }
   }
   return res;
 }
 
-INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct msghdr *msg, int flags) {
-  ENSURE_MSAN_INITED();
-  SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
-  if (res > 0) {
-    for (SIZE_T i = 0; i < __sanitizer_get_msghdr_iovlen(msg); ++i)
-      __msan_unpoison(__sanitizer_get_msghdr_iov_iov_base(msg, i),
-          __sanitizer_get_msghdr_iov_iov_len(msg, i));
-  }
-  return res;
-}
-
 INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
   if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
   GET_MALLOC_STACK_TRACE;
@@ -745,7 +789,7 @@
   return MsanReallocate(&stack, 0, size, sizeof(u64), false);
 }
 
-void __msan_allocated_memory(void* data, uptr size) {
+void __msan_allocated_memory(const void* data, uptr size) {
   GET_MALLOC_STACK_TRACE;
   if (flags()->poison_in_malloc)
     __msan_poison(data, size);
@@ -806,14 +850,44 @@
   EnterLoader();
   link_map *map = (link_map *)REAL(dlopen)(filename, flag);
   ExitLoader();
-  if (!__msan_has_dynamic_component()) {
+  if (!__msan_has_dynamic_component() && map) {
     // If msandr didn't clear the shadow before the initializers ran, we do it
     // ourselves afterwards.
-    UnpoisonMappedDSO(map);
+    ForEachMappedRegion(map, __msan_unpoison);
   }
   return (void *)map;
 }
 
+typedef int (*dl_iterate_phdr_cb)(__sanitizer_dl_phdr_info *info, SIZE_T size,
+                                  void *data);
+struct dl_iterate_phdr_data {
+  dl_iterate_phdr_cb callback;
+  void *data;
+};
+
+static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
+                                   void *data) {
+  if (info) {
+    __msan_unpoison(info, size);
+    if (info->dlpi_name)
+      __msan_unpoison(info->dlpi_name, REAL(strlen)(info->dlpi_name) + 1);
+  }
+  dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
+  UnpoisonParam(3);
+  return cbdata->callback(info, size, cbdata->data);
+}
+
+INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) {
+  ENSURE_MSAN_INITED();
+  EnterLoader();
+  dl_iterate_phdr_data cbdata;
+  cbdata.callback = callback;
+  cbdata.data = data;
+  int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata);
+  ExitLoader();
+  return res;
+}
+
 INTERCEPTOR(int, getrusage, int who, void *usage) {
   ENSURE_MSAN_INITED();
   int res = REAL(getrusage)(who, usage);
@@ -823,10 +897,85 @@
   return res;
 }
 
+const int kMaxSignals = 1024;
+static uptr sigactions[kMaxSignals];
+static StaticSpinMutex sigactions_mu;
+
+static void SignalHandler(int signo) {
+  typedef void (*signal_cb)(int x);
+  signal_cb cb = (signal_cb)sigactions[signo];
+  cb(signo);
+}
+
+static void SignalAction(int signo, void *si, void *uc) {
+  UnpoisonParam(3);
+  __msan_unpoison(si, __sanitizer::struct_sigaction_sz);
+  __msan_unpoison(uc, __sanitizer::ucontext_t_sz);
+
+  typedef void (*sigaction_cb)(int, void *, void *);
+  sigaction_cb cb = (sigaction_cb)sigactions[signo];
+  cb(signo, si, uc);
+}
+
+INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
+            __sanitizer_sigaction *oldact) {
+  ENSURE_MSAN_INITED();
+  // FIXME: check that *act is unpoisoned.
+  // That requires intercepting all of sigemptyset, sigfillset, etc.
+  int res;
+  if (flags()->wrap_signals) {
+    SpinMutexLock lock(&sigactions_mu);
+    CHECK_LT(signo, kMaxSignals);
+    uptr old_cb = sigactions[signo];
+    __sanitizer_sigaction new_act;
+    __sanitizer_sigaction *pnew_act = act ? &new_act : 0;
+    if (act) {
+      internal_memcpy(pnew_act, act, __sanitizer::struct_sigaction_sz);
+      uptr cb = __sanitizer::__sanitizer_get_sigaction_sa_sigaction(pnew_act);
+      uptr new_cb =
+          __sanitizer::__sanitizer_get_sigaction_sa_siginfo(pnew_act) ?
+          (uptr)SignalAction : (uptr)SignalHandler;
+      if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
+        sigactions[signo] = cb;
+        __sanitizer::__sanitizer_set_sigaction_sa_sigaction(pnew_act, new_cb);
+      }
+    }
+    res = REAL(sigaction)(signo, pnew_act, oldact);
+    if (res == 0 && oldact) {
+      uptr cb = __sanitizer::__sanitizer_get_sigaction_sa_sigaction(oldact);
+      if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
+        __sanitizer::__sanitizer_set_sigaction_sa_sigaction(oldact, old_cb);
+      }
+    }
+  } else {
+    res = REAL(sigaction)(signo, act, oldact);
+  }
+
+  if (res == 0 && oldact) {
+    __msan_unpoison(oldact, __sanitizer::struct_sigaction_sz);
+  }
+  return res;
+}
+
+INTERCEPTOR(int, signal, int signo, uptr cb) {
+  ENSURE_MSAN_INITED();
+  if (flags()->wrap_signals) {
+    CHECK_LT(signo, kMaxSignals);
+    SpinMutexLock lock(&sigactions_mu);
+    if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) {
+      sigactions[signo] = cb;
+      cb = (uptr) SignalHandler;
+    }
+    return REAL(signal)(signo, cb);
+  } else {
+    return REAL(signal)(signo, cb);
+  }
+}
+
 extern "C" int pthread_attr_init(void *attr);
 extern "C" int pthread_attr_destroy(void *attr);
 extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
-extern "C" int pthread_attr_getstacksize(void *attr, uptr *stacksize);
+extern "C" int pthread_attr_getstack(void *attr, uptr *stack, uptr *stacksize);
 
 INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
             void * param) {
@@ -836,38 +985,79 @@
     pthread_attr_init(&myattr);
     attr = &myattr;
   }
-  uptr stacksize = 0;
-  pthread_attr_getstacksize(attr, &stacksize);
-  // We place the huge ThreadState object into TLS, account for that.
-  const uptr minstacksize = GetTlsSize() + 128*1024;
-  if (stacksize < minstacksize) {
-    if (flags()->verbosity)
-      Printf("MemorySanitizer: increasing stacksize %zu->%zu\n", stacksize,
-             minstacksize);
-    pthread_attr_setstacksize(attr, minstacksize);
-  }
+
+  AdjustStackSizeLinux(attr, flags()->verbosity);
 
   int res = REAL(pthread_create)(th, attr, callback, param);
   if (attr == &myattr)
     pthread_attr_destroy(&myattr);
+  if (!res) {
+    __msan_unpoison(th, __sanitizer::pthread_t_sz);
+  }
   return res;
 }
 
+INTERCEPTOR(int, pthread_key_create, __sanitizer_pthread_key_t *key,
+            void (*dtor)(void *value)) {
+  ENSURE_MSAN_INITED();
+  int res = REAL(pthread_key_create)(key, dtor);
+  if (!res && key)
+    __msan_unpoison(key, sizeof(*key));
+  return res;
+}
+
+INTERCEPTOR(int, pthread_join, void *th, void **retval) {
+  ENSURE_MSAN_INITED();
+  int res = REAL(pthread_join)(th, retval);
+  if (!res && retval)
+    __msan_unpoison(retval, sizeof(*retval));
+  return res;
+}
+
+struct MSanInterceptorContext {
+  bool in_interceptor_scope;
+};
+
+// A version of CHECK_UNPOISED using a saved scope value. Used in common
+// interceptors.
+#define CHECK_UNPOISONED_CTX(ctx, x, n)                         \
+  do {                                                          \
+    if (!((MSanInterceptorContext *)ctx)->in_interceptor_scope) \
+      CHECK_UNPOISONED_0(x, n);                                 \
+  } while (0)
+
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count)  \
+  UnpoisonParam(count)
 #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
-    __msan_unpoison(ptr, size)
-#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) do { } while (false)
-#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
-  do {                                           \
-    ctx = 0;                                     \
-    (void)ctx;                                   \
-    ENSURE_MSAN_INITED();                        \
+  __msan_unpoison(ptr, size)
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+  CHECK_UNPOISONED_CTX(ctx, ptr, size)
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...)              \
+  if (msan_init_is_running) return REAL(func)(__VA_ARGS__);   \
+  MSanInterceptorContext msan_ctx = {IsInInterceptorScope()}; \
+  ctx = (void *)&msan_ctx;                                    \
+  InterceptorScope interceptor_scope;                         \
+  ENSURE_MSAN_INITED();
+#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
+  do {                                         \
   } while (false)
-#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) do { } while (false)
-#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) do { } while (false)
+#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
+  do {                                         \
+  } while (false)
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+  do {                                                      \
+  } while (false)
 #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
-  do { } while (false)  // FIXME
+  do {                                                \
+  } while (false)  // FIXME
 #include "sanitizer_common/sanitizer_common_interceptors.inc"
 
+#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s)
+#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
+#include "sanitizer_common/sanitizer_common_syscalls.inc"
+
 // static
 void *fast_memset(void *ptr, int c, SIZE_T n) {
   // hack until we have a really fast internal_memset
@@ -903,12 +1093,12 @@
 
 // These interface functions reside here so that they can use
 // fast_memset, etc.
-void __msan_unpoison(void *a, uptr size) {
+void __msan_unpoison(const void *a, uptr size) {
   if (!MEM_IS_APP(a)) return;
   fast_memset((void*)MEM_TO_SHADOW((uptr)a), 0, size);
 }
 
-void __msan_poison(void *a, uptr size) {
+void __msan_poison(const void *a, uptr size) {
   if (!MEM_IS_APP(a)) return;
   fast_memset((void*)MEM_TO_SHADOW((uptr)a),
               __msan::flags()->poison_heap_with_zeroes ? 0 : -1, size);
@@ -989,15 +1179,17 @@
   INTERCEPT_FUNCTION(fread);
   INTERCEPT_FUNCTION(fread_unlocked);
   INTERCEPT_FUNCTION(readlink);
-  INTERCEPT_FUNCTION(readdir);
-  INTERCEPT_FUNCTION(readdir64);
   INTERCEPT_FUNCTION(memcpy);
+  INTERCEPT_FUNCTION(mempcpy);
   INTERCEPT_FUNCTION(memset);
   INTERCEPT_FUNCTION(memmove);
+  INTERCEPT_FUNCTION(bcopy);
   INTERCEPT_FUNCTION(wmemset);
   INTERCEPT_FUNCTION(wmemcpy);
+  INTERCEPT_FUNCTION(wmempcpy);
   INTERCEPT_FUNCTION(wmemmove);
   INTERCEPT_FUNCTION(strcpy);  // NOLINT
+  INTERCEPT_FUNCTION(stpcpy);  // NOLINT
   INTERCEPT_FUNCTION(strdup);
   INTERCEPT_FUNCTION(__strdup);
   INTERCEPT_FUNCTION(strndup);
@@ -1015,6 +1207,8 @@
   INTERCEPT_FUNCTION(strtod);
   INTERCEPT_FUNCTION(strtof);
   INTERCEPT_FUNCTION(strtold);
+  INTERCEPT_FUNCTION(vasprintf);
+  INTERCEPT_FUNCTION(asprintf);
   INTERCEPT_FUNCTION(vsprintf);
   INTERCEPT_FUNCTION(vsnprintf);
   INTERCEPT_FUNCTION(vswprintf);
@@ -1022,14 +1216,16 @@
   INTERCEPT_FUNCTION(snprintf);
   INTERCEPT_FUNCTION(swprintf);
   INTERCEPT_FUNCTION(strftime);
-  INTERCEPT_FUNCTION(wcstombs);
-  INTERCEPT_FUNCTION(mbstowcs);
+  INTERCEPT_FUNCTION(mbtowc);
+  INTERCEPT_FUNCTION(mbrtowc);
   INTERCEPT_FUNCTION(wcslen);
   INTERCEPT_FUNCTION(wcschr);
   INTERCEPT_FUNCTION(wcscpy);
   INTERCEPT_FUNCTION(wcscmp);
   INTERCEPT_FUNCTION(wcstod);
   INTERCEPT_FUNCTION(getenv);
+  INTERCEPT_FUNCTION(setenv);
+  INTERCEPT_FUNCTION(putenv);
   INTERCEPT_FUNCTION(gettimeofday);
   INTERCEPT_FUNCTION(fcvt);
   INTERCEPT_FUNCTION(__fxstat);
@@ -1039,12 +1235,10 @@
   INTERCEPT_FUNCTION(__xstat64);
   INTERCEPT_FUNCTION(__lxstat64);
   INTERCEPT_FUNCTION(pipe);
-  INTERCEPT_FUNCTION(wait);
-  INTERCEPT_FUNCTION(waitpid);
+  INTERCEPT_FUNCTION(pipe2);
+  INTERCEPT_FUNCTION(socketpair);
   INTERCEPT_FUNCTION(fgets);
   INTERCEPT_FUNCTION(fgets_unlocked);
-  INTERCEPT_FUNCTION(getcwd);
-  INTERCEPT_FUNCTION(realpath);
   INTERCEPT_FUNCTION(getrlimit);
   INTERCEPT_FUNCTION(getrlimit64);
   INTERCEPT_FUNCTION(statfs);
@@ -1057,11 +1251,15 @@
   INTERCEPT_FUNCTION(epoll_pwait);
   INTERCEPT_FUNCTION(recv);
   INTERCEPT_FUNCTION(recvfrom);
-  INTERCEPT_FUNCTION(recvmsg);
   INTERCEPT_FUNCTION(dladdr);
   INTERCEPT_FUNCTION(dlopen);
+  INTERCEPT_FUNCTION(dl_iterate_phdr);
   INTERCEPT_FUNCTION(getrusage);
+  INTERCEPT_FUNCTION(sigaction);
+  INTERCEPT_FUNCTION(signal);
   INTERCEPT_FUNCTION(pthread_create);
+  INTERCEPT_FUNCTION(pthread_key_create);
+  INTERCEPT_FUNCTION(pthread_join);
   inited = 1;
 }
 }  // namespace __msan
diff --git a/lib/msan/msan_interface_internal.h b/lib/msan/msan_interface_internal.h
index e1cd13c..5d643e8 100644
--- a/lib/msan/msan_interface_internal.h
+++ b/lib/msan/msan_interface_internal.h
@@ -38,7 +38,7 @@
 void __msan_warning_noreturn();
 
 SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_unpoison(void *a, uptr size);
+void __msan_unpoison(const void *a, uptr size);
 SANITIZER_INTERFACE_ATTRIBUTE
 void __msan_clear_and_unpoison(void *a, uptr size);
 SANITIZER_INTERFACE_ATTRIBUTE
@@ -54,7 +54,7 @@
 SANITIZER_INTERFACE_ATTRIBUTE
 void __msan_move_poison(void *dst, const void *src, uptr size);
 SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_poison(void *a, uptr size);
+void __msan_poison(const void *a, uptr size);
 SANITIZER_INTERFACE_ATTRIBUTE
 void __msan_poison_stack(void *a, uptr size);
 
@@ -69,11 +69,11 @@
 sptr __msan_test_shadow(const void *x, uptr size);
 
 SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_origin(void *a, uptr size, u32 origin);
+void __msan_set_origin(const void *a, uptr size, u32 origin);
 SANITIZER_INTERFACE_ATTRIBUTE
 void __msan_set_alloca_origin(void *a, uptr size, const char *descr);
 SANITIZER_INTERFACE_ATTRIBUTE
-u32 __msan_get_origin(void *a);
+u32 __msan_get_origin(const void *a);
 
 SANITIZER_INTERFACE_ATTRIBUTE
 void __msan_clear_on_return();
@@ -83,6 +83,9 @@
 void __msan_set_exit_code(int exit_code);
 
 SANITIZER_INTERFACE_ATTRIBUTE
+void __msan_set_keep_going(int keep_going);
+
+SANITIZER_INTERFACE_ATTRIBUTE
 int __msan_set_poison_in_malloc(int do_poison);
 
 SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
@@ -114,12 +117,57 @@
 SANITIZER_INTERFACE_ATTRIBUTE
 const char *__msan_get_origin_descr_if_stack(u32 id);
 SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_partial_poison(void* data, void* shadow, uptr size);
+void __msan_partial_poison(const void* data, void* shadow, uptr size);
 
 // Tell MSan about newly allocated memory (ex.: custom allocator).
 // Memory will be marked uninitialized, with origin at the call site.
 SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_allocated_memory(void* data, uptr size);
+void __msan_allocated_memory(const void* data, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u16 __sanitizer_unaligned_load16(const uu16 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u32 __sanitizer_unaligned_load32(const uu32 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+u64 __sanitizer_unaligned_load64(const uu64 *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store16(uu16 *p, u16 x);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store32(uu32 *p, u32 x);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_unaligned_store64(uu64 *p, u64 x);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __msan_get_estimated_allocated_size(uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+bool __msan_get_ownership(const void *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __msan_get_allocated_size(const void *p);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __msan_get_current_allocated_bytes();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __msan_get_heap_size();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __msan_get_free_bytes();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __msan_get_unmapped_bytes();
+
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+/* OPTIONAL */ void __msan_malloc_hook(void *ptr, uptr size);
+
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+/* OPTIONAL */ void __msan_free_hook(void *ptr);
 }  // extern "C"
 
 #endif  // MSAN_INTERFACE_INTERNAL_H
diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc
index cda23b1..b82ed8c 100644
--- a/lib/msan/msan_linux.cc
+++ b/lib/msan/msan_linux.cc
@@ -12,11 +12,11 @@
 // Linux-specific code.
 //===----------------------------------------------------------------------===//
 
-#ifdef __linux__
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "msan.h"
 
-#include <algorithm>
 #include <elf.h>
 #include <link.h>
 #include <stdio.h>
@@ -91,41 +91,6 @@
   atexit(MsanAtExit);
 }
 
-void UnpoisonMappedDSO(link_map *map) {
-  typedef ElfW(Phdr) Elf_Phdr;
-  typedef ElfW(Ehdr) Elf_Ehdr;
-  char *base = (char *)map->l_addr;
-  Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
-  char *phdrs = base + ehdr->e_phoff;
-  char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
-
-  // Find the segment with the minimum base so we can "relocate" the p_vaddr
-  // fields.  Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
-  // objects have a non-zero base.
-  uptr preferred_base = ~0ULL;
-  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
-    Elf_Phdr *phdr = (Elf_Phdr *)iter;
-    if (phdr->p_type == PT_LOAD)
-      preferred_base = std::min(preferred_base, (uptr)phdr->p_vaddr);
-  }
-
-  // Compute the delta from the real base to get a relocation delta.
-  sptr delta = (uptr)base - preferred_base;
-  // Now we can figure out what the loader really mapped.
-  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
-    Elf_Phdr *phdr = (Elf_Phdr *)iter;
-    if (phdr->p_type == PT_LOAD) {
-      uptr seg_start = phdr->p_vaddr + delta;
-      uptr seg_end = seg_start + phdr->p_memsz;
-      // None of these values are aligned.  We consider the ragged edges of the
-      // load command as defined, since they are mapped from the file.
-      seg_start = RoundDownTo(seg_start, GetPageSizeCached());
-      seg_end = RoundUpTo(seg_end, GetPageSizeCached());
-      __msan_unpoison((void *)seg_start, seg_end - seg_start);
-    }
-  }
-}
-
 }  // namespace __msan
 
 #endif  // __linux__
diff --git a/lib/msan/msan_new_delete.cc b/lib/msan/msan_new_delete.cc
index c4efe2e..88d4364 100644
--- a/lib/msan/msan_new_delete.cc
+++ b/lib/msan/msan_new_delete.cc
@@ -14,6 +14,8 @@
 
 #include "msan.h"
 
+#if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
+
 #include <stddef.h>
 
 namespace __msan {
@@ -49,3 +51,5 @@
 void operator delete[](void *ptr, std::nothrow_t const&) {
   OPERATOR_DELETE_BODY;
 }
+
+#endif // MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc
index df6990f..d8a6996 100644
--- a/lib/msan/msan_report.cc
+++ b/lib/msan/msan_report.cc
@@ -13,7 +13,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "msan.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_mutex.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
@@ -21,8 +23,6 @@
 
 using namespace __sanitizer;
 
-static StaticSpinMutex report_mu;
-
 namespace __msan {
 
 static bool PrintsToTtyCached() {
@@ -46,7 +46,8 @@
 
 static void PrintStack(const uptr *trace, uptr size) {
   SymbolizerScope sym_scope;
-  StackTrace::PrintStack(trace, size, true, flags()->strip_path_prefix, 0);
+  StackTrace::PrintStack(trace, size, true,
+                         common_flags()->strip_path_prefix, 0);
 }
 
 static void DescribeOrigin(u32 origin) {
@@ -61,7 +62,7 @@
     Printf("%s", d.Origin());
     Printf("  %sUninitialized value was created by an allocation of '%s%s%s'"
            " in the stack frame of function '%s%s%s'%s\n",
-           d.Origin(), d.Name(), s, d.Origin(), d.Name(), sep + 1,
+           d.Origin(), d.Name(), s, d.Origin(), d.Name(), Demangle(sep + 1),
            d.Origin(), d.End());
     InternalFree(s);
   } else {
@@ -82,18 +83,19 @@
     SymbolizeCode(pc, &ai, 1);
   }
   ReportErrorSummary(error_type,
-                     StripPathPrefix(ai.file, flags()->strip_path_prefix),
+                     StripPathPrefix(ai.file,
+                                     common_flags()->strip_path_prefix),
                      ai.line, ai.function);
 }
 
 void ReportUMR(StackTrace *stack, u32 origin) {
   if (!__msan::flags()->report_umrs) return;
 
-  GenericScopedLock<StaticSpinMutex> lock(&report_mu);
+  SpinMutexLock l(&CommonSanitizerReportMutex);
 
   Decorator d;
   Printf("%s", d.Warning());
-  Report(" WARNING: Use of uninitialized value\n");
+  Report(" WARNING: MemorySanitizer: use-of-uninitialized-value\n");
   Printf("%s", d.End());
   PrintStack(stack->trace, stack->size);
   if (origin) {
@@ -103,13 +105,15 @@
 }
 
 void ReportExpectedUMRNotFound(StackTrace *stack) {
-  GenericScopedLock<StaticSpinMutex> lock(&report_mu);
+  SpinMutexLock l(&CommonSanitizerReportMutex);
 
   Printf(" WARNING: Expected use of uninitialized value not found\n");
   PrintStack(stack->trace, stack->size);
 }
 
 void ReportAtExitStatistics() {
+  SpinMutexLock l(&CommonSanitizerReportMutex);
+
   Decorator d;
   Printf("%s", d.Warning());
   Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);
diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt
index 813aad0..39aea1c 100644
--- a/lib/msan/tests/CMakeLists.txt
+++ b/lib/msan/tests/CMakeLists.txt
@@ -6,7 +6,6 @@
 include_directories(../..)
 
 # Instrumented libcxx sources and build flags.
-set(MSAN_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx)
 file(GLOB MSAN_LIBCXX_SOURCES ${MSAN_LIBCXX_PATH}/src/*.cpp)
 set(MSAN_LIBCXX_CFLAGS
   -I${MSAN_LIBCXX_PATH}/include
@@ -31,9 +30,10 @@
   -fsanitize=memory)
 
 # Unittest sources and build flags.
-set(MSAN_UNITTEST_SOURCE msan_test.cc)
+set(MSAN_UNITTEST_SOURCES msan_test.cc msan_test_main.cc)
 set(MSAN_LOADABLE_SOURCE msan_loadable.cc)
 set(MSAN_UNITTEST_HEADERS
+  msan_test_config.h
   msandr_test_so.h
   ../../../include/sanitizer/msan_interface.h
 )
@@ -46,7 +46,6 @@
   -I${COMPILER_RT_SOURCE_DIR}/lib/msan
   -std=c++0x
   -stdlib=libc++
-  -fPIE
   -g
   -O2
   -fno-exceptions
@@ -61,7 +60,6 @@
 )
 set(MSAN_UNITTEST_LINK_FLAGS
   -fsanitize=memory
-  -pie
   -ldl
   # FIXME: we build libcxx without cxxabi and need libstdc++ to provide it.
   -lstdc++
@@ -133,8 +131,10 @@
 
   # Instrumented tests.
   set(MSAN_INST_TEST_OBJECTS)
-  msan_compile(MSAN_INST_TEST_OBJECTS ${MSAN_UNITTEST_SOURCE} ${arch}
-               ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS})
+  foreach (SOURCE ${MSAN_UNITTEST_SOURCES})
+    msan_compile(MSAN_INST_TEST_OBJECTS ${SOURCE} ${arch}
+                 ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS})
+  endforeach(SOURCE)
 
   # Instrumented loadable module objects.
   set(MSAN_INST_LOADABLE_OBJECTS)
@@ -164,7 +164,7 @@
                 ${MSAN_INST_LIBCXX} ${MSANDR_TEST_SO})
 endmacro()
 
-if(COMPILER_RT_CAN_EXECUTE_TESTS AND EXISTS ${MSAN_LIBCXX_PATH}/)
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND MSAN_CAN_INSTRUMENT_LIBCXX)
   if(CAN_TARGET_x86_64)
     add_msan_tests_for_arch(x86_64)
   endif()
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc
index 3380c13..aa1e8eb 100644
--- a/lib/msan/tests/msan_test.cc
+++ b/lib/msan/tests/msan_test.cc
@@ -12,10 +12,14 @@
 // MemorySanitizer unit tests.
 //===----------------------------------------------------------------------===//
 
+#ifndef MSAN_EXTERNAL_TEST_CONFIG
+#include "msan_test_config.h"
+#endif // MSAN_EXTERNAL_TEST_CONFIG
+
 #include "sanitizer/msan_interface.h"
 #include "msandr_test_so.h"
-#include "gtest/gtest.h"
 
+#include <inttypes.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -23,8 +27,11 @@
 #include <wchar.h>
 #include <math.h>
 
+#include <arpa/inet.h>
 #include <dlfcn.h>
+#include <grp.h>
 #include <unistd.h>
+#include <link.h>
 #include <limits.h>
 #include <sys/time.h>
 #include <sys/types.h>
@@ -32,11 +39,14 @@
 #include <fcntl.h>
 #include <sys/resource.h>
 #include <sys/ioctl.h>
+#include <sys/sysinfo.h>
 #include <sys/utsname.h>
 #include <sys/mman.h>
 #include <sys/vfs.h>
-#include <sys/types.h>
 #include <dirent.h>
+#include <pwd.h>
+#include <sys/socket.h>
+#include <netdb.h>
 
 #if defined(__i386__) || defined(__x86_64__)
 # include <emmintrin.h>
@@ -514,6 +524,20 @@
   return res;
 }
 
+TEST(MemorySanitizer, strcmp) {
+  char s1[10];
+  char s2[10];
+  strncpy(s1, "foo", 10);
+  s2[0] = 'f';
+  s2[1] = 'n';
+  EXPECT_GT(strcmp(s1, s2), 0);
+  s2[1] = 'o';
+  int res;
+  EXPECT_UMR(res = strcmp(s1, s2));
+  EXPECT_NOT_POISONED(res);
+  EXPECT_EQ(strncmp(s1, s2, 1), 0);
+}
+
 TEST(MemorySanitizer, LargeRet) {
   LargeStruct a = LargeRetTest();
   EXPECT_POISONED(a.x[0]);
@@ -558,6 +582,52 @@
   delete x;
 }
 
+TEST(MemorySanitizer, readv) {
+  char buf[2011];
+  struct iovec iov[2];
+  iov[0].iov_base = buf + 1;
+  iov[0].iov_len = 5;
+  iov[1].iov_base = buf + 10;
+  iov[1].iov_len = 2000;
+  int fd = open("/proc/self/stat", O_RDONLY);
+  assert(fd > 0);
+  int sz = readv(fd, iov, 2);
+  ASSERT_LT(sz, 5 + 2000);
+  ASSERT_GT(sz, iov[0].iov_len);
+  EXPECT_POISONED(buf[0]);
+  EXPECT_NOT_POISONED(buf[1]);
+  EXPECT_NOT_POISONED(buf[5]);
+  EXPECT_POISONED(buf[6]);
+  EXPECT_POISONED(buf[9]);
+  EXPECT_NOT_POISONED(buf[10]);
+  EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]);
+  EXPECT_POISONED(buf[11 + (sz - 1) - 5]);
+  close(fd);
+}
+
+TEST(MemorySanitizer, preadv) {
+  char buf[2011];
+  struct iovec iov[2];
+  iov[0].iov_base = buf + 1;
+  iov[0].iov_len = 5;
+  iov[1].iov_base = buf + 10;
+  iov[1].iov_len = 2000;
+  int fd = open("/proc/self/stat", O_RDONLY);
+  assert(fd > 0);
+  int sz = preadv(fd, iov, 2, 3);
+  ASSERT_LT(sz, 5 + 2000);
+  ASSERT_GT(sz, iov[0].iov_len);
+  EXPECT_POISONED(buf[0]);
+  EXPECT_NOT_POISONED(buf[1]);
+  EXPECT_NOT_POISONED(buf[5]);
+  EXPECT_POISONED(buf[6]);
+  EXPECT_POISONED(buf[9]);
+  EXPECT_NOT_POISONED(buf[10]);
+  EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]);
+  EXPECT_POISONED(buf[11 + (sz - 1) - 5]);
+  close(fd);
+}
+
 // FIXME: fails now.
 TEST(MemorySanitizer, DISABLED_ioctl) {
   struct winsize ws;
@@ -601,6 +671,240 @@
   close(pipefd[1]);
 }
 
+TEST(MemorySanitizer, pipe2) {
+  int* pipefd = new int[2];
+  int res = pipe2(pipefd, O_NONBLOCK);
+  assert(!res);
+  EXPECT_NOT_POISONED(pipefd[0]);
+  EXPECT_NOT_POISONED(pipefd[1]);
+  close(pipefd[0]);
+  close(pipefd[1]);
+}
+
+TEST(MemorySanitizer, socketpair) {
+  int sv[2];
+  int res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+  assert(!res);
+  EXPECT_NOT_POISONED(sv[0]);
+  EXPECT_NOT_POISONED(sv[1]);
+  close(sv[0]);
+  close(sv[1]);
+}
+
+TEST(MemorySanitizer, bind_getsockname) {
+  int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+  struct sockaddr_in sai;
+  memset(&sai, 0, sizeof(sai));
+  sai.sin_family = AF_UNIX;
+  int res = bind(sock, (struct sockaddr *)&sai, sizeof(sai));
+
+  assert(!res);
+  char buf[200];
+  socklen_t addrlen;
+  EXPECT_UMR(getsockname(sock, (struct sockaddr *)&buf, &addrlen));
+
+  addrlen = sizeof(buf);
+  res = getsockname(sock, (struct sockaddr *)&buf, &addrlen);
+  EXPECT_NOT_POISONED(addrlen);
+  EXPECT_NOT_POISONED(buf[0]);
+  EXPECT_NOT_POISONED(buf[addrlen - 1]);
+  EXPECT_POISONED(buf[addrlen]);
+  close(sock);
+}
+
+TEST(MemorySanitizer, accept) {
+  int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
+  ASSERT_LT(0, listen_socket);
+
+  struct sockaddr_in sai;
+  sai.sin_family = AF_INET;
+  sai.sin_port = 0;
+  sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  int res = bind(listen_socket, (struct sockaddr *)&sai, sizeof(sai));
+  ASSERT_EQ(0, res);
+
+  res = listen(listen_socket, 1);
+  ASSERT_EQ(0, res);
+
+  socklen_t sz = sizeof(sai);
+  res = getsockname(listen_socket, (struct sockaddr *)&sai, &sz);
+  ASSERT_EQ(0, res);
+  ASSERT_EQ(sizeof(sai), sz);
+
+  int connect_socket = socket(AF_INET, SOCK_STREAM, 0);
+  ASSERT_LT(0, connect_socket);
+  res = fcntl(connect_socket, F_SETFL, O_NONBLOCK);
+  ASSERT_EQ(0, res);
+  res = connect(connect_socket, (struct sockaddr *)&sai, sizeof(sai));
+  ASSERT_EQ(-1, res);
+  ASSERT_EQ(EINPROGRESS, errno);
+
+  __msan_poison(&sai, sizeof(sai));
+  int new_sock = accept(listen_socket, (struct sockaddr *)&sai, &sz);
+  ASSERT_LT(0, new_sock);
+  ASSERT_EQ(sizeof(sai), sz);
+  EXPECT_NOT_POISONED(sai);
+
+  __msan_poison(&sai, sizeof(sai));
+  res = getpeername(new_sock, (struct sockaddr *)&sai, &sz);
+  ASSERT_EQ(0, res);
+  ASSERT_EQ(sizeof(sai), sz);
+  EXPECT_NOT_POISONED(sai);
+
+  close(new_sock);
+  close(connect_socket);
+  close(listen_socket);
+}
+
+TEST(MemorySanitizer, getaddrinfo) {
+  struct addrinfo *ai;
+  struct addrinfo hints;
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_INET;
+  int res = getaddrinfo("localhost", NULL, &hints, &ai);
+  ASSERT_EQ(0, res);
+  EXPECT_NOT_POISONED(*ai);
+  ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen);
+  EXPECT_NOT_POISONED(*(sockaddr_in*)ai->ai_addr); 
+}
+
+TEST(MemorySanitizer, getnameinfo) {
+  struct sockaddr_in sai;
+  sai.sin_family = AF_INET;
+  sai.sin_port = 80;
+  sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  char host[500];
+  char serv[500];
+  int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host,
+                        sizeof(host), serv, sizeof(serv), 0);
+  ASSERT_EQ(0, res);
+  EXPECT_NOT_POISONED(host[0]);
+  EXPECT_POISONED(host[sizeof(host) - 1]);
+
+  ASSERT_NE(0, strlen(host));
+  EXPECT_NOT_POISONED(serv[0]);
+  EXPECT_POISONED(serv[sizeof(serv) - 1]);
+  ASSERT_NE(0, strlen(serv));
+}
+
+#define EXPECT_HOSTENT_NOT_POISONED(he)        \
+  do {                                         \
+    EXPECT_NOT_POISONED(*(he));                \
+    ASSERT_NE((void *) 0, (he)->h_name);       \
+    ASSERT_NE((void *) 0, (he)->h_aliases);    \
+    ASSERT_NE((void *) 0, (he)->h_addr_list);  \
+    EXPECT_NOT_POISONED(strlen((he)->h_name)); \
+    char **p = (he)->h_aliases;                \
+    while (*p) {                               \
+      EXPECT_NOT_POISONED(strlen(*p));         \
+      ++p;                                     \
+    }                                          \
+    char **q = (he)->h_addr_list;              \
+    while (*q) {                               \
+      EXPECT_NOT_POISONED(*q[0]);              \
+      ++q;                                     \
+    }                                          \
+    EXPECT_NOT_POISONED(*q);                   \
+  } while (0)
+
+TEST(MemorySanitizer, gethostent) {
+  struct hostent *he = gethostent();
+  ASSERT_NE((void *)NULL, he);
+  EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+#ifndef MSAN_TEST_DISABLE_GETHOSTBYNAME
+
+TEST(MemorySanitizer, gethostbyname) {
+  struct hostent *he = gethostbyname("localhost");
+  ASSERT_NE((void *)NULL, he);
+  EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+#endif // MSAN_TEST_DISABLE_GETHOSTBYNAME
+
+TEST(MemorySanitizer, gethostbyname2) {
+  struct hostent *he = gethostbyname2("localhost", AF_INET);
+  ASSERT_NE((void *)NULL, he);
+  EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+TEST(MemorySanitizer, gethostbyaddr) {
+  in_addr_t addr = inet_addr("127.0.0.1");
+  EXPECT_NOT_POISONED(addr);
+  struct hostent *he = gethostbyaddr(&addr, sizeof(addr), AF_INET);
+  ASSERT_NE((void *)NULL, he);
+  EXPECT_HOSTENT_NOT_POISONED(he);
+}
+
+TEST(MemorySanitizer, gethostent_r) {
+  char buf[2000];
+  struct hostent he;
+  struct hostent *result;
+  int err;
+  int res = gethostent_r(&he, buf, sizeof(buf), &result, &err);
+  ASSERT_EQ(0, res);
+  EXPECT_NOT_POISONED(result);
+  ASSERT_NE((void *)NULL, result);
+  EXPECT_HOSTENT_NOT_POISONED(result);
+  EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname_r) {
+  char buf[2000];
+  struct hostent he;
+  struct hostent *result;
+  int err;
+  int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err);
+  ASSERT_EQ(0, res);
+  EXPECT_NOT_POISONED(result);
+  ASSERT_NE((void *)NULL, result);
+  EXPECT_HOSTENT_NOT_POISONED(result);
+  EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyname2_r) {
+  char buf[2000];
+  struct hostent he;
+  struct hostent *result;
+  int err;
+  int res = gethostbyname2_r("localhost", AF_INET, &he, buf, sizeof(buf),
+                             &result, &err);
+  ASSERT_EQ(0, res);
+  EXPECT_NOT_POISONED(result);
+  ASSERT_NE((void *)NULL, result);
+  EXPECT_HOSTENT_NOT_POISONED(result);
+  EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, gethostbyaddr_r) {
+  char buf[2000];
+  struct hostent he;
+  struct hostent *result;
+  int err;
+  in_addr_t addr = inet_addr("127.0.0.1");
+  EXPECT_NOT_POISONED(addr);
+  int res = gethostbyaddr_r(&addr, sizeof(addr), AF_INET, &he, buf, sizeof(buf),
+                            &result, &err);
+  ASSERT_EQ(0, res);
+  EXPECT_NOT_POISONED(result);
+  ASSERT_NE((void *)NULL, result);
+  EXPECT_HOSTENT_NOT_POISONED(result);
+  EXPECT_NOT_POISONED(err);
+}
+
+TEST(MemorySanitizer, getsockopt) {
+  int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+  struct linger l[2];
+  socklen_t sz = sizeof(l[0]);
+  int res = getsockopt(sock, SOL_SOCKET, SO_LINGER, &l[0], &sz);
+  ASSERT_EQ(0, res);
+  ASSERT_EQ(sizeof(l[0]), sz);
+  EXPECT_NOT_POISONED(l[0]);
+  EXPECT_POISONED(*(char *)(l + 1));
+}
+
 TEST(MemorySanitizer, getcwd) {
   char path[PATH_MAX + 1];
   char* res = getcwd(path, sizeof(path));
@@ -615,6 +919,29 @@
   free(res);
 }
 
+TEST(MemorySanitizer, get_current_dir_name) {
+  char* res = get_current_dir_name();
+  assert(res);
+  EXPECT_NOT_POISONED(res[0]);
+  free(res);
+}
+
+TEST(MemorySanitizer, confstr) {
+  char buf[3];
+  size_t res = confstr(_CS_PATH, buf, sizeof(buf));
+  ASSERT_GT(res, sizeof(buf));
+  EXPECT_NOT_POISONED(buf[0]);
+  EXPECT_NOT_POISONED(buf[sizeof(buf) - 1]);
+
+  char buf2[1000];
+  res = confstr(_CS_PATH, buf2, sizeof(buf2));
+  ASSERT_LT(res, sizeof(buf2));
+  EXPECT_NOT_POISONED(buf2[0]);
+  EXPECT_NOT_POISONED(buf2[res - 1]);
+  EXPECT_POISONED(buf2[res]);
+  ASSERT_EQ(res, strlen(buf2) + 1);
+}
+
 TEST(MemorySanitizer, readdir) {
   DIR *dir = opendir(".");
   struct dirent *d = readdir(dir);
@@ -623,6 +950,17 @@
   closedir(dir);
 }
 
+TEST(MemorySanitizer, readdir_r) {
+  DIR *dir = opendir(".");
+  struct dirent d;
+  struct dirent *pd;
+  int res = readdir_r(dir, &d, &pd);
+  assert(!res);
+  EXPECT_NOT_POISONED(pd);
+  EXPECT_NOT_POISONED(d.d_name[0]);
+  closedir(dir);
+}
+
 TEST(MemorySanitizer, realpath) {
   const char* relpath = ".";
   char path[PATH_MAX + 1];
@@ -631,6 +969,42 @@
   EXPECT_NOT_POISONED(path[0]);
 }
 
+TEST(MemorySanitizer, realpath_null) {
+  const char* relpath = ".";
+  char* res = realpath(relpath, NULL);
+  printf("%d, %s\n", errno, strerror(errno));
+  assert(res);
+  EXPECT_NOT_POISONED(res[0]);
+  free(res);
+}
+
+TEST(MemorySanitizer, canonicalize_file_name) {
+  const char* relpath = ".";
+  char* res = canonicalize_file_name(relpath);
+  assert(res);
+  EXPECT_NOT_POISONED(res[0]);
+  free(res);
+}
+
+extern char **environ;
+
+TEST(MemorySanitizer, setenv) {
+  setenv("AAA", "BBB", 1);
+  for (char **envp = environ; *envp; ++envp) {
+    EXPECT_NOT_POISONED(*envp);
+    EXPECT_NOT_POISONED(*envp[0]);
+  }
+}
+
+TEST(MemorySanitizer, putenv) {
+  char s[] = "AAA=BBB";
+  putenv(s);
+  for (char **envp = environ; *envp; ++envp) {
+    EXPECT_NOT_POISONED(*envp);
+    EXPECT_NOT_POISONED(*envp[0]);
+  }
+}
+
 TEST(MemorySanitizer, memcpy) {
   char* x = new char[2];
   char* y = new char[2];
@@ -651,6 +1025,16 @@
   EXPECT_POISONED(y[1]);
 }
 
+TEST(MemorySanitizer, bcopy) {
+  char* x = new char[2];
+  char* y = new char[2];
+  x[0] = 1;
+  x[1] = *GetPoisoned<char>();
+  bcopy(x, y, 2);
+  EXPECT_NOT_POISONED(y[0]);
+  EXPECT_POISONED(y[1]);
+}
+
 TEST(MemorySanitizer, strdup) {
   char buf[4] = "abc";
   __msan_poison(buf + 2, sizeof(*buf));
@@ -733,6 +1117,19 @@
   EXPECT_POISONED(y[2]);
 }
 
+TEST(MemorySanitizer, stpcpy) {  // NOLINT
+  char* x = new char[3];
+  char* y = new char[3];
+  x[0] = 'a';
+  x[1] = *GetPoisoned<char>(1, 1);
+  x[2] = 0;
+  char *res = stpcpy(y, x);  // NOLINT
+  ASSERT_EQ(res, y + 2);
+  EXPECT_NOT_POISONED(y[0]);
+  EXPECT_POISONED(y[1]);
+  EXPECT_NOT_POISONED(y[2]);
+}
+
 TEST(MemorySanitizer, strtol) {
   char *e;
   assert(1 == strtol("1", &e, 10));
@@ -757,6 +1154,18 @@
   EXPECT_NOT_POISONED((S8) e);
 }
 
+TEST(MemorySanitizer, strtoimax) {
+  char *e;
+  assert(1 == strtoimax("1", &e, 10));
+  EXPECT_NOT_POISONED((S8) e);
+}
+
+TEST(MemorySanitizer, strtoumax) {
+  char *e;
+  assert(1 == strtoumax("1", &e, 10));
+  EXPECT_NOT_POISONED((S8) e);
+}
+
 TEST(MemorySanitizer, strtod) {
   char *e;
   assert(0 != strtod("1.5", &e));
@@ -775,6 +1184,24 @@
   EXPECT_NOT_POISONED((S8) e);
 }
 
+TEST(MemorySanitizer, modf) {
+  double x, y;
+  x = modf(2.1, &y);
+  EXPECT_NOT_POISONED(y);
+}
+
+TEST(MemorySanitizer, modff) {
+  float x, y;
+  x = modff(2.1, &y);
+  EXPECT_NOT_POISONED(y);
+}
+
+TEST(MemorySanitizer, modfl) {
+  long double x, y;
+  x = modfl(2.1, &y);
+  EXPECT_NOT_POISONED(y);
+}
+
 TEST(MemorySanitizer, sprintf) {  // NOLINT
   char buff[10];
   break_optimization(buff);
@@ -818,6 +1245,33 @@
   EXPECT_POISONED(buff[8]);
 }
 
+TEST(MemorySanitizer, asprintf) {  // NOLINT
+  char *pbuf;
+  EXPECT_POISONED(pbuf);
+  int res = asprintf(&pbuf, "%d", 1234567);  // NOLINT
+  assert(res == 7);
+  EXPECT_NOT_POISONED(pbuf);
+  assert(pbuf[0] == '1');
+  assert(pbuf[1] == '2');
+  assert(pbuf[2] == '3');
+  assert(pbuf[6] == '7');
+  assert(pbuf[7] == 0);
+  free(pbuf);
+}
+
+TEST(MemorySanitizer, mbstowcs) {
+  const char *x = "abc";
+  wchar_t buff[10];
+  int res = mbstowcs(buff, x, 2);
+  EXPECT_EQ(2, res);
+  EXPECT_EQ(L'a', buff[0]);
+  EXPECT_EQ(L'b', buff[1]);
+  EXPECT_POISONED(buff[2]);
+  res = mbstowcs(buff, x, 10);
+  EXPECT_EQ(3, res);
+  EXPECT_NOT_POISONED(buff[3]);
+}
+
 TEST(MemorySanitizer, wcstombs) {
   const wchar_t *x = L"abc";
   char buff[10];
@@ -828,6 +1282,52 @@
   EXPECT_EQ(buff[2], 'c');
 }
 
+TEST(MemorySanitizer, wcsrtombs) {
+  const wchar_t *x = L"abc";
+  const wchar_t *p = x;
+  char buff[10];
+  mbstate_t mbs;
+  memset(&mbs, 0, sizeof(mbs));
+  int res = wcsrtombs(buff, &p, 4, &mbs);
+  EXPECT_EQ(res, 3);
+  EXPECT_EQ(buff[0], 'a');
+  EXPECT_EQ(buff[1], 'b');
+  EXPECT_EQ(buff[2], 'c');
+  EXPECT_EQ(buff[3], '\0');
+  EXPECT_POISONED(buff[4]);
+}
+
+TEST(MemorySanitizer, wcsnrtombs) {
+  const wchar_t *x = L"abc";
+  const wchar_t *p = x;
+  char buff[10];
+  mbstate_t mbs;
+  memset(&mbs, 0, sizeof(mbs));
+  int res = wcsnrtombs(buff, &p, 2, 4, &mbs);
+  EXPECT_EQ(res, 2);
+  EXPECT_EQ(buff[0], 'a');
+  EXPECT_EQ(buff[1], 'b');
+  EXPECT_POISONED(buff[2]);
+}
+
+TEST(MemorySanitizer, mbtowc) {
+  const char *x = "abc";
+  wchar_t wx;
+  int res = mbtowc(&wx, x, 3);
+  EXPECT_GT(res, 0);
+  EXPECT_NOT_POISONED(wx);
+}
+
+TEST(MemorySanitizer, mbrtowc) {
+  const char *x = "abc";
+  wchar_t wx;
+  mbstate_t mbs;
+  memset(&mbs, 0, sizeof(mbs));
+  int res = mbrtowc(&wx, x, 3, &mbs);
+  EXPECT_GT(res, 0);
+  EXPECT_NOT_POISONED(wx);
+}
+
 TEST(MemorySanitizer, gettimeofday) {
   struct timeval tv;
   struct timezone tz;
@@ -846,6 +1346,72 @@
   EXPECT_NOT_POISONED(tz.tz_dsttime);
 }
 
+TEST(MemorySanitizer, clock_gettime) {
+  struct timespec tp;
+  EXPECT_POISONED(tp.tv_sec);
+  EXPECT_POISONED(tp.tv_nsec);
+  assert(0 == clock_gettime(CLOCK_REALTIME, &tp));
+  EXPECT_NOT_POISONED(tp.tv_sec);
+  EXPECT_NOT_POISONED(tp.tv_nsec);
+}
+
+TEST(MemorySanitizer, clock_getres) {
+  struct timespec tp;
+  EXPECT_POISONED(tp.tv_sec);
+  EXPECT_POISONED(tp.tv_nsec);
+  assert(0 == clock_getres(CLOCK_REALTIME, 0));
+  EXPECT_POISONED(tp.tv_sec);
+  EXPECT_POISONED(tp.tv_nsec);
+  assert(0 == clock_getres(CLOCK_REALTIME, &tp));
+  EXPECT_NOT_POISONED(tp.tv_sec);
+  EXPECT_NOT_POISONED(tp.tv_nsec);
+}
+
+TEST(MemorySanitizer, getitimer) {
+  struct itimerval it1, it2;
+  int res;
+  EXPECT_POISONED(it1.it_interval.tv_sec);
+  EXPECT_POISONED(it1.it_interval.tv_usec);
+  EXPECT_POISONED(it1.it_value.tv_sec);
+  EXPECT_POISONED(it1.it_value.tv_usec);
+  res = getitimer(ITIMER_VIRTUAL, &it1);
+  assert(!res);
+  EXPECT_NOT_POISONED(it1.it_interval.tv_sec);
+  EXPECT_NOT_POISONED(it1.it_interval.tv_usec);
+  EXPECT_NOT_POISONED(it1.it_value.tv_sec);
+  EXPECT_NOT_POISONED(it1.it_value.tv_usec);
+
+  it1.it_interval.tv_sec = it1.it_value.tv_sec = 10000;
+  it1.it_interval.tv_usec = it1.it_value.tv_usec = 0;
+
+  res = setitimer(ITIMER_VIRTUAL, &it1, &it2);
+  assert(!res);
+  EXPECT_NOT_POISONED(it2.it_interval.tv_sec);
+  EXPECT_NOT_POISONED(it2.it_interval.tv_usec);
+  EXPECT_NOT_POISONED(it2.it_value.tv_sec);
+  EXPECT_NOT_POISONED(it2.it_value.tv_usec);
+
+  // Check that old_value can be 0, and disable the timer.
+  memset(&it1, 0, sizeof(it1));
+  res = setitimer(ITIMER_VIRTUAL, &it1, 0);
+  assert(!res);
+}
+
+TEST(MemorySanitizer, setitimer_null) {
+  setitimer(ITIMER_VIRTUAL, 0, 0);
+  // Not testing the return value, since it the behaviour seems to differ
+  // between libc implementations and POSIX.
+  // Should never crash, though.
+}
+
+TEST(MemorySanitizer, time) {
+  time_t t;
+  EXPECT_POISONED(t);
+  time_t t2 = time(&t);
+  assert(t2 != (time_t)-1);
+  EXPECT_NOT_POISONED(t);
+}
+
 TEST(MemorySanitizer, localtime) {
   time_t t = 123;
   struct tm *time = localtime(&t);
@@ -917,6 +1483,68 @@
   EXPECT_NOT_POISONED(x);
 }
 
+namespace {
+
+static int cnt;
+
+void SigactionHandler(int signo, siginfo_t* si, void* uc) {
+  assert(signo == SIGPROF);
+  assert(si);
+  EXPECT_NOT_POISONED(si->si_errno);
+  EXPECT_NOT_POISONED(si->si_pid);
+#if __linux__
+# if defined(__x86_64__)
+  EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_RIP]);
+# elif defined(__i386__)
+  EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP]);
+# endif
+#endif
+  ++cnt;
+}
+
+TEST(MemorySanitizer, sigaction) {
+  struct sigaction act = {};
+  struct sigaction oldact = {};
+  struct sigaction origact = {};
+
+  sigaction(SIGPROF, 0, &origact);
+
+  act.sa_flags |= SA_SIGINFO;
+  act.sa_sigaction = &SigactionHandler;
+  sigaction(SIGPROF, &act, 0);
+
+  kill(getpid(), SIGPROF);
+
+  act.sa_flags &= ~SA_SIGINFO;
+  act.sa_handler = SIG_DFL;
+  sigaction(SIGPROF, &act, 0);
+
+  act.sa_flags &= ~SA_SIGINFO;
+  act.sa_handler = SIG_IGN;
+  sigaction(SIGPROF, &act, &oldact);
+  EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO);
+  EXPECT_EQ(SIG_DFL, oldact.sa_handler);
+  kill(getpid(), SIGPROF);
+
+  act.sa_flags |= SA_SIGINFO;
+  act.sa_sigaction = &SigactionHandler;
+  sigaction(SIGPROF, &act, &oldact);
+  EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO);
+  EXPECT_EQ(SIG_IGN, oldact.sa_handler);
+  kill(getpid(), SIGPROF);
+
+  act.sa_flags &= ~SA_SIGINFO;
+  act.sa_handler = SIG_DFL;
+  sigaction(SIGPROF, &act, &oldact);
+  EXPECT_TRUE(oldact.sa_flags & SA_SIGINFO);
+  EXPECT_EQ(&SigactionHandler, oldact.sa_sigaction);
+  EXPECT_EQ(2, cnt);
+
+  sigaction(SIGPROF, &origact, 0);
+}
+
+} // namespace
+
 struct StructWithDtor {
   ~StructWithDtor();
 };
@@ -1163,8 +1791,8 @@
 
 
 #if MSAN_HAS_M128
-NOINLINE __m128i m128Eq(__m128i *a, __m128i *b) { return *a == *b; }
-NOINLINE __m128i m128Lt(__m128i *a, __m128i *b) { return *a < *b; }
+NOINLINE __m128i m128Eq(__m128i *a, __m128i *b) { return _mm_cmpeq_epi16(*a, *b); }
+NOINLINE __m128i m128Lt(__m128i *a, __m128i *b) { return _mm_cmplt_epi16(*a, *b); }
 TEST(MemorySanitizer, m128) {
   __m128i a = _mm_set1_epi16(0x1234);
   __m128i b = _mm_set1_epi16(0x7890);
@@ -1304,9 +1932,8 @@
   __msan_poison(&limit, sizeof(limit));
   int result = getrlimit(RLIMIT_DATA, &limit);
   assert(result == 0);
-  volatile rlim_t t;
-  t = limit.rlim_cur;
-  t = limit.rlim_max;
+  EXPECT_NOT_POISONED(limit.rlim_cur);
+  EXPECT_NOT_POISONED(limit.rlim_max);
 }
 
 TEST(MemorySanitizer, getrusage) {
@@ -1314,7 +1941,6 @@
   __msan_poison(&usage, sizeof(usage));
   int result = getrusage(RUSAGE_SELF, &usage);
   assert(result == 0);
-  volatile struct timeval t;
   EXPECT_NOT_POISONED(usage.ru_utime.tv_sec);
   EXPECT_NOT_POISONED(usage.ru_utime.tv_usec);
   EXPECT_NOT_POISONED(usage.ru_stime.tv_sec);
@@ -1328,6 +1954,12 @@
   EXPECT_NOT_POISONED(usage.ru_nivcsw);
 }
 
+#ifdef __GLIBC__
+extern char *program_invocation_name;
+#else  // __GLIBC__
+# error "TODO: port this"
+#endif
+
 static void dladdr_testfn() {}
 
 TEST(MemorySanitizer, dladdr) {
@@ -1345,31 +1977,52 @@
   EXPECT_NOT_POISONED((unsigned long)info.dli_saddr);
 }
 
-#ifdef __GLIBC__
-extern "C" {
-  extern void *__libc_stack_end;
+#ifndef MSAN_TEST_DISABLE_DLOPEN
+
+static int dl_phdr_callback(struct dl_phdr_info *info, size_t size, void *data) {
+  (*(int *)data)++;
+  EXPECT_NOT_POISONED(info->dlpi_addr);
+  EXPECT_NOT_POISONED(strlen(info->dlpi_name));
+  EXPECT_NOT_POISONED(info->dlpi_phnum);
+  for (int i = 0; i < info->dlpi_phnum; ++i)
+    EXPECT_NOT_POISONED(info->dlpi_phdr[i]);
+  return 0;
 }
 
-static char **GetArgv(void) {
-  uintptr_t *stack_end = (uintptr_t *)__libc_stack_end;
-  return (char**)(stack_end + 1);
+// Compute the path to our loadable DSO.  We assume it's in the same
+// directory.  Only use string routines that we intercept so far to do this.
+static int PathToLoadable(char *buf, size_t sz) {
+  const char *basename = "libmsan_loadable.x86_64.so";
+  char *argv0 = program_invocation_name;
+  char *last_slash = strrchr(argv0, '/');
+  assert(last_slash);
+  int res =
+      snprintf(buf, sz, "%.*s/%s", int(last_slash - argv0), argv0, basename);
+  return res < sz ? 0 : res;
 }
 
-#else  // __GLIBC__
-# error "TODO: port this"
-#endif
+TEST(MemorySanitizer, dl_iterate_phdr) {
+  char path[4096];
+  int res = PathToLoadable(path, sizeof(path));
+  assert(!res);
+
+  // Having at least one dlopen'ed library in the process makes this more
+  // entertaining.
+  void *lib = dlopen(path, RTLD_LAZY);
+  ASSERT_NE((void*)0, lib);
+
+  int count = 0;
+  int result = dl_iterate_phdr(dl_phdr_callback, &count);
+  assert(count > 0);
+  
+  dlclose(lib);
+}
+
 
 TEST(MemorySanitizer, dlopen) {
-  // Compute the path to our loadable DSO.  We assume it's in the same
-  // directory.  Only use string routines that we intercept so far to do this.
-  char **argv = GetArgv();
-  const char *basename = "libmsan_loadable.x86_64.so";
-  size_t path_max = strlen(argv[0]) + 1 + strlen(basename) + 1;
-  char *path = new char[path_max];
-  char *last_slash = strrchr(argv[0], '/');
-  assert(last_slash);
-  snprintf(path, path_max, "%.*s/%s", int(last_slash - argv[0]),
-           argv[0], basename);
+  char path[4096];
+  int res = PathToLoadable(path, sizeof(path));
+  assert(!res);
 
   // We need to clear shadow for globals when doing dlopen.  In order to test
   // this, we have to poison the shadow for the DSO before we load it.  In
@@ -1390,8 +2043,22 @@
     EXPECT_POISONED(*dso_global);
     dlclose(lib);
   }
+}
 
-  delete[] path;
+// Regression test for a crash in dlopen() interceptor.
+TEST(MemorySanitizer, dlopenFailed) {
+  const char *path = "/libmsan_loadable_does_not_exist.x86_64.so";
+  void *lib = dlopen(path, RTLD_LAZY);
+  ASSERT_EQ(0, lib);
+}
+
+#endif // MSAN_TEST_DISABLE_DLOPEN
+
+TEST(MemorySanitizer, sched_getaffinity) {
+  cpu_set_t mask;
+  int res = sched_getaffinity(getpid(), sizeof(mask), &mask);
+  ASSERT_EQ(0, res);
+  EXPECT_NOT_POISONED(mask);
 }
 
 TEST(MemorySanitizer, scanf) {
@@ -1413,36 +2080,36 @@
   delete d;
 }
 
-static void* SimpleThread_threadfn(void* data) {
+static void *SimpleThread_threadfn(void* data) {
   return new int;
 }
 
 TEST(MemorySanitizer, SimpleThread) {
   pthread_t t;
-  void* p;
+  void *p;
   int res = pthread_create(&t, NULL, SimpleThread_threadfn, NULL);
   assert(!res);
+  EXPECT_NOT_POISONED(t);
   res = pthread_join(t, &p);
   assert(!res);
-  if (!__msan_has_dynamic_component())  // FIXME: intercept pthread_join (?).
-    __msan_unpoison(&p, sizeof(p));
+  EXPECT_NOT_POISONED(p);
   delete (int*)p;
 }
 
-static void* SmallStackThread_threadfn(void* data) {
+static void *SmallStackThread_threadfn(void* data) {
   return 0;
 }
 
 TEST(MemorySanitizer, SmallStackThread) {
   pthread_attr_t attr;
   pthread_t t;
-  void* p;
+  void *p;
   int res;
   res = pthread_attr_init(&attr);
   ASSERT_EQ(0, res);
   res = pthread_attr_setstacksize(&attr, 64 * 1024);
   ASSERT_EQ(0, res);
-  res = pthread_create(&t, &attr, SimpleThread_threadfn, NULL);
+  res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL);
   ASSERT_EQ(0, res);
   res = pthread_join(t, &p);
   ASSERT_EQ(0, res);
@@ -1450,6 +2117,77 @@
   ASSERT_EQ(0, res);
 }
 
+TEST(MemorySanitizer, PreAllocatedStackThread) {
+  pthread_attr_t attr;
+  pthread_t t;
+  int res;
+  res = pthread_attr_init(&attr);
+  ASSERT_EQ(0, res);
+  void *stack;
+  const size_t kStackSize = 64 * 1024;
+  res = posix_memalign(&stack, 4096, kStackSize);
+  ASSERT_EQ(0, res);
+  res = pthread_attr_setstack(&attr, stack, kStackSize);
+  ASSERT_EQ(0, res);
+  // A small self-allocated stack can not be extended by the tool.
+  // In this case pthread_create is expected to fail.
+  res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL);
+  EXPECT_NE(0, res);
+  res = pthread_attr_destroy(&attr);
+  ASSERT_EQ(0, res);
+}
+
+TEST(MemorySanitizer, pthread_getschedparam) {
+  int policy;
+  struct sched_param param;
+  int res = pthread_getschedparam(pthread_self(), &policy, &param);
+  ASSERT_EQ(0, res);
+  EXPECT_NOT_POISONED(policy);
+  EXPECT_NOT_POISONED(param.sched_priority);
+}
+
+TEST(MemorySanitizer, pthread_key_create) {
+  pthread_key_t key;
+  int res = pthread_key_create(&key, NULL);
+  assert(!res);
+  EXPECT_NOT_POISONED(key);
+  res = pthread_key_delete(key);
+  assert(!res);
+}
+
+TEST(MemorySanitizer, posix_memalign) {
+  void *p;
+  EXPECT_POISONED(p);
+  int res = posix_memalign(&p, 4096, 13);
+  ASSERT_EQ(0, res);
+  EXPECT_NOT_POISONED(p);
+  free(p);
+}
+
+TEST(MemorySanitizer, inet_pton) {
+  const char *s = "1:0:0:0:0:0:0:8";
+  unsigned char buf[sizeof(struct in6_addr)];
+  int res = inet_pton(AF_INET6, s, buf);
+  ASSERT_EQ(1, res);
+  EXPECT_NOT_POISONED(buf[0]);
+  EXPECT_NOT_POISONED(buf[sizeof(struct in6_addr) - 1]);
+
+  char s_out[INET6_ADDRSTRLEN];
+  EXPECT_POISONED(s_out[3]);
+  const char *q = inet_ntop(AF_INET6, buf, s_out, INET6_ADDRSTRLEN);
+  ASSERT_NE((void*)0, q);
+  EXPECT_NOT_POISONED(s_out[3]);
+}
+
+TEST(MemorySanitizer, inet_aton) {
+  const char *s = "127.0.0.1";
+  struct in_addr in[2];
+  int res = inet_aton(s, in);
+  ASSERT_NE(0, res);
+  EXPECT_NOT_POISONED(in[0]);
+  EXPECT_POISONED(*(char *)(in + 1));
+}
+
 TEST(MemorySanitizer, uname) {
   struct utsname u;
   int res = uname(&u);
@@ -1468,6 +2206,59 @@
   EXPECT_NOT_POISONED(strlen(buf));
 }
 
+TEST(MemorySanitizer, sysinfo) {
+  struct sysinfo info;
+  int res = sysinfo(&info);
+  assert(!res);
+  EXPECT_NOT_POISONED(info);
+}
+
+TEST(MemorySanitizer, getpwuid) {
+  struct passwd *p = getpwuid(0); // root
+  assert(p);
+  EXPECT_NOT_POISONED(p->pw_name);
+  assert(p->pw_name);
+  EXPECT_NOT_POISONED(p->pw_name[0]);
+  EXPECT_NOT_POISONED(p->pw_uid);
+  assert(p->pw_uid == 0);
+}
+
+TEST(MemorySanitizer, getpwnam_r) {
+  struct passwd pwd;
+  struct passwd *pwdres;
+  char buf[10000];
+  int res = getpwnam_r("root", &pwd, buf, sizeof(buf), &pwdres);
+  assert(!res);
+  EXPECT_NOT_POISONED(pwd.pw_name);
+  assert(pwd.pw_name);
+  EXPECT_NOT_POISONED(pwd.pw_name[0]);
+  EXPECT_NOT_POISONED(pwd.pw_uid);
+  assert(pwd.pw_uid == 0);
+}
+
+TEST(MemorySanitizer, getpwnam_r_positive) {
+  struct passwd pwd;
+  struct passwd *pwdres;
+  char s[5];
+  strncpy(s, "abcd", 5);
+  __msan_poison(s, 5);
+  char buf[10000];
+  int res;
+  EXPECT_UMR(res = getpwnam_r(s, &pwd, buf, sizeof(buf), &pwdres));
+}
+
+TEST(MemorySanitizer, getgrnam_r) {
+  struct group grp;
+  struct group *grpres;
+  char buf[10000];
+  int res = getgrnam_r("root", &grp, buf, sizeof(buf), &grpres);
+  assert(!res);
+  EXPECT_NOT_POISONED(grp.gr_name);
+  assert(grp.gr_name);
+  EXPECT_NOT_POISONED(grp.gr_name[0]);
+  EXPECT_NOT_POISONED(grp.gr_gid);
+}
+
 template<class T>
 static bool applySlt(T value, T shadow) {
   __msan_partial_poison(&value, &shadow, sizeof(T));
@@ -1546,14 +2337,17 @@
 
 #if MSAN_HAS_M128
 TEST(MemorySanitizer, ICmpVectorRelational) {
-  EXPECT_NOT_POISONED(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0)) <
-                      poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0)));
-  EXPECT_NOT_POISONED(poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0)) <
-                      poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0)));
-  EXPECT_POISONED(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF)) <
-                  poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF)));
-  EXPECT_POISONED(poisoned(_mm_set1_epi16(6), _mm_set1_epi16(0xF)) >
-                  poisoned(_mm_set1_epi16(7), _mm_set1_epi16(0)));
+  EXPECT_NOT_POISONED(
+      _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0)),
+                   poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0))));
+  EXPECT_NOT_POISONED(
+      _mm_cmplt_epi16(poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0)),
+                   poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0))));
+  EXPECT_POISONED(
+      _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF)),
+                   poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF))));
+  EXPECT_POISONED(_mm_cmpgt_epi16(poisoned(_mm_set1_epi16(6), _mm_set1_epi16(0xF)),
+                               poisoned(_mm_set1_epi16(7), _mm_set1_epi16(0))));
 }
 #endif
 
@@ -1571,6 +2365,83 @@
   EXPECT_POISONED((unsigned)S->y);
 }
 
+TEST(MemorySanitizer, UnalignedLoad) {
+  char x[32];
+  memset(x + 8, 0, 16);
+  EXPECT_POISONED(__sanitizer_unaligned_load16(x+6));
+  EXPECT_POISONED(__sanitizer_unaligned_load16(x+7));
+  EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x+8));
+  EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x+9));
+  EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x+22));
+  EXPECT_POISONED(__sanitizer_unaligned_load16(x+23));
+  EXPECT_POISONED(__sanitizer_unaligned_load16(x+24));
+
+  EXPECT_POISONED(__sanitizer_unaligned_load32(x+4));
+  EXPECT_POISONED(__sanitizer_unaligned_load32(x+7));
+  EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x+8));
+  EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x+9));
+  EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x+20));
+  EXPECT_POISONED(__sanitizer_unaligned_load32(x+21));
+  EXPECT_POISONED(__sanitizer_unaligned_load32(x+24));
+
+  EXPECT_POISONED(__sanitizer_unaligned_load64(x));
+  EXPECT_POISONED(__sanitizer_unaligned_load64(x+1));
+  EXPECT_POISONED(__sanitizer_unaligned_load64(x+7));
+  EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x+8));
+  EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x+9));
+  EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x+16));
+  EXPECT_POISONED(__sanitizer_unaligned_load64(x+17));
+  EXPECT_POISONED(__sanitizer_unaligned_load64(x+21));
+  EXPECT_POISONED(__sanitizer_unaligned_load64(x+24));
+}
+
+TEST(MemorySanitizer, UnalignedStore16) {
+  char x[5];
+  U2 y = 0;
+  __msan_poison(&y, 1);
+  __sanitizer_unaligned_store16(x + 1, y);
+  EXPECT_POISONED(x[0]);
+  EXPECT_POISONED(x[1]);
+  EXPECT_NOT_POISONED(x[2]);
+  EXPECT_POISONED(x[3]);
+  EXPECT_POISONED(x[4]);
+}
+
+TEST(MemorySanitizer, UnalignedStore32) {
+  char x[8];
+  U4 y4 = 0;
+  __msan_poison(&y4, 2);
+  __sanitizer_unaligned_store32(x+3, y4);
+  EXPECT_POISONED(x[0]);
+  EXPECT_POISONED(x[1]);
+  EXPECT_POISONED(x[2]);
+  EXPECT_POISONED(x[3]);
+  EXPECT_POISONED(x[4]);
+  EXPECT_NOT_POISONED(x[5]);
+  EXPECT_NOT_POISONED(x[6]);
+  EXPECT_POISONED(x[7]);
+}
+
+TEST(MemorySanitizer, UnalignedStore64) {
+  char x[16];
+  U8 y = 0;
+  __msan_poison(&y, 3);
+  __msan_poison(((char *)&y) + sizeof(y) - 2, 1);
+  __sanitizer_unaligned_store64(x+3, y);
+  EXPECT_POISONED(x[0]);
+  EXPECT_POISONED(x[1]);
+  EXPECT_POISONED(x[2]);
+  EXPECT_POISONED(x[3]);
+  EXPECT_POISONED(x[4]);
+  EXPECT_POISONED(x[5]);
+  EXPECT_NOT_POISONED(x[6]);
+  EXPECT_NOT_POISONED(x[7]);
+  EXPECT_NOT_POISONED(x[8]);
+  EXPECT_POISONED(x[9]);
+  EXPECT_NOT_POISONED(x[10]);
+  EXPECT_POISONED(x[11]);
+}
+
 TEST(MemorySanitizerDr, StoreInDSOTest) {
   if (!__msan_has_dynamic_component()) return;
   char* s = new char[10];
@@ -1766,6 +2637,7 @@
   T *x = new T[N];
   T *y = new T[N];
   T *z = new T[N];
+  T *q = new T[N];
   __msan_poison(x, N * sizeof(T));
   __msan_set_origin(x, N * sizeof(T), ox);
   __msan_set_origin(y, N * sizeof(T), 777777);
@@ -1776,6 +2648,12 @@
   EXPECT_POISONED_O(y[N/2], ox);
   EXPECT_POISONED_O(y[N-1], ox);
   EXPECT_NOT_POISONED(x);
+  void *res = mempcpy(q, x, N * sizeof(T));
+  ASSERT_EQ(q + N, res);
+  EXPECT_POISONED_O(q[0], ox);
+  EXPECT_POISONED_O(q[N/2], ox);
+  EXPECT_POISONED_O(q[N-1], ox);
+  EXPECT_NOT_POISONED(x);
   memmove(z, x, N * sizeof(T));
   EXPECT_POISONED_O(z[0], ox);
   EXPECT_POISONED_O(z[N/2], ox);
@@ -1922,8 +2800,38 @@
   RecursiveMalloc(22);
 }
 
-int main(int argc, char **argv) {
-  testing::InitGoogleTest(&argc, argv);
-  int res = RUN_ALL_TESTS();
-  return res;
+TEST(MemorySanitizerAllocator, get_estimated_allocated_size) {
+  size_t sizes[] = {0, 20, 5000, 1<<20};
+  for (size_t i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i) {
+    size_t alloc_size = __msan_get_estimated_allocated_size(sizes[i]);
+    EXPECT_EQ(alloc_size, sizes[i]);
+  }
+}
+
+TEST(MemorySanitizerAllocator, get_allocated_size_and_ownership) {
+  char *array = reinterpret_cast<char*>(malloc(100));
+  int *int_ptr = new int;
+
+  EXPECT_TRUE(__msan_get_ownership(array));
+  EXPECT_EQ(100, __msan_get_allocated_size(array));
+
+  EXPECT_TRUE(__msan_get_ownership(int_ptr));
+  EXPECT_EQ(sizeof(*int_ptr), __msan_get_allocated_size(int_ptr));
+
+  void *wild_addr = reinterpret_cast<void*>(0x1);
+  EXPECT_FALSE(__msan_get_ownership(wild_addr));
+  EXPECT_EQ(0, __msan_get_allocated_size(wild_addr));
+
+  EXPECT_FALSE(__msan_get_ownership(array + 50));
+  EXPECT_EQ(0, __msan_get_allocated_size(array + 50));
+
+  // NULL is a valid argument for GetAllocatedSize but is not owned.                                                  
+  EXPECT_FALSE(__msan_get_ownership(NULL));
+  EXPECT_EQ(0, __msan_get_allocated_size(NULL));
+ 
+  free(array);
+  EXPECT_FALSE(__msan_get_ownership(array));
+  EXPECT_EQ(0, __msan_get_allocated_size(array));
+
+  delete int_ptr;
 }
diff --git a/lib/msan/tests/msan_test_config.h b/lib/msan/tests/msan_test_config.h
new file mode 100644
index 0000000..5404c43
--- /dev/null
+++ b/lib/msan/tests/msan_test_config.h
@@ -0,0 +1,20 @@
+//===-- msan_test_config.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 MemorySanitizer.
+//
+// MemorySanitizer unit tests.
+//===----------------------------------------------------------------------===//
+
+#ifndef MSAN_TEST_CONFIG_H
+#define MSAN_TEST_CONFIG_H
+
+#include "gtest/gtest.h"
+
+#endif // MSAN_TEST_CONFIG_H
diff --git a/lib/msan/tests/msan_test_main.cc b/lib/msan/tests/msan_test_main.cc
new file mode 100644
index 0000000..c8c5fef
--- /dev/null
+++ b/lib/msan/tests/msan_test_main.cc
@@ -0,0 +1,21 @@
+//===-- msan_test_main.cc -------------------------------------------------===//
+//
+//                     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 MemorySanitizer.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MSAN_EXTERNAL_TEST_CONFIG
+#include "msan_test_config.h"
+#endif // MSAN_EXTERNAL_TEST_CONFIG
+
+int main(int argc, char **argv) {
+  testing::GTEST_FLAG(death_test_style) = "threadsafe";
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/lib/msandr/msandr.cc b/lib/msandr/msandr.cc
index d4c07a3..27b1c94 100644
--- a/lib/msandr/msandr.cc
+++ b/lib/msandr/msandr.cc
@@ -45,8 +45,6 @@
 #include <vector>
 #include <string.h>
 
-using std::string;
-
 #define TESTALL(mask, var) (((mask) & (var)) == (mask))
 #define TESTANY(mask, var) (((mask) & (var)) != 0)
 
@@ -74,13 +72,13 @@
   app_pc start_;
   app_pc end_;
   // Full path to the module.
-  string path_;
+  std::string path_;
   module_handle_t handle_;
   bool should_instrument_;
   bool executed_;
 };
 
-string g_app_path;
+std::string g_app_path;
 
 int msan_retval_tls_offset;
 int msan_param_tls_offset;
@@ -399,7 +397,7 @@
   if (VERBOSITY > 1)
     dr_printf("============================================================\n");
   if (VERBOSITY > 0) {
-    string mod_path = (mod_data ? mod_data->path_ : "<no module, JITed?>");
+    std::string mod_path = (mod_data ? mod_data->path_ : "<no module, JITed?>");
     if (mod_data && !mod_data->executed_) {
       mod_data->executed_ = true; // Nevermind this race.
       dr_printf("Executing from new module: %s\n", mod_path.c_str());
@@ -666,7 +664,7 @@
   drmgr_init();
   drutil_init();
 
-  string app_name = dr_get_application_name();
+  std::string app_name = dr_get_application_name();
   // This blacklist will still run these apps through DR's code cache.  On the
   // other hand, we are able to follow children of these apps.
   // FIXME: Once DR has detach, we could just detach here.  Alternatively,
diff --git a/lib/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt
new file mode 100644
index 0000000..bb4fd9e
--- /dev/null
+++ b/lib/profile/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(PROFILE_SOURCES
+  GCDAProfiling.c)
+
+filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386)
+
+if(APPLE)
+  add_compiler_rt_osx_static_runtime(clang_rt.profile_osx
+    ARCH ${PROFILE_SUPPORTED_ARCH}
+    SOURCES ${PROFILE_SOURCES})
+else()
+  foreach(arch ${PROFILE_SUPPORTED_ARCH})
+    add_compiler_rt_static_runtime(clang_rt.profile-${arch}
+      ${arch}
+      SOURCES ${PROFILE_SOURCES})
+  endforeach()
+endif()
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c
index ccaf01b..ea62e79 100644
--- a/lib/profile/GCDAProfiling.c
+++ b/lib/profile/GCDAProfiling.c
@@ -20,10 +20,13 @@
 |*
 \*===----------------------------------------------------------------------===*/
 
+#include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
 #include <sys/types.h>
 #ifdef _WIN32
 #include <direct.h>
@@ -43,11 +46,40 @@
  */
 
 /*
+ * The current file name we're outputting. Used primarily for error logging.
+ */
+static char *filename = NULL;
+
+/*
  * The current file we're outputting.
  */ 
 static FILE *output_file = NULL;
 
 /*
+ * Buffer that we write things into.
+ */
+#define WRITE_BUFFER_SIZE (128 * 1024)
+static char *write_buffer = NULL;
+static uint64_t cur_buffer_size = 0;
+static uint64_t cur_pos = 0;
+static uint64_t file_size = 0;
+static int new_file = 0;
+static int fd = -1;
+
+/*
+ * A list of functions to write out the data.
+ */
+typedef void (*writeout_fn)();
+
+struct writeout_fn_node {
+  writeout_fn fn;
+  struct writeout_fn_node *next;
+};
+
+static struct writeout_fn_node *writeout_fn_head = NULL;
+static struct writeout_fn_node *writeout_fn_tail = NULL;
+
+/*
  *  A list of flush functions that our __gcov_flush() function should call.
  */
 typedef void (*flush_fn)();
@@ -57,18 +89,31 @@
   struct flush_fn_node *next;
 };
 
-struct flush_fn_node *flush_fn_head = NULL;
-struct flush_fn_node *flush_fn_tail = NULL;
+static struct flush_fn_node *flush_fn_head = NULL;
+static struct flush_fn_node *flush_fn_tail = NULL;
 
-static void write_int32(uint32_t i) {
-  fwrite(&i, 4, 1, output_file);
+static void resize_write_buffer(uint64_t size) {
+  if (!new_file) return;
+  size += cur_pos;
+  if (size <= cur_buffer_size) return;
+  size = (size - 1) / WRITE_BUFFER_SIZE + 1;
+  size *= WRITE_BUFFER_SIZE;
+  write_buffer = realloc(write_buffer, size);
+  cur_buffer_size = size;
 }
 
-static void write_int64(uint64_t i) {
-  uint32_t lo = i >>  0;
-  uint32_t hi = i >> 32;
-  write_int32(lo);
-  write_int32(hi);
+static void write_bytes(const char *s, size_t len) {
+  resize_write_buffer(len);
+  memcpy(&write_buffer[cur_pos], s, len);
+  cur_pos += len;
+}
+
+static void write_32bit_value(uint32_t i) {
+  write_bytes((char*)&i, 4);
+}
+
+static void write_64bit_value(uint64_t i) {
+  write_bytes((char*)&i, 8);
 }
 
 static uint32_t length_of_string(const char *s) {
@@ -77,27 +122,31 @@
 
 static void write_string(const char *s) {
   uint32_t len = length_of_string(s);
-  write_int32(len);
-  fwrite(s, strlen(s), 1, output_file);
-  fwrite("\0\0\0\0", 4 - (strlen(s) % 4), 1, output_file);
+  write_32bit_value(len);
+  write_bytes(s, strlen(s));
+  write_bytes("\0\0\0\0", 4 - (strlen(s) % 4));
 }
 
-static uint32_t read_int32() {
-  uint32_t tmp;
+static uint32_t read_32bit_value() {
+  uint32_t val;
 
-  if (fread(&tmp, 1, 4, output_file) != 4)
+  if (new_file)
     return (uint32_t)-1;
 
-  return tmp;
+  val = *(uint32_t*)&write_buffer[cur_pos];
+  cur_pos += 4;
+  return val;
 }
 
-static uint64_t read_int64() {
-  uint64_t tmp;
+static uint64_t read_64bit_value() {
+  uint64_t val;
 
-  if (fread(&tmp, 1, 8, output_file) != 8)
+  if (new_file)
     return (uint64_t)-1;
 
-  return tmp;
+  val = *(uint64_t*)&write_buffer[cur_pos];
+  cur_pos += 8;
+  return val;
 }
 
 static char *mangle_filename(const char *orig_filename) {
@@ -107,13 +156,13 @@
   int level = 0;
   const char *fname = orig_filename, *ptr = NULL;
   const char *prefix = getenv("GCOV_PREFIX");
-  const char *tmp = getenv("GCOV_PREFIX_STRIP");
+  const char *prefix_strip_str = getenv("GCOV_PREFIX_STRIP");
 
   if (!prefix)
     return strdup(orig_filename);
 
-  if (tmp) {
-    prefix_strip = atoi(tmp);
+  if (prefix_strip_str) {
+    prefix_strip = atoi(prefix_strip_str);
 
     /* Negative GCOV_PREFIX_STRIP values are ignored */
     if (prefix_strip < 0)
@@ -153,6 +202,36 @@
   }
 }
 
+static int map_file() {
+  fseek(output_file, 0L, SEEK_END);
+  file_size = ftell(output_file);
+
+  write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE,
+                      MAP_FILE | MAP_SHARED, fd, 0);
+  if (write_buffer == (void *)-1) {
+    int errnum = errno;
+    fprintf(stderr, "profiling: %s: cannot map: %s\n", filename,
+            strerror(errnum));
+    return -1;
+  }
+  return 0;
+}
+
+static void unmap_file() {
+  if (msync(write_buffer, file_size, MS_SYNC) == -1) {
+    int errnum = errno;
+    fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename,
+            strerror(errnum));
+  }
+
+  /* We explicitly ignore errors from unmapping because at this point the data
+   * is written and we don't care.
+   */
+  (void)munmap(write_buffer, file_size);
+  write_buffer = NULL;
+  file_size = 0;
+}
+
 /*
  * --- LLVM line counter API ---
  */
@@ -162,32 +241,57 @@
  * started at a time.
  */
 void llvm_gcda_start_file(const char *orig_filename, const char version[4]) {
-  char *filename = mangle_filename(orig_filename);
+  const char *mode = "r+b";
+  filename = mangle_filename(orig_filename);
 
   /* Try just opening the file. */
-  output_file = fopen(filename, "r+b");
+  new_file = 0;
+  fd = open(filename, O_RDWR);
 
-  if (!output_file) {
+  if (fd == -1) {
     /* Try opening the file, creating it if necessary. */
-    output_file = fopen(filename, "w+b");
-    if (!output_file) {
+    new_file = 1;
+    mode = "w+b";
+    fd = open(filename, O_RDWR | O_CREAT, 0644);
+    if (fd == -1) {
       /* Try creating the directories first then opening the file. */
       recursive_mkdir(filename);
-      output_file = fopen(filename, "w+b");
-      if (!output_file) {
+      fd = open(filename, O_RDWR | O_CREAT, 0644);
+      if (fd == -1) {
         /* Bah! It's hopeless. */
-        fprintf(stderr, "profiling:%s: cannot open\n", filename);
-        free(filename);
+        int errnum = errno;
+        fprintf(stderr, "profiling: %s: cannot open: %s\n", filename,
+                strerror(errnum));
         return;
       }
     }
   }
 
+  output_file = fdopen(fd, mode);
+
+  /* Initialize the write buffer. */
+  write_buffer = NULL;
+  cur_buffer_size = 0;
+  cur_pos = 0;
+
+  if (new_file) {
+    resize_write_buffer(WRITE_BUFFER_SIZE);
+    memset(write_buffer, 0, WRITE_BUFFER_SIZE);
+  } else {
+    if (map_file() == -1) {
+      /* mmap failed, try to recover by clobbering */
+      new_file = 1;
+      write_buffer = NULL;
+      cur_buffer_size = 0;
+      resize_write_buffer(WRITE_BUFFER_SIZE);
+      memset(write_buffer, 0, WRITE_BUFFER_SIZE);
+    }
+  }
+
   /* gcda file, version, stamp LLVM. */
-  fwrite("adcg", 4, 1, output_file);
-  fwrite(version, 4, 1, output_file);
-  fwrite("MVLL", 4, 1, output_file);
-  free(filename);
+  write_bytes("adcg", 4);
+  write_bytes(version, 4);
+  write_bytes("MVLL", 4);
 
 #ifdef DEBUG_GCDAPROFILING
   fprintf(stderr, "llvmgcda: [%s]\n", orig_filename);
@@ -222,6 +326,7 @@
 void llvm_gcda_emit_function(uint32_t ident, const char *function_name,
                              uint8_t use_extra_checksum) {
   uint32_t len = 2;
+
   if (use_extra_checksum)
     len++;
 #ifdef DEBUG_GCDAPROFILING
@@ -231,14 +336,14 @@
   if (!output_file) return;
 
   /* function tag */
-  fwrite("\0\0\0\1", 4, 1, output_file);
+  write_bytes("\0\0\0\1", 4);
   if (function_name)
     len += 1 + length_of_string(function_name);
-  write_int32(len);
-  write_int32(ident);
-  write_int32(0);
+  write_32bit_value(len);
+  write_32bit_value(ident);
+  write_32bit_value(0);
   if (use_extra_checksum)
-    write_int32(0);
+    write_32bit_value(0);
   if (function_name)
     write_string(function_name);
 }
@@ -247,42 +352,39 @@
   uint32_t i;
   uint64_t *old_ctrs = NULL;
   uint32_t val = 0;
-  long pos = 0;
+  uint64_t save_cur_pos = cur_pos;
 
   if (!output_file) return;
 
-  pos = ftell(output_file);
-  val = read_int32();
+  val = read_32bit_value();
 
   if (val != (uint32_t)-1) {
     /* There are counters present in the file. Merge them. */
-    uint32_t j;
-
     if (val != 0x01a10000) {
-      fprintf(stderr, "profiling: invalid magic number (0x%08x)\n", val);
+      fprintf(stderr, "profiling:invalid magic number (0x%08x)\n", val);
       return;
     }
 
-    val = read_int32();
+    val = read_32bit_value();
     if (val == (uint32_t)-1 || val / 2 != num_counters) {
-      fprintf(stderr, "profiling: invalid number of counters (%d)\n", val);
+      fprintf(stderr, "profiling:invalid number of counters (%d)\n", val);
       return;
     }
 
     old_ctrs = malloc(sizeof(uint64_t) * num_counters);
-
-    for (j = 0; j < num_counters; ++j)
-      old_ctrs[j] = read_int64();
+    for (i = 0; i < num_counters; ++i)
+      old_ctrs[i] = read_64bit_value();
   }
 
-  /* Reset for writing. */
-  fseek(output_file, pos, SEEK_SET);
+  cur_pos = save_cur_pos;
 
   /* Counter #1 (arcs) tag */
-  fwrite("\0\0\xa1\1", 4, 1, output_file);
-  write_int32(num_counters * 2);
-  for (i = 0; i < num_counters; ++i)
-    write_int64(counters[i] + (old_ctrs ? old_ctrs[i] : 0));
+  write_bytes("\0\0\xa1\1", 4);
+  write_32bit_value(num_counters * 2);
+  for (i = 0; i < num_counters; ++i) {
+    counters[i] += (old_ctrs ? old_ctrs[i] : 0);
+    write_64bit_value(counters[i]);
+  }
 
   free(old_ctrs);
 
@@ -295,16 +397,59 @@
 
 void llvm_gcda_end_file() {
   /* Write out EOF record. */
-  if (!output_file) return;
-  fwrite("\0\0\0\0\0\0\0\0", 8, 1, output_file);
-  fclose(output_file);
-  output_file = NULL;
+  if (output_file) {
+    write_bytes("\0\0\0\0\0\0\0\0", 8);
+
+    if (new_file) {
+      fwrite(write_buffer, cur_pos, 1, output_file);
+      free(write_buffer);
+    } else {
+      unmap_file();
+    }
+
+    fclose(output_file);
+    output_file = NULL;
+    write_buffer = NULL;
+  }
+  free(filename);
 
 #ifdef DEBUG_GCDAPROFILING
   fprintf(stderr, "llvmgcda: -----\n");
 #endif
 }
 
+void llvm_register_writeout_function(writeout_fn fn) {
+  struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node));
+  new_node->fn = fn;
+  new_node->next = NULL;
+
+  if (!writeout_fn_head) {
+    writeout_fn_head = writeout_fn_tail = new_node;
+  } else {
+    writeout_fn_tail->next = new_node;
+    writeout_fn_tail = new_node;
+  }
+}
+
+void llvm_writeout_files() {
+  struct writeout_fn_node *curr = writeout_fn_head;
+
+  while (curr) {
+    curr->fn();
+    curr = curr->next;
+  }
+}
+
+void llvm_delete_writeout_function_list() {
+  while (writeout_fn_head) {
+    struct writeout_fn_node *node = writeout_fn_head;
+    writeout_fn_head = writeout_fn_head->next;
+    free(node);
+  }
+  
+  writeout_fn_head = writeout_fn_tail = NULL;
+}
+
 void llvm_register_flush_function(flush_fn fn) {
   struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node));
   new_node->fn = fn;
@@ -336,3 +481,22 @@
 
   flush_fn_head = flush_fn_tail = NULL;
 }
+
+void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) {
+  static int atexit_ran = 0;
+
+  if (wfn)
+    llvm_register_writeout_function(wfn);
+
+  if (ffn)
+    llvm_register_flush_function(ffn);
+
+  if (atexit_ran == 0) {
+    atexit_ran = 1;
+
+    /* Make sure we write out the data and delete the data structures. */
+    atexit(llvm_delete_flush_function_list);
+    atexit(llvm_delete_writeout_function_list);
+    atexit(llvm_writeout_files);
+  }
+}
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index e89e207..8141ae6 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -13,27 +13,37 @@
   sanitizer_printf.cc
   sanitizer_stackdepot.cc
   sanitizer_stacktrace.cc
-  sanitizer_stoptheworld_linux.cc
-  sanitizer_symbolizer.cc
+  sanitizer_suppressions.cc
   sanitizer_symbolizer_itanium.cc
   sanitizer_symbolizer_linux.cc
   sanitizer_symbolizer_mac.cc
   sanitizer_symbolizer_win.cc
   sanitizer_thread_registry.cc
-  sanitizer_win.cc
-  )
+  sanitizer_win.cc)
+
+set(SANITIZER_LIBCDEP_SOURCES
+  sanitizer_common_libcdep.cc
+  sanitizer_linux_libcdep.cc
+  sanitizer_posix_libcdep.cc
+  sanitizer_stoptheworld_linux_libcdep.cc
+  sanitizer_symbolizer_libcdep.cc
+  sanitizer_symbolizer_linux_libcdep.cc
+  sanitizer_symbolizer_posix_libcdep.cc)
 
 # Explicitly list all sanitizer_common headers. Not all of these are
 # included in sanitizer_common source files, but we need to depend on
 # headers when building our custom unit tests.
 set(SANITIZER_HEADERS
   sanitizer_allocator.h
+  sanitizer_allocator_internal.h
   sanitizer_atomic_clang.h
   sanitizer_atomic_msvc.h
   sanitizer_atomic.h
   sanitizer_common.h
   sanitizer_common_interceptors.inc
+  sanitizer_common_interceptors_ioctl.inc
   sanitizer_common_interceptors_scanf.inc
+  sanitizer_common_syscalls.inc
   sanitizer_flags.h
   sanitizer_internal_defs.h
   sanitizer_lfstack.h
@@ -49,8 +59,7 @@
   sanitizer_stackdepot.h
   sanitizer_stacktrace.h
   sanitizer_symbolizer.h
-  sanitizer_thread_registry.h
-  )
+  sanitizer_thread_registry.h)
 
 set(SANITIZER_CFLAGS
   ${SANITIZER_COMMON_CFLAGS}
@@ -61,11 +70,12 @@
   # Build universal binary on APPLE.
   add_compiler_rt_osx_object_library(RTSanitizerCommon
     ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH}
-    SOURCES ${SANITIZER_SOURCES}
+    SOURCES ${SANITIZER_SOURCES} ${SANITIZER_LIBCDEP_SOURCES}
     CFLAGS ${SANITIZER_CFLAGS})
   list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.osx)
 elseif(ANDROID)
-  add_library(RTSanitizerCommon.arm.android OBJECT ${SANITIZER_SOURCES})
+  add_library(RTSanitizerCommon.arm.android OBJECT
+    ${SANITIZER_SOURCES} ${SANITIZER_LIBCDEP_SOURCES})
   set_target_compile_flags(RTSanitizerCommon.arm.android
     ${SANITIZER_CFLAGS})
   list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.arm.android)
@@ -74,6 +84,12 @@
   foreach(arch ${SANITIZER_COMMON_SUPPORTED_ARCH})
     add_compiler_rt_object_library(RTSanitizerCommon ${arch}
       SOURCES ${SANITIZER_SOURCES} CFLAGS ${SANITIZER_CFLAGS})
+    add_compiler_rt_object_library(RTSanitizerCommonLibc ${arch}
+      SOURCES ${SANITIZER_LIBCDEP_SOURCES} CFLAGS ${SANITIZER_CFLAGS})
+    add_compiler_rt_static_runtime(clang_rt.san-${arch} ${arch}
+      SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+      CFLAGS ${SANITIZER_CFLAGS})
     list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${arch})
   endforeach()
 endif()
diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc
index 88a3a1b..2975073 100644
--- a/lib/sanitizer_common/sanitizer_allocator.cc
+++ b/lib/sanitizer_common/sanitizer_allocator.cc
@@ -9,44 +9,102 @@
 //
 // This file is shared between AddressSanitizer and ThreadSanitizer
 // run-time libraries.
-// This allocator that is used inside run-times.
+// This allocator is used inside run-times.
 //===----------------------------------------------------------------------===//
+#include "sanitizer_allocator.h"
+#include "sanitizer_allocator_internal.h"
 #include "sanitizer_common.h"
 
-// FIXME: We should probably use more low-level allocator that would
-// mmap some pages and split them into chunks to fulfill requests.
-#if defined(__linux__) && !defined(__ANDROID__)
-extern "C" void *__libc_malloc(__sanitizer::uptr size);
-extern "C" void __libc_free(void *ptr);
-# define LIBC_MALLOC __libc_malloc
-# define LIBC_FREE __libc_free
-#else  // __linux__ && !ANDROID
-# include <stdlib.h>
-# define LIBC_MALLOC malloc
-# define LIBC_FREE free
-#endif  // __linux__ && !ANDROID
-
 namespace __sanitizer {
 
+// ThreadSanitizer for Go uses libc malloc/free.
+#if defined(SANITIZER_GO)
+# if SANITIZER_LINUX && !SANITIZER_ANDROID
+extern "C" void *__libc_malloc(uptr size);
+extern "C" void __libc_free(void *ptr);
+#  define LIBC_MALLOC __libc_malloc
+#  define LIBC_FREE __libc_free
+# else
+#  include <stdlib.h>
+#  define LIBC_MALLOC malloc
+#  define LIBC_FREE free
+# endif
+
+static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) {
+  (void)cache;
+  return LIBC_MALLOC(size);
+}
+
+static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
+  (void)cache;
+  LIBC_FREE(ptr);
+}
+
+InternalAllocator *internal_allocator() {
+  return 0;
+}
+
+#else  // SANITIZER_GO
+
+static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)];
+static atomic_uint8_t internal_allocator_initialized;
+static StaticSpinMutex internal_alloc_init_mu;
+
+static InternalAllocatorCache internal_allocator_cache;
+static StaticSpinMutex internal_allocator_cache_mu;
+
+InternalAllocator *internal_allocator() {
+  InternalAllocator *internal_allocator_instance =
+      reinterpret_cast<InternalAllocator *>(&internal_alloc_placeholder);
+  if (atomic_load(&internal_allocator_initialized, memory_order_acquire) == 0) {
+    SpinMutexLock l(&internal_alloc_init_mu);
+    if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) ==
+        0) {
+      internal_allocator_instance->Init();
+      atomic_store(&internal_allocator_initialized, 1, memory_order_release);
+    }
+  }
+  return internal_allocator_instance;
+}
+
+static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) {
+  if (cache == 0) {
+    SpinMutexLock l(&internal_allocator_cache_mu);
+    return internal_allocator()->Allocate(&internal_allocator_cache, size, 8,
+                                          false);
+  }
+  return internal_allocator()->Allocate(cache, size, 8, false);
+}
+
+static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
+  if (cache == 0) {
+    SpinMutexLock l(&internal_allocator_cache_mu);
+    return internal_allocator()->Deallocate(&internal_allocator_cache, ptr);
+  }
+  internal_allocator()->Deallocate(cache, ptr);
+}
+
+#endif  // SANITIZER_GO
+
 const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull;
 
-void *InternalAlloc(uptr size) {
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache) {
   if (size + sizeof(u64) < size)
     return 0;
-  void *p = LIBC_MALLOC(size + sizeof(u64));
+  void *p = RawInternalAlloc(size + sizeof(u64), cache);
   if (p == 0)
     return 0;
   ((u64*)p)[0] = kBlockMagic;
   return (char*)p + sizeof(u64);
 }
 
-void InternalFree(void *addr) {
+void InternalFree(void *addr, InternalAllocatorCache *cache) {
   if (addr == 0)
     return;
   addr = (char*)addr - sizeof(u64);
-  CHECK_EQ(((u64*)addr)[0], kBlockMagic);
+  CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);
   ((u64*)addr)[0] = 0;
-  LIBC_FREE(addr);
+  RawInternalFree(addr, cache);
 }
 
 // LowLevelAllocator
diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h
index 45c93da..ada1a0c 100644
--- a/lib/sanitizer_common/sanitizer_allocator.h
+++ b/lib/sanitizer_common/sanitizer_allocator.h
@@ -105,7 +105,7 @@
     void *batch[kMaxNumCached];
   };
 
-  static const uptr kMaxSize = 1 << kMaxSizeLog;
+  static const uptr kMaxSize = 1UL << kMaxSizeLog;
   static const uptr kNumClasses =
       kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1;
   COMPILER_CHECK(kNumClasses >= 32 && kNumClasses <= 256);
@@ -189,7 +189,7 @@
   }
 };
 
-typedef SizeClassMap<17, 256, 16> DefaultSizeClassMap;
+typedef SizeClassMap<17, 128, 16> DefaultSizeClassMap;
 typedef SizeClassMap<17, 64,  14> CompactSizeClassMap;
 template<class SizeClassAllocator> struct SizeClassAllocatorLocalCache;
 
@@ -279,6 +279,9 @@
   void OnUnmap(uptr p, uptr size) const { }
 };
 
+// Callback type for iterating over chunks.
+typedef void (*ForEachChunkCallback)(uptr chunk, void *arg);
+
 // SizeClassAllocator64 -- allocator for 64-bit address space.
 //
 // Space: a portion of address space of kSpaceSize bytes starting at
@@ -344,15 +347,15 @@
     region->n_freed += b->count;
   }
 
-  static bool PointerIsMine(void *p) {
+  static bool PointerIsMine(const void *p) {
     return reinterpret_cast<uptr>(p) / kSpaceSize == kSpaceBeg / kSpaceSize;
   }
 
-  static uptr GetSizeClass(void *p) {
+  static uptr GetSizeClass(const void *p) {
     return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClassesRounded;
   }
 
-  void *GetBlockBegin(void *p) {
+  void *GetBlockBegin(const void *p) {
     uptr class_id = GetSizeClass(p);
     uptr size = SizeClassMap::Size(class_id);
     if (!size) return 0;
@@ -374,7 +377,7 @@
 
   uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
 
-  void *GetMetaData(void *p) {
+  void *GetMetaData(const void *p) {
     uptr class_id = GetSizeClass(p);
     uptr size = SizeClassMap::Size(class_id);
     uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size);
@@ -433,20 +436,18 @@
     }
   }
 
-  // Iterate over existing chunks. May include chunks that are not currently
-  // allocated to the user (e.g. freed).
-  // The caller is expected to call ForceLock() before calling this function.
-  template<typename Callable>
-  void ForEachChunk(const Callable &callback) {
+  // Iterate over all existing chunks.
+  // The allocator must be locked when calling this function.
+  void ForEachChunk(ForEachChunkCallback callback, void *arg) {
     for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
       RegionInfo *region = GetRegionInfo(class_id);
       uptr chunk_size = SizeClassMap::Size(class_id);
       uptr region_beg = kSpaceBeg + class_id * kRegionSize;
-      for (uptr p = region_beg;
-           p < region_beg + region->allocated_user;
-           p += chunk_size) {
-        // Too slow: CHECK_EQ((void *)p, GetBlockBegin((void *)p));
-        callback((void *)p);
+      for (uptr chunk = region_beg;
+           chunk < region_beg + region->allocated_user;
+           chunk += chunk_size) {
+        // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
+        callback(chunk, arg);
       }
     }
   }
@@ -492,11 +493,12 @@
   }
 
   static uptr GetChunkIdx(uptr chunk, uptr size) {
-    u32 offset = chunk % kRegionSize;
+    uptr offset = chunk % kRegionSize;
     // Here we divide by a non-constant. This is costly.
-    // We require that kRegionSize is at least 2^32 so that offset is 32-bit.
-    // We save 2x by using 32-bit div, but may need to use a 256-way switch.
-    return offset / (u32)size;
+    // size always fits into 32-bits. If the offset fits too, use 32-bit div.
+    if (offset >> (SANITIZER_WORDSIZE / 2))
+      return offset / size;
+    return (u32)offset / (u32)size;
   }
 
   NOINLINE Batch* PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
@@ -534,7 +536,7 @@
       region->mapped_meta += map_size;
     }
     CHECK_LE(region->allocated_meta, region->mapped_meta);
-    if (region->allocated_user + region->allocated_meta > kRegionSize) {
+    if (region->mapped_user + region->mapped_meta > kRegionSize) {
       Printf("%s: Out of memory. Dying. ", SanitizerToolName);
       Printf("The process has exhausted %zuMB for size class %zu.\n",
           kRegionSize / 1024 / 1024, size);
@@ -560,6 +562,30 @@
   }
 };
 
+// Maps integers in rage [0, kSize) to u8 values.
+template<u64 kSize>
+class FlatByteMap {
+ public:
+  void TestOnlyInit() {
+    internal_memset(map_, 0, sizeof(map_));
+  }
+
+  void set(uptr idx, u8 val) {
+    CHECK_LT(idx, kSize);
+    CHECK_EQ(0U, map_[idx]);
+    map_[idx] = val;
+  }
+  u8 operator[] (uptr idx) {
+    CHECK_LT(idx, kSize);
+    // FIXME: CHECK may be too expensive here.
+    return map_[idx];
+  }
+ private:
+  u8 map_[kSize];
+};
+
+// FIXME: Also implement TwoLevelByteMap.
+
 // SizeClassAllocator32 -- allocator for 32-bit address space.
 // This allocator can theoretically be used on 64-bit arch, but there it is less
 // efficient than SizeClassAllocator64.
@@ -571,7 +597,7 @@
 //   a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize).
 // Since the regions are aligned by kRegionSize, there are exactly
 // kNumPossibleRegions possible regions in the address space and so we keep
-// an u8 array possible_regions[kNumPossibleRegions] to store the size classes.
+// a ByteMap possible_regions to store the size classes of each Region.
 // 0 size class means the region is not used by the allocator.
 //
 // One Region is used to allocate chunks of a single size class.
@@ -582,16 +608,19 @@
 // chache-line aligned.
 template <const uptr kSpaceBeg, const u64 kSpaceSize,
           const uptr kMetadataSize, class SizeClassMap,
+          const uptr kRegionSizeLog,
+          class ByteMap,
           class MapUnmapCallback = NoOpMapUnmapCallback>
 class SizeClassAllocator32 {
  public:
   typedef typename SizeClassMap::TransferBatch Batch;
   typedef SizeClassAllocator32<kSpaceBeg, kSpaceSize, kMetadataSize,
-      SizeClassMap, MapUnmapCallback> ThisT;
+      SizeClassMap, kRegionSizeLog, ByteMap, MapUnmapCallback> ThisT;
   typedef SizeClassAllocatorLocalCache<ThisT> AllocatorCache;
 
   void Init() {
-    state_ = reinterpret_cast<State *>(MapWithCallback(sizeof(State)));
+    possible_regions.TestOnlyInit();
+    internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
   }
 
   void *MapWithCallback(uptr size) {
@@ -611,7 +640,7 @@
       alignment <= SizeClassMap::kMaxSize;
   }
 
-  void *GetMetaData(void *p) {
+  void *GetMetaData(const void *p) {
     CHECK(PointerIsMine(p));
     uptr mem = reinterpret_cast<uptr>(p);
     uptr beg = ComputeRegionBeg(mem);
@@ -643,15 +672,15 @@
     sci->free_list.push_front(b);
   }
 
-  bool PointerIsMine(void *p) {
+  bool PointerIsMine(const void *p) {
     return GetSizeClass(p) != 0;
   }
 
-  uptr GetSizeClass(void *p) {
-    return state_->possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))];
+  uptr GetSizeClass(const void *p) {
+    return possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))];
   }
 
-  void *GetBlockBegin(void *p) {
+  void *GetBlockBegin(const void *p) {
     CHECK(PointerIsMine(p));
     uptr mem = reinterpret_cast<uptr>(p);
     uptr beg = ComputeRegionBeg(mem);
@@ -673,16 +702,15 @@
     // No need to lock here.
     uptr res = 0;
     for (uptr i = 0; i < kNumPossibleRegions; i++)
-      if (state_->possible_regions[i])
+      if (possible_regions[i])
         res += kRegionSize;
     return res;
   }
 
   void TestOnlyUnmap() {
     for (uptr i = 0; i < kNumPossibleRegions; i++)
-      if (state_->possible_regions[i])
+      if (possible_regions[i])
         UnmapWithCallback((i * kRegionSize), kRegionSize);
-    UnmapWithCallback(reinterpret_cast<uptr>(state_), sizeof(State));
   }
 
   // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
@@ -699,21 +727,19 @@
     }
   }
 
-  // Iterate over existing chunks. May include chunks that are not currently
-  // allocated to the user (e.g. freed).
-  // The caller is expected to call ForceLock() before calling this function.
-  template<typename Callable>
-  void ForEachChunk(const Callable &callback) {
+  // Iterate over all existing chunks.
+  // The allocator must be locked when calling this function.
+  void ForEachChunk(ForEachChunkCallback callback, void *arg) {
     for (uptr region = 0; region < kNumPossibleRegions; region++)
-      if (state_->possible_regions[region]) {
-        uptr chunk_size = SizeClassMap::Size(state_->possible_regions[region]);
+      if (possible_regions[region]) {
+        uptr chunk_size = SizeClassMap::Size(possible_regions[region]);
         uptr max_chunks_in_region = kRegionSize / (chunk_size + kMetadataSize);
         uptr region_beg = region * kRegionSize;
-        for (uptr p = region_beg;
-             p < region_beg + max_chunks_in_region * chunk_size;
-             p += chunk_size) {
-          // Too slow: CHECK_EQ((void *)p, GetBlockBegin((void *)p));
-          callback((void *)p);
+        for (uptr chunk = region_beg;
+             chunk < region_beg + max_chunks_in_region * chunk_size;
+             chunk += chunk_size) {
+          // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
+          callback(chunk, arg);
         }
       }
   }
@@ -725,7 +751,6 @@
   static const uptr kNumClasses = SizeClassMap::kNumClasses;
 
  private:
-  static const uptr kRegionSizeLog = SANITIZER_WORDSIZE == 64 ? 24 : 20;
   static const uptr kRegionSize = 1 << kRegionSizeLog;
   static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize;
 
@@ -753,14 +778,13 @@
     MapUnmapCallback().OnMap(res, kRegionSize);
     stat->Add(AllocatorStatMmapped, kRegionSize);
     CHECK_EQ(0U, (res & (kRegionSize - 1)));
-    CHECK_EQ(0U, state_->possible_regions[ComputeRegionId(res)]);
-    state_->possible_regions[ComputeRegionId(res)] = class_id;
+    possible_regions.set(ComputeRegionId(res), static_cast<u8>(class_id));
     return res;
   }
 
   SizeClassInfo *GetSizeClassInfo(uptr class_id) {
     CHECK_LT(class_id, kNumClasses);
-    return &state_->size_class_info_array[class_id];
+    return &size_class_info_array[class_id];
   }
 
   void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
@@ -791,11 +815,8 @@
     }
   }
 
-  struct State {
-    u8 possible_regions[kNumPossibleRegions];
-    SizeClassInfo size_class_info_array[kNumClasses];
-  };
-  State *state_;
+  ByteMap possible_regions;
+  SizeClassInfo size_class_info_array[kNumClasses];
 };
 
 // Objects of this type should be used as local caches for SizeClassAllocator64
@@ -939,6 +960,7 @@
     {
       SpinMutexLock l(&mutex_);
       uptr idx = n_chunks_++;
+      chunks_sorted_ = false;
       CHECK_LT(idx, kMaxNumChunks);
       h->chunk_idx = idx;
       chunks_[idx] = h;
@@ -962,6 +984,7 @@
       chunks_[idx] = chunks_[n_chunks_ - 1];
       chunks_[idx]->chunk_idx = idx;
       n_chunks_--;
+      chunks_sorted_ = false;
       stats.n_frees++;
       stats.currently_allocated -= h->map_size;
       stat->Add(AllocatorStatFreed, h->map_size);
@@ -982,7 +1005,7 @@
     return res;
   }
 
-  bool PointerIsMine(void *p) {
+  bool PointerIsMine(const void *p) {
     return GetBlockBegin(p) != 0;
   }
 
@@ -991,13 +1014,13 @@
   }
 
   // At least page_size_/2 metadata bytes is available.
-  void *GetMetaData(void *p) {
+  void *GetMetaData(const void *p) {
     // Too slow: CHECK_EQ(p, GetBlockBegin(p));
     CHECK(IsAligned(reinterpret_cast<uptr>(p), page_size_));
     return GetHeader(p) + 1;
   }
 
-  void *GetBlockBegin(void *ptr) {
+  void *GetBlockBegin(const void *ptr) {
     uptr p = reinterpret_cast<uptr>(ptr);
     SpinMutexLock l(&mutex_);
     uptr nearest_chunk = 0;
@@ -1014,7 +1037,49 @@
     CHECK_GE(nearest_chunk, h->map_beg);
     CHECK_LT(nearest_chunk, h->map_beg + h->map_size);
     CHECK_LE(nearest_chunk, p);
-    if (h->map_beg + h->map_size < p)
+    if (h->map_beg + h->map_size <= p)
+      return 0;
+    return GetUser(h);
+  }
+
+  // This function does the same as GetBlockBegin, but is much faster.
+  // Must be called with the allocator locked.
+  void *GetBlockBeginFastLocked(void *ptr) {
+    uptr p = reinterpret_cast<uptr>(ptr);
+    uptr n = n_chunks_;
+    if (!n) return 0;
+    if (!chunks_sorted_) {
+      // Do one-time sort. chunks_sorted_ is reset in Allocate/Deallocate.
+      SortArray(reinterpret_cast<uptr*>(chunks_), n);
+      for (uptr i = 0; i < n; i++)
+        chunks_[i]->chunk_idx = i;
+      chunks_sorted_ = true;
+      min_mmap_ = reinterpret_cast<uptr>(chunks_[0]);
+      max_mmap_ = reinterpret_cast<uptr>(chunks_[n - 1]) +
+          chunks_[n - 1]->map_size;
+    }
+    if (p < min_mmap_ || p >= max_mmap_)
+      return 0;
+    uptr beg = 0, end = n - 1;
+    // This loop is a log(n) lower_bound. It does not check for the exact match
+    // to avoid expensive cache-thrashing loads.
+    while (end - beg >= 2) {
+      uptr mid = (beg + end) / 2;  // Invariant: mid >= beg + 1
+      if (p < reinterpret_cast<uptr>(chunks_[mid]))
+        end = mid - 1;  // We are not interested in chunks_[mid].
+      else
+        beg = mid;  // chunks_[mid] may still be what we want.
+    }
+
+    if (beg < end) {
+      CHECK_EQ(beg + 1, end);
+      // There are 2 chunks left, choose one.
+      if (p >= reinterpret_cast<uptr>(chunks_[end]))
+        beg = end;
+    }
+
+    Header *h = chunks_[beg];
+    if (h->map_beg + h->map_size <= p || p < h->map_beg)
       return 0;
     return GetUser(h);
   }
@@ -1042,13 +1107,11 @@
     mutex_.Unlock();
   }
 
-  // Iterate over existing chunks. May include chunks that are not currently
-  // allocated to the user (e.g. freed).
-  // The caller is expected to call ForceLock() before calling this function.
-  template<typename Callable>
-  void ForEachChunk(const Callable &callback) {
+  // Iterate over all existing chunks.
+  // The allocator must be locked when calling this function.
+  void ForEachChunk(ForEachChunkCallback callback, void *arg) {
     for (uptr i = 0; i < n_chunks_; i++)
-      callback(GetUser(chunks_[i]));
+      callback(reinterpret_cast<uptr>(GetUser(chunks_[i])), arg);
   }
 
  private:
@@ -1061,13 +1124,15 @@
   };
 
   Header *GetHeader(uptr p) {
-    CHECK_EQ(p % page_size_, 0);
+    CHECK(IsAligned(p, page_size_));
     return reinterpret_cast<Header*>(p - page_size_);
   }
-  Header *GetHeader(void *p) { return GetHeader(reinterpret_cast<uptr>(p)); }
+  Header *GetHeader(const void *p) {
+    return GetHeader(reinterpret_cast<uptr>(p));
+  }
 
   void *GetUser(Header *h) {
-    CHECK_EQ((uptr)h % page_size_, 0);
+    CHECK(IsAligned((uptr)h, page_size_));
     return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + page_size_);
   }
 
@@ -1078,6 +1143,8 @@
   uptr page_size_;
   Header *chunks_[kMaxNumChunks];
   uptr n_chunks_;
+  uptr min_mmap_, max_mmap_;
+  bool chunks_sorted_;
   struct Stats {
     uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64];
   } stats;
@@ -1157,18 +1224,26 @@
     return primary_.PointerIsMine(p);
   }
 
-  void *GetMetaData(void *p) {
+  void *GetMetaData(const void *p) {
     if (primary_.PointerIsMine(p))
       return primary_.GetMetaData(p);
     return secondary_.GetMetaData(p);
   }
 
-  void *GetBlockBegin(void *p) {
+  void *GetBlockBegin(const void *p) {
     if (primary_.PointerIsMine(p))
       return primary_.GetBlockBegin(p);
     return secondary_.GetBlockBegin(p);
   }
 
+  // This function does the same as GetBlockBegin, but is much faster.
+  // Must be called with the allocator locked.
+  void *GetBlockBeginFastLocked(void *p) {
+    if (primary_.PointerIsMine(p))
+      return primary_.GetBlockBegin(p);
+    return secondary_.GetBlockBeginFastLocked(p);
+  }
+
   uptr GetActuallyAllocatedSize(void *p) {
     if (primary_.PointerIsMine(p))
       return primary_.GetActuallyAllocatedSize(p);
@@ -1214,13 +1289,11 @@
     primary_.ForceUnlock();
   }
 
-  // Iterate over existing chunks. May include chunks that are not currently
-  // allocated to the user (e.g. freed).
-  // The caller is expected to call ForceLock() before calling this function.
-  template<typename Callable>
-  void ForEachChunk(const Callable &callback) {
-    primary_.ForEachChunk(callback);
-    secondary_.ForEachChunk(callback);
+  // Iterate over all existing chunks.
+  // The allocator must be locked when calling this function.
+  void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+    primary_.ForEachChunk(callback, arg);
+    secondary_.ForEachChunk(callback, arg);
   }
 
  private:
diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h
new file mode 100644
index 0000000..5b24bfd
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_allocator_internal.h
@@ -0,0 +1,64 @@
+//===-- sanitizer_allocator_internal.h -------------------------- C++ -----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This allocator is used inside run-times.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ALLOCATOR_INTERNAL_H
+#define SANITIZER_ALLOCATOR_INTERNAL_H
+
+#include "sanitizer_allocator.h"
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+// FIXME: Check if we may use even more compact size class map for internal
+// purposes.
+typedef CompactSizeClassMap InternalSizeClassMap;
+
+static const uptr kInternalAllocatorSpace = 0;
+#if SANITIZER_WORDSIZE == 32
+static const u64 kInternalAllocatorSize = (1ULL << 32);
+static const uptr kInternalAllocatorRegionSizeLog = 20;
+#else
+static const u64 kInternalAllocatorSize = (1ULL << 47);
+static const uptr kInternalAllocatorRegionSizeLog = 24;
+#endif
+static const uptr kInternalAllocatorFlatByteMapSize =
+    kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+typedef SizeClassAllocator32<
+    kInternalAllocatorSpace, kInternalAllocatorSize, 16, InternalSizeClassMap,
+    kInternalAllocatorRegionSizeLog,
+    FlatByteMap<kInternalAllocatorFlatByteMapSize> > PrimaryInternalAllocator;
+
+typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
+    InternalAllocatorCache;
+
+// We don't want our internal allocator to do any map/unmap operations.
+struct CrashOnMapUnmap {
+  void OnMap(uptr p, uptr size) const {
+    RAW_CHECK_MSG(0, "Unexpected mmap in InternalAllocator!");
+  }
+  void OnUnmap(uptr p, uptr size) const {
+    RAW_CHECK_MSG(0, "Unexpected munmap in InternalAllocator!");
+  }
+};
+
+typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache,
+                          LargeMmapAllocator<CrashOnMapUnmap> >
+    InternalAllocator;
+
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache = 0);
+void InternalFree(void *p, InternalAllocatorCache *cache = 0);
+InternalAllocator *internal_allocator();
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_ALLOCATOR_INTERNAL_H
diff --git a/lib/sanitizer_common/sanitizer_atomic_clang.h b/lib/sanitizer_common/sanitizer_atomic_clang.h
index 7f73df3..30158b4 100644
--- a/lib/sanitizer_common/sanitizer_atomic_clang.h
+++ b/lib/sanitizer_common/sanitizer_atomic_clang.h
@@ -113,9 +113,9 @@
 
 template<typename T>
 INLINE bool atomic_compare_exchange_weak(volatile T *a,
-                                           typename T::Type *cmp,
-                                           typename T::Type xchg,
-                                           memory_order mo) {
+                                         typename T::Type *cmp,
+                                         typename T::Type xchg,
+                                         memory_order mo) {
   return atomic_compare_exchange_strong(a, cmp, xchg, mo);
 }
 
diff --git a/lib/sanitizer_common/sanitizer_atomic_msvc.h b/lib/sanitizer_common/sanitizer_atomic_msvc.h
index 58a6a20..dc22ef0 100644
--- a/lib/sanitizer_common/sanitizer_atomic_msvc.h
+++ b/lib/sanitizer_common/sanitizer_atomic_msvc.h
@@ -134,6 +134,27 @@
   return v;
 }
 
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a,
+                                           u8 *cmp,
+                                           u8 xchgv,
+                                           memory_order mo) {
+  (void)mo;
+  DCHECK(!((uptr)a % sizeof(*a)));
+  u8 cmpv = *cmp;
+  u8 prev;
+  __asm {
+    mov al, cmpv
+    mov ecx, a
+    mov dl, xchgv
+    lock cmpxchg [ecx], dl
+    mov prev, al
+  }
+  if (prev == cmpv)
+    return true;
+  *cmp = prev;
+  return false;
+}
+
 INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
                                            uptr *cmp,
                                            uptr xchg,
@@ -149,9 +170,9 @@
 
 template<typename T>
 INLINE bool atomic_compare_exchange_weak(volatile T *a,
-                                           typename T::Type *cmp,
-                                           typename T::Type xchg,
-                                           memory_order mo) {
+                                         typename T::Type *cmp,
+                                         typename T::Type xchg,
+                                         memory_order mo) {
   return atomic_compare_exchange_strong(a, cmp, xchg, mo);
 }
 
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 39e52e8..abbe5f9 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -31,11 +31,11 @@
 // By default, dump to stderr. If |log_to_file| is true and |report_fd_pid|
 // isn't equal to the current PID, try to obtain file descriptor by opening
 // file "report_path_prefix.<PID>".
-static fd_t report_fd = kStderrFd;
+fd_t report_fd = kStderrFd;
 static char report_path_prefix[4096];  // Set via __sanitizer_set_report_path.
 // PID of process that opened |report_fd|. If a fork() occurs, the PID of the
 // child thread will be different from |report_fd_pid|.
-static int report_fd_pid = 0;
+static uptr report_fd_pid = 0;
 
 static void (*DieCallback)(void);
 void SetDieCallback(void (*callback)(void)) {
@@ -64,13 +64,13 @@
   Die();
 }
 
-static void MaybeOpenReportFile() {
-  if (!log_to_file || (report_fd_pid == GetPid())) return;
+void MaybeOpenReportFile() {
+  if (!log_to_file || (report_fd_pid == internal_getpid())) return;
   InternalScopedBuffer<char> report_path_full(4096);
   internal_snprintf(report_path_full.data(), report_path_full.size(),
-                    "%s.%d", report_path_prefix, GetPid());
-  fd_t fd = OpenFile(report_path_full.data(), true);
-  if (fd == kInvalidFd) {
+                    "%s.%d", report_path_prefix, internal_getpid());
+  uptr openrv = OpenFile(report_path_full.data(), true);
+  if (internal_iserror(openrv)) {
     report_fd = kStderrFd;
     log_to_file = false;
     Report("ERROR: Can't open file: %s\n", report_path_full.data());
@@ -80,13 +80,8 @@
     // We're in the child. Close the parent's log.
     internal_close(report_fd);
   }
-  report_fd = fd;
-  report_fd_pid = GetPid();
-}
-
-bool PrintsToTty() {
-  MaybeOpenReportFile();
-  return internal_isatty(report_fd);
+  report_fd = openrv;
+  report_fd_pid = internal_getpid();
 }
 
 void RawWrite(const char *buffer) {
@@ -108,8 +103,9 @@
   *buff_size = 0;
   // The files we usually open are not seekable, so try different buffer sizes.
   for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
-    fd_t fd = OpenFile(file_name, /*write*/ false);
-    if (fd == kInvalidFd) return 0;
+    uptr openrv = OpenFile(file_name, /*write*/ false);
+    if (internal_iserror(openrv)) return 0;
+    fd_t fd = openrv;
     UnmapOrDie(*buff, *buff_size);
     *buff = (char*)MmapOrDie(size, __FUNCTION__);
     *buff_size = size;
@@ -131,45 +127,15 @@
   return read_len;
 }
 
-// We don't want to use std::sort to avoid including <algorithm>, as
-// we may end up with two implementation of std::sort - one in instrumented
-// code, and the other in runtime.
-// qsort() from stdlib won't work as it calls malloc(), which results
-// in deadlock in ASan allocator.
-// We re-implement in-place sorting w/o recursion as straightforward heapsort.
+typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
+
+template<class T>
+static inline bool CompareLess(const T &a, const T &b) {
+  return a < b;
+}
+
 void SortArray(uptr *array, uptr size) {
-  if (size < 2)
-    return;
-  // Stage 1: insert elements to the heap.
-  for (uptr i = 1; i < size; i++) {
-    uptr j, p;
-    for (j = i; j > 0; j = p) {
-      p = (j - 1) / 2;
-      if (array[j] > array[p])
-        Swap(array[j], array[p]);
-      else
-        break;
-    }
-  }
-  // Stage 2: swap largest element with the last one,
-  // and sink the new top.
-  for (uptr i = size - 1; i > 0; i--) {
-    Swap(array[0], array[i]);
-    uptr j, max_ind;
-    for (j = 0; j < i; j = max_ind) {
-      uptr left = 2 * j + 1;
-      uptr right = 2 * j + 2;
-      max_ind = j;
-      if (left < i && array[left] > array[max_ind])
-        max_ind = left;
-      if (right < i && array[right] > array[max_ind])
-        max_ind = right;
-      if (max_ind != j)
-        Swap(array[j], array[max_ind]);
-      else
-        break;
-    }
-  }
+  InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
 }
 
 // We want to map a chunk of address space aligned to 'alignment'.
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index bca65c1..4288a9a 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -18,6 +18,7 @@
 
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
+#include "sanitizer_mutex.h"
 
 namespace __sanitizer {
 struct StackTrace;
@@ -32,18 +33,22 @@
 const uptr kCacheLineSize = 64;
 #endif
 
+const uptr kMaxPathLength = 512;
+
 extern const char *SanitizerToolName;  // Can be changed by the tool.
 extern uptr SanitizerVerbosity;
 
 uptr GetPageSize();
 uptr GetPageSizeCached();
 uptr GetMmapGranularity();
+uptr GetMaxVirtualAddress();
 // Threads
-int GetPid();
 uptr GetTid();
 uptr GetThreadSelf();
 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                 uptr *stack_bottom);
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+                          uptr *tls_addr, uptr *tls_size);
 
 // Memory management
 void *MmapOrDie(uptr size, const char *mem_type);
@@ -57,10 +62,6 @@
 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
 void FlushUnneededShadowMemory(uptr addr, uptr size);
 
-// Internal allocator
-void *InternalAlloc(uptr size);
-void InternalFree(void *p);
-
 // InternalScopedBuffer can be used instead of large stack arrays to
 // keep frame size low.
 // FIXME: use InternalAlloc instead of MmapOrDie once
@@ -109,8 +110,12 @@
 void Printf(const char *format, ...);
 void Report(const char *format, ...);
 void SetPrintfAndReportCallback(void (*callback)(const char *));
+// Can be used to prevent mixing error reports from different sanitizers.
+extern StaticSpinMutex CommonSanitizerReportMutex;
+void MaybeOpenReportFile();
+extern fd_t report_fd;
 
-fd_t OpenFile(const char *filename, bool write);
+uptr OpenFile(const char *filename, bool write);
 // Opens the file 'file_name" and reads up to 'max_len' bytes.
 // The resulting buffer is mmaped and stored in '*buff'.
 // The size of the mmaped region is stored in '*buff_size',
@@ -127,6 +132,7 @@
 void DumpProcessMap();
 bool FileExists(const char *filename);
 const char *GetEnv(const char *name);
+bool SetEnv(const char *name, const char *value);
 const char *GetPwd();
 u32 GetUid();
 void ReExec();
@@ -140,6 +146,7 @@
 // Other
 void SleepForSeconds(int seconds);
 void SleepForMillis(int millis);
+u64 NanoTime();
 int Atexit(void (*function)(void));
 void SortArray(uptr *array, uptr size);
 
@@ -170,7 +177,7 @@
                         int line, const char *function);
 
 // Math
-#if defined(_WIN32) && !defined(__clang__)
+#if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__)
 extern "C" {
 unsigned char _BitScanForward(unsigned long *index, unsigned long mask);  // NOLINT
 unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);  // NOLINT
@@ -184,7 +191,7 @@
 INLINE uptr MostSignificantSetBitIndex(uptr x) {
   CHECK_NE(x, 0U);
   unsigned long up;  // NOLINT
-#if !defined(_WIN32) || defined(__clang__)
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
   up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x);
 #elif defined(_WIN64)
   _BitScanReverse64(&up, x);
@@ -223,7 +230,7 @@
 
 INLINE uptr Log2(uptr x) {
   CHECK(IsPowerOfTwo(x));
-#if !defined(_WIN32) || defined(__clang__)
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
   return __builtin_ctzl(x);
 #elif defined(_WIN64)
   unsigned long ret;  // NOLINT
@@ -268,21 +275,25 @@
 // small vectors.
 // WARNING: The current implementation supports only POD types.
 template<typename T>
-class InternalVector {
+class InternalMmapVector {
  public:
-  explicit InternalVector(uptr initial_capacity) {
+  explicit InternalMmapVector(uptr initial_capacity) {
     CHECK_GT(initial_capacity, 0);
     capacity_ = initial_capacity;
     size_ = 0;
-    data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalVector");
+    data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalMmapVector");
   }
-  ~InternalVector() {
+  ~InternalMmapVector() {
     UnmapOrDie(data_, capacity_ * sizeof(T));
   }
   T &operator[](uptr i) {
     CHECK_LT(i, size_);
     return data_[i];
   }
+  const T &operator[](uptr i) const {
+    CHECK_LT(i, size_);
+    return data_[i];
+  }
   void push_back(const T &element) {
     CHECK_LE(size_, capacity_);
     if (size_ == capacity_) {
@@ -299,16 +310,22 @@
     CHECK_GT(size_, 0);
     size_--;
   }
-  uptr size() {
+  uptr size() const {
     return size_;
   }
+  const T *data() const {
+    return data_;
+  }
+  uptr capacity() const {
+    return capacity_;
+  }
 
  private:
   void Resize(uptr new_capacity) {
     CHECK_GT(new_capacity, 0);
     CHECK_LE(size_, new_capacity);
     T *new_data = (T *)MmapOrDie(new_capacity * sizeof(T),
-                                 "InternalVector");
+                                 "InternalMmapVector");
     internal_memcpy(new_data, data_, size_ * sizeof(T));
     T *old_data = data_;
     data_ = new_data;
@@ -316,13 +333,51 @@
     capacity_ = new_capacity;
   }
   // Disallow evil constructors.
-  InternalVector(const InternalVector&);
-  void operator=(const InternalVector&);
+  InternalMmapVector(const InternalMmapVector&);
+  void operator=(const InternalMmapVector&);
 
   T *data_;
   uptr capacity_;
   uptr size_;
 };
+
+// HeapSort for arrays and InternalMmapVector.
+template<class Container, class Compare>
+void InternalSort(Container *v, uptr size, Compare comp) {
+  if (size < 2)
+    return;
+  // Stage 1: insert elements to the heap.
+  for (uptr i = 1; i < size; i++) {
+    uptr j, p;
+    for (j = i; j > 0; j = p) {
+      p = (j - 1) / 2;
+      if (comp((*v)[p], (*v)[j]))
+        Swap((*v)[j], (*v)[p]);
+      else
+        break;
+    }
+  }
+  // Stage 2: swap largest element with the last one,
+  // and sink the new top.
+  for (uptr i = size - 1; i > 0; i--) {
+    Swap((*v)[0], (*v)[i]);
+    uptr j, max_ind;
+    for (j = 0; j < i; j = max_ind) {
+      uptr left = 2 * j + 1;
+      uptr right = 2 * j + 2;
+      max_ind = j;
+      if (left < i && comp((*v)[max_ind], (*v)[left]))
+        max_ind = left;
+      if (right < i && comp((*v)[max_ind], (*v)[right]))
+        max_ind = right;
+      if (max_ind != j)
+        Swap((*v)[j], (*v)[max_ind]);
+      else
+        break;
+    }
+  }
+}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_COMMON_H
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 3cb1d4a..bf99141 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -24,10 +24,98 @@
 
 #include <stdarg.h>
 
-#ifdef _WIN32
+#if SANITIZER_WINDOWS
 #define va_copy(dst, src) ((dst) = (src))
 #endif // _WIN32
 
+#if SANITIZER_INTERCEPT_STRCMP
+static inline int CharCmpX(unsigned char c1, unsigned char c2) {
+  return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
+}
+
+INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2);
+  unsigned char c1, c2;
+  uptr i;
+  for (i = 0; ; i++) {
+    c1 = (unsigned char)s1[i];
+    c2 = (unsigned char)s2[i];
+    if (c1 != c2 || c1 == '\0') break;
+  }
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
+  return CharCmpX(c1, c2);
+}
+
+INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size);
+  unsigned char c1 = 0, c2 = 0;
+  uptr i;
+  for (i = 0; i < size; i++) {
+    c1 = (unsigned char)s1[i];
+    c2 = (unsigned char)s2[i];
+    if (c1 != c2 || c1 == '\0') break;
+  }
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size));
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size));
+  return CharCmpX(c1, c2);
+}
+
+#define INIT_STRCMP INTERCEPT_FUNCTION(strcmp)
+#define INIT_STRNCMP INTERCEPT_FUNCTION(strncmp)
+#else
+#define INIT_STRCMP
+#define INIT_STRNCMP
+#endif
+
+#if SANITIZER_INTERCEPT_STRCASECMP
+static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
+  int c1_low = ToLower(c1);
+  int c2_low = ToLower(c2);
+  return c1_low - c2_low;
+}
+
+INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2);
+  unsigned char c1 = 0, c2 = 0;
+  uptr i;
+  for (i = 0; ; i++) {
+    c1 = (unsigned char)s1[i];
+    c2 = (unsigned char)s2[i];
+    if (CharCaseCmp(c1, c2) != 0 || c1 == '\0')
+      break;
+  }
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
+  return CharCaseCmp(c1, c2);
+}
+
+INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, n);
+  unsigned char c1 = 0, c2 = 0;
+  uptr i;
+  for (i = 0; i < n; i++) {
+    c1 = (unsigned char)s1[i];
+    c2 = (unsigned char)s2[i];
+    if (CharCaseCmp(c1, c2) != 0 || c1 == '\0')
+      break;
+  }
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, n));
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, n));
+  return CharCaseCmp(c1, c2);
+}
+
+#define INIT_STRCASECMP INTERCEPT_FUNCTION(strcasecmp)
+#define INIT_STRNCASECMP INTERCEPT_FUNCTION(strncasecmp)
+#else
+#define INIT_STRCASECMP
+#define INIT_STRNCASECMP
+#endif
+
 #if SANITIZER_INTERCEPT_FREXP
 INTERCEPTOR(double, frexp, double x, int *exp) {
   void *ctx;
@@ -66,6 +154,27 @@
 #define INIT_FREXPF_FREXPL
 #endif // SANITIZER_INTERCEPT_FREXPF_FREXPL
 
+#if SI_NOT_WINDOWS
+static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec,
+                        SIZE_T iovlen, SIZE_T maxlen) {
+  for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+    SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec[i].iov_base, sz);
+    maxlen -= sz;
+  }
+}
+
+static void read_iovec(void *ctx, struct __sanitizer_iovec *iovec,
+                       SIZE_T iovlen, SIZE_T maxlen) {
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec) * iovlen);
+  for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
+    SSIZE_T sz = Min(iovec[i].iov_len, maxlen);
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec[i].iov_base, sz);
+    maxlen -= sz;
+  }
+}
+#endif
+
 #if SANITIZER_INTERCEPT_READ
 INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
   void *ctx;
@@ -114,6 +223,51 @@
 #define INIT_PREAD64
 #endif
 
+#if SANITIZER_INTERCEPT_READV
+INTERCEPTOR_WITH_SUFFIX(SSIZE_T, readv, int fd, __sanitizer_iovec *iov,
+                        int iovcnt) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, readv, fd, iov, iovcnt);
+  SSIZE_T res = REAL(readv)(fd, iov, iovcnt);
+  if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+  if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+  return res;
+}
+#define INIT_READV INTERCEPT_FUNCTION(readv)
+#else
+#define INIT_READV
+#endif
+
+#if SANITIZER_INTERCEPT_PREADV
+INTERCEPTOR(SSIZE_T, preadv, int fd, __sanitizer_iovec *iov, int iovcnt,
+            OFF_T offset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, preadv, fd, iov, iovcnt, offset);
+  SSIZE_T res = REAL(preadv)(fd, iov, iovcnt, offset);
+  if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+  if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+  return res;
+}
+#define INIT_PREADV INTERCEPT_FUNCTION(preadv)
+#else
+#define INIT_PREADV
+#endif
+
+#if SANITIZER_INTERCEPT_PREADV64
+INTERCEPTOR(SSIZE_T, preadv64, int fd, __sanitizer_iovec *iov, int iovcnt,
+            OFF64_T offset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, preadv64, fd, iov, iovcnt, offset);
+  SSIZE_T res = REAL(preadv64)(fd, iov, iovcnt, offset);
+  if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+  if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+  return res;
+}
+#define INIT_PREADV64 INTERCEPT_FUNCTION(preadv64)
+#else
+#define INIT_PREADV64
+#endif
+
 #if SANITIZER_INTERCEPT_WRITE
 INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
   void *ctx;
@@ -121,6 +275,7 @@
   if (fd >= 0)
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
   SSIZE_T res = REAL(write)(fd, ptr, count);
+  // FIXME: this check should be _before_ the call to REAL(write), not after
   if (res > 0)
     COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
   return res;
@@ -163,6 +318,51 @@
 #define INIT_PWRITE64
 #endif
 
+#if SANITIZER_INTERCEPT_WRITEV
+INTERCEPTOR_WITH_SUFFIX(SSIZE_T, writev, int fd, __sanitizer_iovec *iov,
+                        int iovcnt) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, writev, fd, iov, iovcnt);
+  if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+  SSIZE_T res = REAL(writev)(fd, iov, iovcnt);
+  if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+  return res;
+}
+#define INIT_WRITEV INTERCEPT_FUNCTION(writev)
+#else
+#define INIT_WRITEV
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITEV
+INTERCEPTOR(SSIZE_T, pwritev, int fd, __sanitizer_iovec *iov, int iovcnt,
+            OFF_T offset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, pwritev, fd, iov, iovcnt, offset);
+  if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+  SSIZE_T res = REAL(pwritev)(fd, iov, iovcnt, offset);
+  if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+  return res;
+}
+#define INIT_PWRITEV INTERCEPT_FUNCTION(pwritev)
+#else
+#define INIT_PWRITEV
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITEV64
+INTERCEPTOR(SSIZE_T, pwritev64, int fd, __sanitizer_iovec *iov, int iovcnt,
+            OFF64_T offset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, pwritev64, fd, iov, iovcnt, offset);
+  if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+  SSIZE_T res = REAL(pwritev64)(fd, iov, iovcnt, offset);
+  if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+  return res;
+}
+#define INIT_PWRITEV64 INTERCEPT_FUNCTION(pwritev64)
+#else
+#define INIT_PWRITEV64
+#endif
+
 #if SANITIZER_INTERCEPT_PRCTL
 INTERCEPTOR(int, prctl, int option,
             unsigned long arg2, unsigned long arg3,   // NOLINT
@@ -184,6 +384,24 @@
 #define INIT_PRCTL
 #endif // SANITIZER_INTERCEPT_PRCTL
 
+
+#if SANITIZER_INTERCEPT_TIME
+INTERCEPTOR(unsigned long, time, unsigned long *t) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, time, t);
+  unsigned long res = REAL(time)(t);
+  if (t && res != (unsigned long)-1) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, t, sizeof(*t));
+  }
+  return res;
+}
+#define INIT_TIME                                \
+  INTERCEPT_FUNCTION(time);
+#else
+#define INIT_TIME
+#endif // SANITIZER_INTERCEPT_TIME
+
+
 #if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
 INTERCEPTOR(void *, localtime, unsigned long *timep) {
   void *ctx;
@@ -365,15 +583,1257 @@
 #define INIT_SCANF
 #endif
 
-#define SANITIZER_COMMON_INTERCEPTORS_INIT                                     \
-  INIT_READ;                                                                   \
-  INIT_PREAD;                                                                  \
-  INIT_PREAD64;                                                                \
-  INIT_PRCTL;                                                                  \
-  INIT_WRITE;                                                                  \
-  INIT_PWRITE;                                                                 \
-  INIT_PWRITE64;                                                               \
-  INIT_LOCALTIME_AND_FRIENDS;                                                  \
-  INIT_SCANF;                                                                  \
-  INIT_FREXP;                                                                  \
-  INIT_FREXPF_FREXPL;
+
+#if SANITIZER_INTERCEPT_IOCTL
+#include "sanitizer_common_interceptors_ioctl.inc"
+INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, ioctl, d, request, arg);
+
+  CHECK(ioctl_initialized);
+
+  // Note: TSan does not use common flags, and they are zero-initialized.
+  // This effectively disables ioctl handling in TSan.
+  if (!common_flags()->handle_ioctl)
+    return REAL(ioctl)(d, request, arg);
+
+  const ioctl_desc *desc = ioctl_lookup(request);
+  if (!desc)
+    Printf("WARNING: unknown ioctl %x\n", request);
+
+  if (desc)
+    ioctl_common_pre(ctx, desc, d, request, arg);
+  int res = REAL(ioctl)(d, request, arg);
+  // FIXME: some ioctls have different return values for success and failure.
+  if (desc && res != -1)
+    ioctl_common_post(ctx, desc, res, d, request, arg);
+  return res;
+}
+#define INIT_IOCTL \
+  ioctl_init();    \
+  INTERCEPT_FUNCTION(ioctl);
+#else
+#define INIT_IOCTL
+#endif
+
+
+#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
+INTERCEPTOR(void *, getpwnam, const char *name) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  void *res = REAL(getpwnam)(name);
+  if (res != 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
+  return res;
+}
+INTERCEPTOR(void *, getpwuid, u32 uid) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid);
+  void *res = REAL(getpwuid)(uid);
+  if (res != 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
+  return res;
+}
+INTERCEPTOR(void *, getgrnam, const char *name) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  void *res = REAL(getgrnam)(name);
+  if (res != 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
+  return res;
+}
+INTERCEPTOR(void *, getgrgid, u32 gid) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid);
+  void *res = REAL(getgrgid)(gid);
+  if (res != 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
+  return res;
+}
+#define INIT_GETPWNAM_AND_FRIENDS                  \
+  INTERCEPT_FUNCTION(getpwnam);                    \
+  INTERCEPT_FUNCTION(getpwuid);                    \
+  INTERCEPT_FUNCTION(getgrnam);                    \
+  INTERCEPT_FUNCTION(getgrgid);
+#else
+#define INIT_GETPWNAM_AND_FRIENDS
+#endif
+
+
+#if SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd,
+    char *buf, SIZE_T buflen, void **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  return res;
+}
+INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd,
+    char *buf, SIZE_T buflen, void **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result);
+  int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  return res;
+}
+INTERCEPTOR(int, getgrnam_r, const char *name, void *grp,
+    char *buf, SIZE_T buflen, void **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  int res = REAL(getgrnam_r)(name, grp, buf, buflen, result);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, struct_group_sz);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  return res;
+}
+INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp,
+    char *buf, SIZE_T buflen, void **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result);
+  int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, struct_group_sz);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  return res;
+}
+#define INIT_GETPWNAM_R_AND_FRIENDS                \
+  INTERCEPT_FUNCTION(getpwnam_r);                  \
+  INTERCEPT_FUNCTION(getpwuid_r);                  \
+  INTERCEPT_FUNCTION(getgrnam_r);                  \
+  INTERCEPT_FUNCTION(getgrgid_r);
+#else
+#define INIT_GETPWNAM_R_AND_FRIENDS
+#endif
+
+
+#if SANITIZER_INTERCEPT_CLOCK_GETTIME
+INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, clock_getres, clk_id, tp);
+  int res = REAL(clock_getres)(clk_id, tp);
+  if (!res && tp) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
+  }
+  return res;
+}
+INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, clock_gettime, clk_id, tp);
+  int res = REAL(clock_gettime)(clk_id, tp);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
+  }
+  return res;
+}
+INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, tp, struct_timespec_sz);
+  return REAL(clock_settime)(clk_id, tp);
+}
+#define INIT_CLOCK_GETTIME                         \
+  INTERCEPT_FUNCTION(clock_getres);                \
+  INTERCEPT_FUNCTION(clock_gettime);               \
+  INTERCEPT_FUNCTION(clock_settime);
+#else
+#define INIT_CLOCK_GETTIME
+#endif
+
+
+#if SANITIZER_INTERCEPT_GETITIMER
+INTERCEPTOR(int, getitimer, int which, void *curr_value) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getitimer, which, curr_value);
+  int res = REAL(getitimer)(which, curr_value);
+  if (!res && curr_value) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz);
+  }
+  return res;
+}
+INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, setitimer, which, new_value, old_value);
+  if (new_value)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz);
+  int res = REAL(setitimer)(which, new_value, old_value);
+  if (!res && old_value) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz);
+  }
+  return res;
+}
+#define INIT_GETITIMER                             \
+  INTERCEPT_FUNCTION(getitimer);                   \
+  INTERCEPT_FUNCTION(setitimer);
+#else
+#define INIT_GETITIMER
+#endif
+
+#if SANITIZER_INTERCEPT_GLOB
+static void unpoison_glob_t(void *ctx, __sanitizer_glob_t *pglob) {
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pglob, sizeof(*pglob));
+  // +1 for NULL pointer at the end.
+  if (pglob->gl_pathv)
+    COMMON_INTERCEPTOR_WRITE_RANGE(
+        ctx, pglob->gl_pathv, (pglob->gl_pathc + 1) * sizeof(*pglob->gl_pathv));
+  for (SIZE_T i = 0; i < pglob->gl_pathc; ++i) {
+    char *p = pglob->gl_pathv[i];
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, REAL(strlen)(p) + 1);
+  }
+}
+
+static THREADLOCAL __sanitizer_glob_t* pglob_copy;
+static THREADLOCAL void* glob_ctx;
+
+static void wrapped_gl_closedir(void *dir) {
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
+  pglob_copy->gl_closedir(dir);
+}
+
+static void *wrapped_gl_readdir(void *dir) {
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
+  return pglob_copy->gl_readdir(dir);
+}
+
+static void *wrapped_gl_opendir(const char *s) {
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
+  COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1);
+  return pglob_copy->gl_opendir(s);
+}
+
+static int wrapped_gl_lstat(const char *s, void *st) {
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 2);
+  COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1);
+  return pglob_copy->gl_lstat(s, st);
+}
+
+static int wrapped_gl_stat(const char *s, void *st) {
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 2);
+  COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1);
+  return pglob_copy->gl_stat(s, st);
+}
+
+INTERCEPTOR(int, glob, const char *pattern, int flags,
+            int (*errfunc)(const char *epath, int eerrno),
+            __sanitizer_glob_t *pglob) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
+  __sanitizer_glob_t glob_copy = {0, 0, 0, 0, wrapped_gl_closedir,
+                                  wrapped_gl_readdir, wrapped_gl_opendir,
+                                  wrapped_gl_lstat, wrapped_gl_stat};
+  if (flags & glob_altdirfunc) {
+    Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+    Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+    Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+    Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+    Swap(pglob->gl_stat, glob_copy.gl_stat);
+    pglob_copy = &glob_copy;
+    glob_ctx = ctx;
+  }
+  int res = REAL(glob)(pattern, flags, errfunc, pglob);
+  if (flags & glob_altdirfunc) {
+    Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+    Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+    Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+    Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+    Swap(pglob->gl_stat, glob_copy.gl_stat);
+  }
+  pglob_copy = 0;
+  glob_ctx = 0;
+  if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
+  return res;
+}
+
+INTERCEPTOR(int, glob64, const char *pattern, int flags,
+            int (*errfunc)(const char *epath, int eerrno),
+            __sanitizer_glob_t *pglob) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob);
+  __sanitizer_glob_t glob_copy = {0, 0, 0, 0, wrapped_gl_closedir,
+                                  wrapped_gl_readdir, wrapped_gl_opendir,
+                                  wrapped_gl_lstat, wrapped_gl_stat};
+  if (flags & glob_altdirfunc) {
+    Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+    Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+    Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+    Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+    Swap(pglob->gl_stat, glob_copy.gl_stat);
+    pglob_copy = &glob_copy;
+    glob_ctx = ctx;
+  }
+  int res = REAL(glob64)(pattern, flags, errfunc, pglob);
+  if (flags & glob_altdirfunc) {
+    Swap(pglob->gl_closedir, glob_copy.gl_closedir);
+    Swap(pglob->gl_readdir, glob_copy.gl_readdir);
+    Swap(pglob->gl_opendir, glob_copy.gl_opendir);
+    Swap(pglob->gl_lstat, glob_copy.gl_lstat);
+    Swap(pglob->gl_stat, glob_copy.gl_stat);
+  }
+  pglob_copy = 0;
+  glob_ctx = 0;
+  if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
+  return res;
+}
+#define INIT_GLOB           \
+  INTERCEPT_FUNCTION(glob); \
+  INTERCEPT_FUNCTION(glob64);
+#else  // SANITIZER_INTERCEPT_GLOB
+#define INIT_GLOB
+#endif  // SANITIZER_INTERCEPT_GLOB
+
+#if SANITIZER_INTERCEPT_WAIT
+// According to sys/wait.h, wait(), waitid(), waitpid() may have symbol version
+// suffixes on Darwin. See the declaration of INTERCEPTOR_WITH_SUFFIX for
+// details.
+INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, wait, status);
+  int res = REAL(wait)(status);
+  if (res != -1 && status)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+  return res;
+}
+INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
+  int options) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options);
+  int res = REAL(waitid)(idtype, id, infop, options);
+  if (res != -1 && infop)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz);
+  return res;
+}
+INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, waitpid, pid, status, options);
+  int res = REAL(waitpid)(pid, status, options);
+  if (res != -1 && status)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+  return res;
+}
+INTERCEPTOR(int, wait3, int *status, int options, void *rusage) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage);
+  int res = REAL(wait3)(status, options, rusage);
+  if (res != -1) {
+    if (status)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+    if (rusage)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+  }
+  return res;
+}
+INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage);
+  int res = REAL(wait4)(pid, status, options, rusage);
+  if (res != -1) {
+    if (status)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+    if (rusage)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+  }
+  return res;
+}
+#define INIT_WAIT                                \
+  INTERCEPT_FUNCTION(wait);                      \
+  INTERCEPT_FUNCTION(waitid);                    \
+  INTERCEPT_FUNCTION(waitpid);                   \
+  INTERCEPT_FUNCTION(wait3);                     \
+  INTERCEPT_FUNCTION(wait4);
+#else
+#define INIT_WAIT
+#endif
+
+#if SANITIZER_INTERCEPT_INET
+INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, inet_ntop, af, src, dst, size);
+  uptr sz = __sanitizer_in_addr_sz(af);
+  if (sz) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sz);
+  // FIXME: figure out read size based on the address family.
+  char *res = REAL(inet_ntop)(af, src, dst, size);
+  if (res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  return res;
+}
+INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, inet_pton, af, src, dst);
+  // FIXME: figure out read size based on the address family.
+  int res = REAL(inet_pton)(af, src, dst);
+  if (res == 1) {
+    uptr sz = __sanitizer_in_addr_sz(af);
+    if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz);
+  }
+  return res;
+}
+#define INIT_INET                                \
+  INTERCEPT_FUNCTION(inet_ntop);                 \
+  INTERCEPT_FUNCTION(inet_pton);
+#else
+#define INIT_INET
+#endif
+
+#if SANITIZER_INTERCEPT_INET
+INTERCEPTOR(int, inet_aton, const char *cp, void *dst) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, inet_aton, cp, dst);
+  if (cp) COMMON_INTERCEPTOR_READ_RANGE(ctx, cp, REAL(strlen)(cp) + 1);
+  int res = REAL(inet_aton)(cp, dst);
+  if (res != 0) {
+    uptr sz = __sanitizer_in_addr_sz(af_inet);
+    if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz);
+  }
+  return res;
+}
+#define INIT_INET_ATON INTERCEPT_FUNCTION(inet_aton);
+#else
+#define INIT_INET_ATON
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM
+INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, pthread_getschedparam, thread, policy, param);
+  int res = REAL(pthread_getschedparam)(thread, policy, param);
+  if (res == 0) {
+    if (policy) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, policy, sizeof(*policy));
+    if (param) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, param, sizeof(*param));
+  }
+  return res;
+}
+#define INIT_PTHREAD_GETSCHEDPARAM INTERCEPT_FUNCTION(pthread_getschedparam);
+#else
+#define INIT_PTHREAD_GETSCHEDPARAM
+#endif
+
+#if SANITIZER_INTERCEPT_GETADDRINFO
+INTERCEPTOR(int, getaddrinfo, char *node, char *service,
+            struct __sanitizer_addrinfo *hints,
+            struct __sanitizer_addrinfo **out) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getaddrinfo, node, service, hints, out);
+  if (node) COMMON_INTERCEPTOR_READ_RANGE(ctx, node, REAL(strlen)(node) + 1);
+  if (service)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, service, REAL(strlen)(service) + 1);
+  if (hints)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, hints, sizeof(__sanitizer_addrinfo));
+  int res = REAL(getaddrinfo)(node, service, hints, out);
+  if (res == 0 && out) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out));
+    struct __sanitizer_addrinfo *p = *out;
+    while (p) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+      if (p->ai_addr)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_addr, p->ai_addrlen);
+      if (p->ai_canonname)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_canonname,
+                                       REAL(strlen)(p->ai_canonname) + 1);
+      p = p->ai_next;
+    }
+  }
+  return res;
+}
+#define INIT_GETADDRINFO INTERCEPT_FUNCTION(getaddrinfo);
+#else
+#define INIT_GETADDRINFO
+#endif
+
+#if SANITIZER_INTERCEPT_GETNAMEINFO
+INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host,
+            unsigned hostlen, char *serv, unsigned servlen, int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getnameinfo, sockaddr, salen, host, hostlen,
+                           serv, servlen, flags);
+  // FIXME: consider adding READ_RANGE(sockaddr, salen)
+  // There is padding in in_addr that may make this too noisy
+  int res =
+      REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags);
+  if (res == 0) {
+    if (host && hostlen)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, host, REAL(strlen)(host) + 1);
+    if (serv && servlen)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, serv, REAL(strlen)(serv) + 1);
+  }
+  return res;
+}
+#define INIT_GETNAMEINFO INTERCEPT_FUNCTION(getnameinfo);
+#else
+#define INIT_GETNAMEINFO
+#endif
+
+#if SANITIZER_INTERCEPT_GETSOCKNAME
+INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getsockname, sock_fd, addr, addrlen);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+  int addrlen_in = *addrlen;
+  int res = REAL(getsockname)(sock_fd, addr, addrlen);
+  if (res == 0) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addrlen_in, *addrlen));
+  }
+  return res;
+}
+#define INIT_GETSOCKNAME INTERCEPT_FUNCTION(getsockname);
+#else
+#define INIT_GETSOCKNAME
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME || SANITIZER_INTERCEPT_GETHOSTBYNAME_R
+static void write_hostent(void *ctx, struct __sanitizer_hostent *h) {
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h, sizeof(__sanitizer_hostent));
+  if (h->h_name)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h->h_name, REAL(strlen)(h->h_name) + 1);
+  char **p = h->h_aliases;
+  while (*p) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, REAL(strlen)(*p) + 1);
+    ++p;
+  }
+  COMMON_INTERCEPTOR_WRITE_RANGE(
+      ctx, h->h_aliases, (p - h->h_aliases + 1) * sizeof(*h->h_aliases));
+  p = h->h_addr_list;
+  while (*p) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, h->h_length);
+    ++p;
+  }
+  COMMON_INTERCEPTOR_WRITE_RANGE(
+      ctx, h->h_addr_list, (p - h->h_addr_list + 1) * sizeof(*h->h_addr_list));
+}
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME
+INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname, char *name) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname, name);
+  struct __sanitizer_hostent *res = REAL(gethostbyname)(name);
+  if (res) write_hostent(ctx, res);
+  return res;
+}
+
+INTERCEPTOR(struct __sanitizer_hostent *, gethostbyaddr, void *addr, int len,
+            int type) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr, addr, len, type);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len);
+  struct __sanitizer_hostent *res = REAL(gethostbyaddr)(addr, len, type);
+  if (res) write_hostent(ctx, res);
+  return res;
+}
+
+INTERCEPTOR(struct __sanitizer_hostent *, gethostent) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, gethostent);
+  struct __sanitizer_hostent *res = REAL(gethostent)();
+  if (res) write_hostent(ctx, res);
+  return res;
+}
+
+INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname2, char *name, int af) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2, name, af);
+  struct __sanitizer_hostent *res = REAL(gethostbyname2)(name, af);
+  if (res) write_hostent(ctx, res);
+  return res;
+}
+#define INIT_GETHOSTBYNAME           \
+  INTERCEPT_FUNCTION(gethostent);    \
+  INTERCEPT_FUNCTION(gethostbyaddr); \
+  INTERCEPT_FUNCTION(gethostbyname); \
+  INTERCEPT_FUNCTION(gethostbyname2);
+#else
+#define INIT_GETHOSTBYNAME
+#endif
+
+#if SANITIZER_INTERCEPT_GETHOSTBYNAME_R
+INTERCEPTOR(int, gethostent_r, struct __sanitizer_hostent *ret, char *buf,
+            SIZE_T buflen, __sanitizer_hostent **result, int *h_errnop) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, gethostent_r, ret, buf, buflen, result,
+                           h_errnop);
+  int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop);
+  if (res == 0) {
+    if (result) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+      if (*result) write_hostent(ctx, *result);
+    }
+    if (h_errnop)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  }
+  return res;
+}
+
+INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type,
+            struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen,
+            __sanitizer_hostent **result, int *h_errnop) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr_r, addr, len, type, ret, buf,
+                           buflen, result, h_errnop);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len);
+  int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result,
+                                  h_errnop);
+  if (res == 0) {
+    if (result) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+      if (*result) write_hostent(ctx, *result);
+    }
+    if (h_errnop)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  }
+  return res;
+}
+
+INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret,
+            char *buf, SIZE_T buflen, __sanitizer_hostent **result,
+            int *h_errnop) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname_r, name, ret, buf, buflen, result,
+                           h_errnop);
+  int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop);
+  if (res == 0) {
+    if (result) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+      if (*result) write_hostent(ctx, *result);
+    }
+    if (h_errnop)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  }
+  return res;
+}
+
+INTERCEPTOR(int, gethostbyname2_r, char *name, int af,
+            struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen,
+            __sanitizer_hostent **result, int *h_errnop) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2_r, name, af, ret, buf, buflen,
+                           result, h_errnop);
+  int res =
+      REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop);
+  if (res == 0) {
+    if (result) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+      if (*result) write_hostent(ctx, *result);
+    }
+    if (h_errnop)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  }
+  return res;
+}
+#define INIT_GETHOSTBYNAME_R           \
+  INTERCEPT_FUNCTION(gethostent_r);    \
+  INTERCEPT_FUNCTION(gethostbyaddr_r); \
+  INTERCEPT_FUNCTION(gethostbyname_r); \
+  INTERCEPT_FUNCTION(gethostbyname2_r);
+#else
+#define INIT_GETHOSTBYNAME_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETSOCKOPT
+INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval,
+            int *optlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getsockopt, sockfd, level, optname, optval,
+                           optlen);
+  if (optlen) COMMON_INTERCEPTOR_READ_RANGE(ctx, optlen, sizeof(*optlen));
+  int res = REAL(getsockopt)(sockfd, level, optname, optval, optlen);
+  if (res == 0)
+    if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen);
+  return res;
+}
+#define INIT_GETSOCKOPT INTERCEPT_FUNCTION(getsockopt);
+#else
+#define INIT_GETSOCKOPT
+#endif
+
+#if SANITIZER_INTERCEPT_ACCEPT
+INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, accept, fd, addr, addrlen);
+  unsigned addrlen0;
+  if (addrlen) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+    addrlen0 = *addrlen;
+  }
+  int fd2 = REAL(accept)(fd, addr, addrlen);
+  if (fd2 >= 0) {
+    if (fd >= 0)
+      COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
+    if (addr && addrlen)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0));
+  }
+  return fd2;
+}
+#define INIT_ACCEPT INTERCEPT_FUNCTION(accept);
+#else
+#define INIT_ACCEPT
+#endif
+
+#if SANITIZER_INTERCEPT_ACCEPT4
+INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, accept4, fd, addr, addrlen, f);
+  unsigned addrlen0;
+  if (addrlen) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
+    addrlen0 = *addrlen;
+  }
+  int fd2 = REAL(accept4)(fd, addr, addrlen, f);
+  if (fd2 >= 0) {
+    if (fd >= 0)
+      COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
+    if (addr && addrlen)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0));
+  }
+  return fd2;
+}
+#define INIT_ACCEPT4 INTERCEPT_FUNCTION(accept4);
+#else
+#define INIT_ACCEPT4
+#endif
+
+#if SANITIZER_INTERCEPT_MODF
+INTERCEPTOR(double, modf, double x, double *iptr) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, modf, x, iptr);
+  double res = REAL(modf)(x, iptr);
+  if (iptr) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+  }
+  return res;
+}
+INTERCEPTOR(float, modff, float x, float *iptr) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, modff, x, iptr);
+  float res = REAL(modff)(x, iptr);
+  if (iptr) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+  }
+  return res;
+}
+INTERCEPTOR(long double, modfl, long double x, long double *iptr) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, modfl, x, iptr);
+  long double res = REAL(modfl)(x, iptr);
+  if (iptr) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
+  }
+  return res;
+}
+#define INIT_MODF            \
+  INTERCEPT_FUNCTION(modf);  \
+  INTERCEPT_FUNCTION(modff); \
+  INTERCEPT_FUNCTION(modfl);
+#else
+#define INIT_MODF
+#endif
+
+#if SANITIZER_INTERCEPT_RECVMSG
+static void write_msghdr(void *ctx, struct __sanitizer_msghdr *msg,
+                         SSIZE_T maxlen) {
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg, sizeof(*msg));
+  if (msg->msg_name)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_name,
+                                   REAL(strlen)((char *)msg->msg_name) + 1);
+  if (msg->msg_iov)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_iov,
+                                   sizeof(*msg->msg_iov) * msg->msg_iovlen);
+  write_iovec(ctx, msg->msg_iov, msg->msg_iovlen, maxlen);
+  if (msg->msg_control)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_control, msg->msg_controllen);
+}
+
+INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,
+            int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, recvmsg, fd, msg, flags);
+  SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
+  if (res >= 0) {
+    if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+    if (msg) write_msghdr(ctx, msg, res);
+  }
+  return res;
+}
+#define INIT_RECVMSG INTERCEPT_FUNCTION(recvmsg);
+#else
+#define INIT_RECVMSG
+#endif
+
+#if SANITIZER_INTERCEPT_GETPEERNAME
+INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpeername, sockfd, addr, addrlen);
+  unsigned addr_sz;
+  if (addrlen) addr_sz = *addrlen;
+  int res = REAL(getpeername)(sockfd, addr, addrlen);
+  if (!res && addr && addrlen)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen));
+  return res;
+}
+#define INIT_GETPEERNAME INTERCEPT_FUNCTION(getpeername);
+#else
+#define INIT_GETPEERNAME
+#endif
+
+#if SANITIZER_INTERCEPT_SYSINFO
+INTERCEPTOR(int, sysinfo, void *info) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info);
+  int res = REAL(sysinfo)(info);
+  if (!res && info)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, struct_sysinfo_sz);
+  return res;
+}
+#define INIT_SYSINFO INTERCEPT_FUNCTION(sysinfo);
+#else
+#define INIT_SYSINFO
+#endif
+
+#if SANITIZER_INTERCEPT_READDIR
+INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp);
+  __sanitizer_dirent *res = REAL(readdir)(dirp);
+  if (res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
+  return res;
+}
+
+INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry,
+            __sanitizer_dirent **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, readdir_r, dirp, entry, result);
+  int res = REAL(readdir_r)(dirp, entry, result);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+    if (*result)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen);
+  }
+  return res;
+}
+
+#define INIT_READDIR           \
+  INTERCEPT_FUNCTION(readdir); \
+  INTERCEPT_FUNCTION(readdir_r);
+#else
+#define INIT_READDIR
+#endif
+
+#if SANITIZER_INTERCEPT_READDIR64
+INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, readdir64, dirp);
+  __sanitizer_dirent64 *res = REAL(readdir64)(dirp);
+  if (res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
+  return res;
+}
+
+INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry,
+            __sanitizer_dirent64 **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, readdir64_r, dirp, entry, result);
+  int res = REAL(readdir64_r)(dirp, entry, result);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+    if (*result)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen);
+  }
+  return res;
+}
+#define INIT_READDIR64           \
+  INTERCEPT_FUNCTION(readdir64); \
+  INTERCEPT_FUNCTION(readdir64_r);
+#else
+#define INIT_READDIR64
+#endif
+
+#if SANITIZER_INTERCEPT_PTRACE
+INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data);
+
+  if (data) {
+    if (request == ptrace_setregs)
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz);
+    else if (request == ptrace_setfpregs)
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz);
+    else if (request == ptrace_setfpxregs)
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+    else if (request == ptrace_setsiginfo)
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz);
+    else if (request == ptrace_setregset) {
+      __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, iov->iov_base, iov->iov_len);
+    }
+  }
+
+  uptr res = REAL(ptrace)(request, pid, addr, data);
+
+  if (!res && data) {
+    // Note that PEEK* requests assing different meaning to the return value.
+    // This function does not handle them (nor does it need to).
+    if (request == ptrace_getregs)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz);
+    else if (request == ptrace_getfpregs)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz);
+    else if (request == ptrace_getfpxregs)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+    else if (request == ptrace_getsiginfo)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz);
+    else if (request == ptrace_getregset) {
+      __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iov->iov_base, iov->iov_len);
+    }
+  }
+  return res;
+}
+
+#define INIT_PTRACE           \
+  INTERCEPT_FUNCTION(ptrace);
+#else
+#define INIT_PTRACE
+#endif
+
+#if SANITIZER_INTERCEPT_SETLOCALE
+INTERCEPTOR(char *, setlocale, int category, char *locale) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, setlocale, category, locale);
+  if (locale)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, locale, REAL(strlen)(locale) + 1);
+  char *res = REAL(setlocale)(category, locale);
+  if (res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  return res;
+}
+
+#define INIT_SETLOCALE           \
+  INTERCEPT_FUNCTION(setlocale);
+#else
+#define INIT_SETLOCALE
+#endif
+
+#if SANITIZER_INTERCEPT_GETCWD
+INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getcwd, buf, size);
+  char *res = REAL(getcwd)(buf, size);
+  if (res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  return res;
+}
+#define INIT_GETCWD           \
+  INTERCEPT_FUNCTION(getcwd);
+#else
+#define INIT_GETCWD
+#endif
+
+#if SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME
+INTERCEPTOR(char *, get_current_dir_name) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name);
+  char *res = REAL(get_current_dir_name)();
+  if (res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  return res;
+}
+
+#define INIT_GET_CURRENT_DIR_NAME           \
+  INTERCEPT_FUNCTION(get_current_dir_name);
+#else
+#define INIT_GET_CURRENT_DIR_NAME
+#endif
+
+#if SANITIZER_INTERCEPT_STRTOIMAX
+INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strtoimax, nptr, endptr, base);
+  INTMAX_T res = REAL(strtoimax)(nptr, endptr, base);
+  if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+  return res;
+}
+
+INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strtoumax, nptr, endptr, base);
+  INTMAX_T res = REAL(strtoumax)(nptr, endptr, base);
+  if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+  return res;
+}
+
+#define INIT_STRTOIMAX           \
+  INTERCEPT_FUNCTION(strtoimax); \
+  INTERCEPT_FUNCTION(strtoumax);
+#else
+#define INIT_STRTOIMAX
+#endif
+
+#if SANITIZER_INTERCEPT_MBSTOWCS
+INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len);
+  SIZE_T res = REAL(mbstowcs)(dest, src, len);
+  if (res != (SIZE_T) - 1 && dest) {
+    SIZE_T write_cnt = res + (res < len);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+  }
+  return res;
+}
+
+INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len,
+            void *ps) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, mbsrtowcs, dest, src, len, ps);
+  if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+  if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+  SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps);
+  if (res != (SIZE_T)(-1) && dest && src) {
+    // This function, and several others, may or may not write the terminating
+    // \0 character. They write it iff they clear *src.
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+  }
+  return res;
+}
+
+#define INIT_MBSTOWCS           \
+  INTERCEPT_FUNCTION(mbstowcs); \
+  INTERCEPT_FUNCTION(mbsrtowcs);
+#else
+#define INIT_MBSTOWCS
+#endif
+
+#if SANITIZER_INTERCEPT_MBSNRTOWCS
+INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms,
+            SIZE_T len, void *ps) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, mbsnrtowcs, dest, src, nms, len, ps);
+  if (src) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+    if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
+  }
+  if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+  SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps);
+  if (res != (SIZE_T)(-1) && dest && src) {
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+  }
+  return res;
+}
+
+#define INIT_MBSNRTOWCS INTERCEPT_FUNCTION(mbsnrtowcs);
+#else
+#define INIT_MBSNRTOWCS
+#endif
+
+#if SANITIZER_INTERCEPT_WCSTOMBS
+INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len);
+  SIZE_T res = REAL(wcstombs)(dest, src, len);
+  if (res != (SIZE_T) - 1 && dest) {
+    SIZE_T write_cnt = res + (res < len);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+  }
+  return res;
+}
+
+INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len,
+            void *ps) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, wcsrtombs, dest, src, len, ps);
+  if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+  if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+  SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps);
+  if (res != (SIZE_T) - 1 && dest && src) {
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+  }
+  return res;
+}
+
+#define INIT_WCSTOMBS           \
+  INTERCEPT_FUNCTION(wcstombs); \
+  INTERCEPT_FUNCTION(wcsrtombs);
+#else
+#define INIT_WCSTOMBS
+#endif
+
+#if SANITIZER_INTERCEPT_WCSNRTOMBS
+INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
+            SIZE_T len, void *ps) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, wcsnrtombs, dest, src, nms, len, ps);
+  if (src) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+    if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
+  }
+  if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+  SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps);
+  if (res != (SIZE_T) - 1 && dest && src) {
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+  }
+  return res;
+}
+
+#define INIT_WCSNRTOMBS INTERCEPT_FUNCTION(wcsnrtombs);
+#else
+#define INIT_WCSNRTOMBS
+#endif
+
+
+#if SANITIZER_INTERCEPT_TCGETATTR
+INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, tcgetattr, fd, termios_p);
+  int res = REAL(tcgetattr)(fd, termios_p);
+  if (!res && termios_p)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz);
+  return res;
+}
+
+#define INIT_TCGETATTR INTERCEPT_FUNCTION(tcgetattr);
+#else
+#define INIT_TCGETATTR
+#endif
+
+
+#if SANITIZER_INTERCEPT_REALPATH
+INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, realpath, path, resolved_path);
+  if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+
+  // Workaround a bug in glibc where dlsym(RTLD_NEXT, ...) returns the oldest
+  // version of a versioned symbol. For realpath(), this gives us something
+  // (called __old_realpath) that does not handle NULL in the second argument.
+  // Handle it as part of the interceptor.
+  char *allocated_path = 0;
+  if (!resolved_path)
+    allocated_path = resolved_path = (char *)WRAP(malloc)(path_max + 1);
+
+  char *res = REAL(realpath)(path, resolved_path);
+  if (allocated_path && !res)
+    WRAP(free)(allocated_path);
+  if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  return res;
+}
+#define INIT_REALPATH INTERCEPT_FUNCTION(realpath);
+#else
+#define INIT_REALPATH
+#endif
+
+#if SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME
+INTERCEPTOR(char *, canonicalize_file_name, const char *path) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, canonicalize_file_name, path);
+  if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+  char *res = REAL(canonicalize_file_name)(path);
+  if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  return res;
+}
+#define INIT_CANONICALIZE_FILE_NAME INTERCEPT_FUNCTION(canonicalize_file_name);
+#else
+#define INIT_CANONICALIZE_FILE_NAME
+#endif
+
+#if SANITIZER_INTERCEPT_CONFSTR
+INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, confstr, name, buf, len);
+  SIZE_T res = REAL(confstr)(name, buf, len);
+  if (buf && res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len);
+  return res;
+}
+#define INIT_CONFSTR INTERCEPT_FUNCTION(confstr);
+#else
+#define INIT_CONFSTR
+#endif
+
+#if SANITIZER_INTERCEPT_SCHED_GETAFFINITY
+INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, sched_getaffinity, pid, cpusetsize, mask);
+  int res = REAL(sched_getaffinity)(pid, cpusetsize, mask);
+  if (mask && !res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize);
+  return res;
+}
+#define INIT_SCHED_GETAFFINITY INTERCEPT_FUNCTION(sched_getaffinity);
+#else
+#define INIT_SCHED_GETAFFINITY
+#endif
+
+#define SANITIZER_COMMON_INTERCEPTORS_INIT \
+  INIT_STRCMP;                             \
+  INIT_STRNCMP;                            \
+  INIT_STRCASECMP;                         \
+  INIT_STRNCASECMP;                        \
+  INIT_READ;                               \
+  INIT_PREAD;                              \
+  INIT_PREAD64;                            \
+  INIT_READV;                              \
+  INIT_PREADV;                             \
+  INIT_PREADV64;                           \
+  INIT_WRITE;                              \
+  INIT_PWRITE;                             \
+  INIT_PWRITE64;                           \
+  INIT_WRITEV;                             \
+  INIT_PWRITEV;                            \
+  INIT_PWRITEV64;                          \
+  INIT_PRCTL;                              \
+  INIT_LOCALTIME_AND_FRIENDS;              \
+  INIT_SCANF;                              \
+  INIT_FREXP;                              \
+  INIT_FREXPF_FREXPL;                      \
+  INIT_GETPWNAM_AND_FRIENDS;               \
+  INIT_GETPWNAM_R_AND_FRIENDS;             \
+  INIT_CLOCK_GETTIME;                      \
+  INIT_GETITIMER;                          \
+  INIT_TIME;                               \
+  INIT_GLOB;                               \
+  INIT_WAIT;                               \
+  INIT_INET;                               \
+  INIT_PTHREAD_GETSCHEDPARAM;              \
+  INIT_GETADDRINFO;                        \
+  INIT_GETNAMEINFO;                        \
+  INIT_GETSOCKNAME;                        \
+  INIT_GETHOSTBYNAME;                      \
+  INIT_GETHOSTBYNAME_R;                    \
+  INIT_GETSOCKOPT;                         \
+  INIT_ACCEPT;                             \
+  INIT_ACCEPT4;                            \
+  INIT_MODF;                               \
+  INIT_RECVMSG;                            \
+  INIT_GETPEERNAME;                        \
+  INIT_IOCTL;                              \
+  INIT_INET_ATON;                          \
+  INIT_SYSINFO;                            \
+  INIT_READDIR;                            \
+  INIT_READDIR64;                          \
+  INIT_PTRACE;                             \
+  INIT_SETLOCALE;                          \
+  INIT_GETCWD;                             \
+  INIT_GET_CURRENT_DIR_NAME;               \
+  INIT_STRTOIMAX;                          \
+  INIT_MBSTOWCS;                           \
+  INIT_MBSNRTOWCS;                         \
+  INIT_WCSTOMBS;                           \
+  INIT_WCSNRTOMBS;                         \
+  INIT_TCGETATTR;                          \
+  INIT_REALPATH;                           \
+  INIT_CANONICALIZE_FILE_NAME;             \
+  INIT_CONFSTR;                            \
+  INIT_SCHED_GETAFFINITY;
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
new file mode 100755
index 0000000..e8249de
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -0,0 +1,568 @@
+//===-- sanitizer_common_interceptors_ioctl.inc -----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Ioctl handling in common sanitizer interceptors.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_flags.h"
+
+struct ioctl_desc {
+  unsigned req;
+  // FIXME: support read+write arguments. Those are currently marked as WRITE.
+  enum {
+    NONE,
+    READ,
+    WRITE,
+    CUSTOM
+  } type : 2;
+  unsigned size : 30;
+  const char* name;
+};
+
+const unsigned ioctl_table_max = 500;
+static ioctl_desc ioctl_table[ioctl_table_max];
+static unsigned ioctl_table_size = 0;
+
+// This can not be declared as a global, because references to struct_*_sz
+// require a global initializer. And this table must be available before global
+// initializers are run.
+static void ioctl_table_fill() {
+#define _(rq, tp, sz)                                    \
+  if (IOCTL_##rq != IOCTL_NOT_PRESENT) {                 \
+    CHECK(ioctl_table_size < ioctl_table_max);           \
+    ioctl_table[ioctl_table_size].req = IOCTL_##rq;      \
+    ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \
+    ioctl_table[ioctl_table_size].size = sz;             \
+    ioctl_table[ioctl_table_size].name = #rq;            \
+    ++ioctl_table_size;                                  \
+  }
+
+  _(FIOASYNC, READ, sizeof(int));
+  _(FIOCLEX, NONE, 0);
+  _(FIOGETOWN, WRITE, sizeof(int));
+  _(FIONBIO, READ, sizeof(int));
+  _(FIONCLEX, NONE, 0);
+  _(FIOSETOWN, READ, sizeof(int));
+  _(SIOCADDMULTI, READ, struct_ifreq_sz);
+  _(SIOCATMARK, WRITE, sizeof(int));
+  _(SIOCDELMULTI, READ, struct_ifreq_sz);
+  _(SIOCGIFADDR, WRITE, struct_ifreq_sz);
+  _(SIOCGIFBRDADDR, WRITE, struct_ifreq_sz);
+  _(SIOCGIFCONF, CUSTOM, 0);
+  _(SIOCGIFDSTADDR, WRITE, struct_ifreq_sz);
+  _(SIOCGIFFLAGS, WRITE, struct_ifreq_sz);
+  _(SIOCGIFMETRIC, WRITE, struct_ifreq_sz);
+  _(SIOCGIFMTU, WRITE, struct_ifreq_sz);
+  _(SIOCGIFNETMASK, WRITE, struct_ifreq_sz);
+  _(SIOCGPGRP, WRITE, sizeof(int));
+  _(SIOCSIFADDR, READ, struct_ifreq_sz);
+  _(SIOCSIFBRDADDR, READ, struct_ifreq_sz);
+  _(SIOCSIFDSTADDR, READ, struct_ifreq_sz);
+  _(SIOCSIFFLAGS, READ, struct_ifreq_sz);
+  _(SIOCSIFMETRIC, READ, struct_ifreq_sz);
+  _(SIOCSIFMTU, READ, struct_ifreq_sz);
+  _(SIOCSIFNETMASK, READ, struct_ifreq_sz);
+  _(SIOCSPGRP, READ, sizeof(int));
+  _(TIOCCONS, NONE, 0);
+  _(TIOCEXCL, NONE, 0);
+  _(TIOCGETD, WRITE, sizeof(int));
+  _(TIOCGPGRP, WRITE, pid_t_sz);
+  _(TIOCGWINSZ, WRITE, struct_winsize_sz);
+  _(TIOCMBIC, READ, sizeof(int));
+  _(TIOCMBIS, READ, sizeof(int));
+  _(TIOCMGET, WRITE, sizeof(int));
+  _(TIOCMSET, READ, sizeof(int));
+  _(TIOCNOTTY, NONE, 0);
+  _(TIOCNXCL, NONE, 0);
+  _(TIOCOUTQ, WRITE, sizeof(int));
+  _(TIOCPKT, READ, sizeof(int));
+  _(TIOCSCTTY, NONE, 0);
+  _(TIOCSETD, READ, sizeof(int));
+  _(TIOCSPGRP, READ, pid_t_sz);
+  _(TIOCSTI, READ, sizeof(char));
+  _(TIOCSWINSZ, READ, struct_winsize_sz);
+
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_MAC
+  _(SIOCGETSGCNT, WRITE, struct_sioc_sg_req_sz);
+  _(SIOCGETVIFCNT, WRITE, struct_sioc_vif_req_sz);
+#endif
+
+#if SANITIZER_LINUX
+  // Conflicting request ids.
+  // _(CDROMAUDIOBUFSIZ, NONE, 0);
+  // _(SNDCTL_TMR_CONTINUE, NONE, 0);
+  // _(SNDCTL_TMR_START, NONE, 0);
+  // _(SNDCTL_TMR_STOP, NONE, 0);
+  // _(SOUND_MIXER_READ_LOUD, WRITE, sizeof(int)); // same as ...READ_ENHANCE
+  // _(SOUND_MIXER_READ_MUTE, WRITE, sizeof(int)); // same as ...READ_ENHANCE
+  // _(SOUND_MIXER_WRITE_LOUD, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE
+  // _(SOUND_MIXER_WRITE_MUTE, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE
+  _(BLKFLSBUF, NONE, 0);
+  _(BLKGETSIZE, WRITE, sizeof(uptr));
+  _(BLKRAGET, WRITE, sizeof(int));
+  _(BLKRASET, NONE, 0);
+  _(BLKROGET, WRITE, sizeof(int));
+  _(BLKROSET, READ, sizeof(int));
+  _(BLKRRPART, NONE, 0);
+  _(CDROMEJECT, NONE, 0);
+  _(CDROMEJECT_SW, NONE, 0);
+  _(CDROMMULTISESSION, WRITE, struct_cdrom_multisession_sz);
+  _(CDROMPAUSE, NONE, 0);
+  _(CDROMPLAYMSF, READ, struct_cdrom_msf_sz);
+  _(CDROMPLAYTRKIND, READ, struct_cdrom_ti_sz);
+  _(CDROMREADAUDIO, READ, struct_cdrom_read_audio_sz);
+  _(CDROMREADCOOKED, READ, struct_cdrom_msf_sz);
+  _(CDROMREADMODE1, READ, struct_cdrom_msf_sz);
+  _(CDROMREADMODE2, READ, struct_cdrom_msf_sz);
+  _(CDROMREADRAW, READ, struct_cdrom_msf_sz);
+  _(CDROMREADTOCENTRY, WRITE, struct_cdrom_tocentry_sz);
+  _(CDROMREADTOCHDR, WRITE, struct_cdrom_tochdr_sz);
+  _(CDROMRESET, NONE, 0);
+  _(CDROMRESUME, NONE, 0);
+  _(CDROMSEEK, READ, struct_cdrom_msf_sz);
+  _(CDROMSTART, NONE, 0);
+  _(CDROMSTOP, NONE, 0);
+  _(CDROMSUBCHNL, WRITE, struct_cdrom_subchnl_sz);
+  _(CDROMVOLCTRL, READ, struct_cdrom_volctrl_sz);
+  _(CDROMVOLREAD, WRITE, struct_cdrom_volctrl_sz);
+  _(CDROM_GET_UPC, WRITE, 8);
+  _(EVIOCGABS, WRITE, struct_input_absinfo_sz); // fixup
+  _(EVIOCGBIT, WRITE, struct_input_id_sz); // fixup
+  _(EVIOCGEFFECTS, WRITE, sizeof(int));
+  _(EVIOCGID, WRITE, struct_input_id_sz);
+  _(EVIOCGKEY, WRITE, 0);
+  _(EVIOCGKEYCODE, WRITE, sizeof(int) * 2);
+  _(EVIOCGLED, WRITE, 0);
+  _(EVIOCGNAME, WRITE, 0);
+  _(EVIOCGPHYS, WRITE, 0);
+  _(EVIOCGRAB, READ, sizeof(int));
+  _(EVIOCGREP, WRITE, sizeof(int) * 2);
+  _(EVIOCGSND, WRITE, 0);
+  _(EVIOCGSW, WRITE, 0);
+  _(EVIOCGUNIQ, WRITE, 0);
+  _(EVIOCGVERSION, WRITE, sizeof(int));
+  _(EVIOCRMFF, READ, sizeof(int));
+  _(EVIOCSABS, READ, struct_input_absinfo_sz); // fixup
+  _(EVIOCSFF, READ, struct_ff_effect_sz);
+  _(EVIOCSKEYCODE, READ, sizeof(int) * 2);
+  _(EVIOCSREP, READ, sizeof(int) * 2);
+  _(FDCLRPRM, NONE, 0);
+  _(FDDEFPRM, READ, struct_floppy_struct_sz);
+  _(FDFLUSH, NONE, 0);
+  _(FDFMTBEG, NONE, 0);
+  _(FDFMTEND, NONE, 0);
+  _(FDFMTTRK, READ, struct_format_descr_sz);
+  _(FDGETDRVPRM, WRITE, struct_floppy_drive_params_sz);
+  _(FDGETDRVSTAT, WRITE, struct_floppy_drive_struct_sz);
+  _(FDGETDRVTYP, WRITE, 16);
+  _(FDGETFDCSTAT, WRITE, struct_floppy_fdc_state_sz);
+  _(FDGETMAXERRS, WRITE, struct_floppy_max_errors_sz);
+  _(FDGETPRM, WRITE, struct_floppy_struct_sz);
+  _(FDMSGOFF, NONE, 0);
+  _(FDMSGON, NONE, 0);
+  _(FDPOLLDRVSTAT, WRITE, struct_floppy_drive_struct_sz);
+  _(FDRAWCMD, WRITE, struct_floppy_raw_cmd_sz);
+  _(FDRESET, NONE, 0);
+  _(FDSETDRVPRM, READ, struct_floppy_drive_params_sz);
+  _(FDSETEMSGTRESH, NONE, 0);
+  _(FDSETMAXERRS, READ, struct_floppy_max_errors_sz);
+  _(FDSETPRM, READ, struct_floppy_struct_sz);
+  _(FDTWADDLE, NONE, 0);
+  _(FDWERRORCLR, NONE, 0);
+  _(FDWERRORGET, WRITE, struct_floppy_write_errors_sz);
+  _(HDIO_DRIVE_CMD, WRITE, sizeof(int));
+  _(HDIO_GETGEO, WRITE, struct_hd_geometry_sz);
+  _(HDIO_GET_32BIT, WRITE, sizeof(int));
+  _(HDIO_GET_DMA, WRITE, sizeof(int));
+  _(HDIO_GET_IDENTITY, WRITE, struct_hd_driveid_sz);
+  _(HDIO_GET_KEEPSETTINGS, WRITE, sizeof(int));
+  _(HDIO_GET_MULTCOUNT, WRITE, sizeof(int));
+  _(HDIO_GET_NOWERR, WRITE, sizeof(int));
+  _(HDIO_GET_UNMASKINTR, WRITE, sizeof(int));
+  _(HDIO_SET_32BIT, NONE, 0);
+  _(HDIO_SET_DMA, NONE, 0);
+  _(HDIO_SET_KEEPSETTINGS, NONE, 0);
+  _(HDIO_SET_MULTCOUNT, NONE, 0);
+  _(HDIO_SET_NOWERR, NONE, 0);
+  _(HDIO_SET_UNMASKINTR, NONE, 0);
+  _(MTIOCGET, WRITE, struct_mtget_sz);
+  _(MTIOCPOS, WRITE, struct_mtpos_sz);
+  _(MTIOCTOP, READ, struct_mtop_sz);
+  _(PPPIOCGASYNCMAP, WRITE, sizeof(int));
+  _(PPPIOCGDEBUG, WRITE, sizeof(int));
+  _(PPPIOCGFLAGS, WRITE, sizeof(int));
+  _(PPPIOCGUNIT, WRITE, sizeof(int));
+  _(PPPIOCGXASYNCMAP, WRITE, sizeof(int) * 8);
+  _(PPPIOCSASYNCMAP, READ, sizeof(int));
+  _(PPPIOCSDEBUG, READ, sizeof(int));
+  _(PPPIOCSFLAGS, READ, sizeof(int));
+  _(PPPIOCSMAXCID, READ, sizeof(int));
+  _(PPPIOCSMRU, READ, sizeof(int));
+  _(PPPIOCSXASYNCMAP, READ, sizeof(int) * 8);
+  _(SIOCADDRT, READ, struct_rtentry_sz);
+  _(SIOCDARP, READ, struct_arpreq_sz);
+  _(SIOCDELRT, READ, struct_rtentry_sz);
+  _(SIOCDRARP, READ, struct_arpreq_sz);
+  _(SIOCGARP, WRITE, struct_arpreq_sz);
+  _(SIOCGIFENCAP, WRITE, sizeof(int));
+  _(SIOCGIFHWADDR, WRITE, struct_ifreq_sz);
+  _(SIOCGIFMAP, WRITE, struct_ifreq_sz);
+  _(SIOCGIFMEM, WRITE, struct_ifreq_sz);
+  _(SIOCGIFNAME, NONE, 0);
+  _(SIOCGIFSLAVE, NONE, 0);
+  _(SIOCGRARP, WRITE, struct_arpreq_sz);
+  _(SIOCGSTAMP, WRITE, timeval_sz);
+  _(SIOCSARP, READ, struct_arpreq_sz);
+  _(SIOCSIFENCAP, READ, sizeof(int));
+  _(SIOCSIFHWADDR, READ, struct_ifreq_sz);
+  _(SIOCSIFLINK, NONE, 0);
+  _(SIOCSIFMAP, READ, struct_ifreq_sz);
+  _(SIOCSIFMEM, READ, struct_ifreq_sz);
+  _(SIOCSIFSLAVE, NONE, 0);
+  _(SIOCSRARP, READ, struct_arpreq_sz);
+  _(SNDCTL_COPR_HALT, WRITE, struct_copr_debug_buf_sz);
+  _(SNDCTL_COPR_LOAD, READ, struct_copr_buffer_sz);
+  _(SNDCTL_COPR_RCODE, WRITE, struct_copr_debug_buf_sz);
+  _(SNDCTL_COPR_RCVMSG, WRITE, struct_copr_msg_sz);
+  _(SNDCTL_COPR_RDATA, WRITE, struct_copr_debug_buf_sz);
+  _(SNDCTL_COPR_RESET, NONE, 0);
+  _(SNDCTL_COPR_RUN, WRITE, struct_copr_debug_buf_sz);
+  _(SNDCTL_COPR_SENDMSG, READ, struct_copr_msg_sz);
+  _(SNDCTL_COPR_WCODE, READ, struct_copr_debug_buf_sz);
+  _(SNDCTL_COPR_WDATA, READ, struct_copr_debug_buf_sz);
+  _(SNDCTL_DSP_GETBLKSIZE, WRITE, sizeof(int));
+  _(SNDCTL_DSP_GETFMTS, WRITE, sizeof(int));
+  _(SNDCTL_DSP_NONBLOCK, NONE, 0);
+  _(SNDCTL_DSP_POST, NONE, 0);
+  _(SNDCTL_DSP_RESET, NONE, 0);
+  _(SNDCTL_DSP_SETFMT, WRITE, sizeof(int));
+  _(SNDCTL_DSP_SETFRAGMENT, WRITE, sizeof(int));
+  _(SNDCTL_DSP_SPEED, WRITE, sizeof(int));
+  _(SNDCTL_DSP_STEREO, WRITE, sizeof(int));
+  _(SNDCTL_DSP_SUBDIVIDE, WRITE, sizeof(int));
+  _(SNDCTL_DSP_SYNC, NONE, 0);
+  _(SNDCTL_FM_4OP_ENABLE, READ, sizeof(int));
+  _(SNDCTL_FM_LOAD_INSTR, READ, struct_sbi_instrument_sz);
+  _(SNDCTL_MIDI_INFO, WRITE, struct_midi_info_sz);
+  _(SNDCTL_MIDI_PRETIME, WRITE, sizeof(int));
+  _(SNDCTL_SEQ_CTRLRATE, WRITE, sizeof(int));
+  _(SNDCTL_SEQ_GETINCOUNT, WRITE, sizeof(int));
+  _(SNDCTL_SEQ_GETOUTCOUNT, WRITE, sizeof(int));
+  _(SNDCTL_SEQ_NRMIDIS, WRITE, sizeof(int));
+  _(SNDCTL_SEQ_NRSYNTHS, WRITE, sizeof(int));
+  _(SNDCTL_SEQ_OUTOFBAND, READ, struct_seq_event_rec_sz);
+  _(SNDCTL_SEQ_PANIC, NONE, 0);
+  _(SNDCTL_SEQ_PERCMODE, NONE, 0);
+  _(SNDCTL_SEQ_RESET, NONE, 0);
+  _(SNDCTL_SEQ_RESETSAMPLES, READ, sizeof(int));
+  _(SNDCTL_SEQ_SYNC, NONE, 0);
+  _(SNDCTL_SEQ_TESTMIDI, READ, sizeof(int));
+  _(SNDCTL_SEQ_THRESHOLD, READ, sizeof(int));
+  _(SNDCTL_SYNTH_INFO, WRITE, struct_synth_info_sz);
+  _(SNDCTL_SYNTH_MEMAVL, WRITE, sizeof(int));
+  _(SNDCTL_TMR_METRONOME, READ, sizeof(int));
+  _(SNDCTL_TMR_SELECT, WRITE, sizeof(int));
+  _(SNDCTL_TMR_SOURCE, WRITE, sizeof(int));
+  _(SNDCTL_TMR_TEMPO, WRITE, sizeof(int));
+  _(SNDCTL_TMR_TIMEBASE, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_ALTPCM, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_BASS, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_CAPS, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_CD, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_DEVMASK, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_ENHANCE, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_IGAIN, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_IMIX, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_LINE, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_LINE1, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_LINE2, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_LINE3, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_MIC, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_OGAIN, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_PCM, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_RECLEV, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_RECMASK, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_RECSRC, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_SPEAKER, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_STEREODEVS, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_SYNTH, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_TREBLE, WRITE, sizeof(int));
+  _(SOUND_MIXER_READ_VOLUME, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_ALTPCM, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_BASS, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_CD, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_ENHANCE, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_IGAIN, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_IMIX, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_LINE, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_LINE1, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_LINE2, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_LINE3, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_MIC, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_OGAIN, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_PCM, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_RECLEV, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_RECSRC, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_SPEAKER, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_SYNTH, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_TREBLE, WRITE, sizeof(int));
+  _(SOUND_MIXER_WRITE_VOLUME, WRITE, sizeof(int));
+  _(SOUND_PCM_READ_BITS, WRITE, sizeof(int));
+  _(SOUND_PCM_READ_CHANNELS, WRITE, sizeof(int));
+  _(SOUND_PCM_READ_FILTER, WRITE, sizeof(int));
+  _(SOUND_PCM_READ_RATE, WRITE, sizeof(int));
+  _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int));
+  _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int));
+  _(TCFLSH, NONE, 0);
+  _(TCGETA, WRITE, struct_termio_sz);
+  _(TCGETS, WRITE, struct_termios_sz);
+  _(TCSBRK, NONE, 0);
+  _(TCSBRKP, NONE, 0);
+  _(TCSETA, READ, struct_termio_sz);
+  _(TCSETAF, READ, struct_termio_sz);
+  _(TCSETAW, READ, struct_termio_sz);
+  _(TCSETS, READ, struct_termios_sz);
+  _(TCSETSF, READ, struct_termios_sz);
+  _(TCSETSW, READ, struct_termios_sz);
+  _(TCXONC, NONE, 0);
+  _(TIOCGLCKTRMIOS, WRITE, struct_termios_sz);
+  _(TIOCGSOFTCAR, WRITE, sizeof(int));
+  _(TIOCINQ, WRITE, sizeof(int));
+  _(TIOCLINUX, READ, sizeof(char));
+  _(TIOCSERCONFIG, NONE, 0);
+  _(TIOCSERGETLSR, WRITE, sizeof(int));
+  _(TIOCSERGWILD, WRITE, sizeof(int));
+  _(TIOCSERSWILD, READ, sizeof(int));
+  _(TIOCSLCKTRMIOS, READ, struct_termios_sz);
+  _(TIOCSSOFTCAR, READ, sizeof(int));
+  _(VT_ACTIVATE, NONE, 0);
+  _(VT_DISALLOCATE, NONE, 0);
+  _(VT_GETMODE, WRITE, struct_vt_mode_sz);
+  _(VT_GETSTATE, WRITE, struct_vt_stat_sz);
+  _(VT_OPENQRY, WRITE, sizeof(int));
+  _(VT_RELDISP, NONE, 0);
+  _(VT_RESIZE, READ, struct_vt_sizes_sz);
+  _(VT_RESIZEX, READ, struct_vt_consize_sz);
+  _(VT_SENDSIG, NONE, 0);
+  _(VT_SETMODE, READ, struct_vt_mode_sz);
+  _(VT_WAITACTIVE, NONE, 0);
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
+  _(CYGETDEFTHRESH, WRITE, sizeof(int));
+  _(CYGETDEFTIMEOUT, WRITE, sizeof(int));
+  _(CYGETMON, WRITE, struct_cyclades_monitor_sz);
+  _(CYGETTHRESH, WRITE, sizeof(int));
+  _(CYGETTIMEOUT, WRITE, sizeof(int));
+  _(CYSETDEFTHRESH, NONE, 0);
+  _(CYSETDEFTIMEOUT, NONE, 0);
+  _(CYSETTHRESH, NONE, 0);
+  _(CYSETTIMEOUT, NONE, 0);
+  _(EQL_EMANCIPATE, WRITE, struct_ifreq_sz);
+  _(EQL_ENSLAVE, WRITE, struct_ifreq_sz);
+  _(EQL_GETMASTRCFG, WRITE, struct_ifreq_sz);
+  _(EQL_GETSLAVECFG, WRITE, struct_ifreq_sz);
+  _(EQL_SETMASTRCFG, WRITE, struct_ifreq_sz);
+  _(EQL_SETSLAVECFG, WRITE, struct_ifreq_sz);
+  _(EVIOCGKEYCODE_V2, WRITE, struct_input_keymap_entry_sz);
+  _(EVIOCGPROP, WRITE, 0);
+  _(EVIOCSKEYCODE_V2, READ, struct_input_keymap_entry_sz);
+  _(FS_IOC_GETFLAGS, WRITE, sizeof(int));
+  _(FS_IOC_GETVERSION, WRITE, sizeof(int));
+  _(FS_IOC_SETFLAGS, READ, sizeof(int));
+  _(FS_IOC_SETVERSION, READ, sizeof(int));
+  _(GIO_CMAP, WRITE, 48);
+  _(GIO_FONT, WRITE, 8192);
+  _(GIO_SCRNMAP, WRITE, e_tabsz);
+  _(GIO_UNIMAP, WRITE, struct_unimapdesc_sz);
+  _(GIO_UNISCRNMAP, WRITE, sizeof(short) * e_tabsz);
+  _(KDADDIO, NONE, 0);
+  _(KDDELIO, NONE, 0);
+  _(KDDISABIO, NONE, 0);
+  _(KDENABIO, NONE, 0);
+  _(KDGETKEYCODE, WRITE, struct_kbkeycode_sz);
+  _(KDGETLED, WRITE, 1);
+  _(KDGETMODE, WRITE, sizeof(int));
+  _(KDGKBDIACR, WRITE, struct_kbdiacrs_sz);
+  _(KDGKBENT, WRITE, struct_kbentry_sz);
+  _(KDGKBLED, WRITE, sizeof(int));
+  _(KDGKBMETA, WRITE, sizeof(int));
+  _(KDGKBMODE, WRITE, sizeof(int));
+  _(KDGKBSENT, WRITE, struct_kbsentry_sz);
+  _(KDGKBTYPE, WRITE, 1);
+  _(KDMAPDISP, NONE, 0);
+  _(KDMKTONE, NONE, 0);
+  _(KDSETKEYCODE, READ, struct_kbkeycode_sz);
+  _(KDSETLED, NONE, 0);
+  _(KDSETMODE, NONE, 0);
+  _(KDSIGACCEPT, NONE, 0);
+  _(KDSKBDIACR, READ, struct_kbdiacrs_sz);
+  _(KDSKBENT, READ, struct_kbentry_sz);
+  _(KDSKBLED, NONE, 0);
+  _(KDSKBMETA, NONE, 0);
+  _(KDSKBMODE, NONE, 0);
+  _(KDSKBSENT, READ, struct_kbsentry_sz);
+  _(KDUNMAPDISP, NONE, 0);
+  _(KIOCSOUND, NONE, 0);
+  _(LPABORT, NONE, 0);
+  _(LPABORTOPEN, NONE, 0);
+  _(LPCAREFUL, NONE, 0);
+  _(LPCHAR, NONE, 0);
+  _(LPGETIRQ, WRITE, sizeof(int));
+  _(LPGETSTATUS, WRITE, sizeof(int));
+  _(LPRESET, NONE, 0);
+  _(LPSETIRQ, NONE, 0);
+  _(LPTIME, NONE, 0);
+  _(LPWAIT, NONE, 0);
+  _(MTIOCGETCONFIG, WRITE, struct_mtconfiginfo_sz);
+  _(MTIOCSETCONFIG, READ, struct_mtconfiginfo_sz);
+  _(PIO_CMAP, NONE, 0);
+  _(PIO_FONT, READ, 8192);
+  _(PIO_SCRNMAP, READ, e_tabsz);
+  _(PIO_UNIMAP, READ, struct_unimapdesc_sz);
+  _(PIO_UNIMAPCLR, READ, struct_unimapinit_sz);
+  _(PIO_UNISCRNMAP, READ, sizeof(short) * e_tabsz);
+  _(SCSI_IOCTL_PROBE_HOST, READ, sizeof(int));
+  _(SCSI_IOCTL_TAGGED_DISABLE, NONE, 0);
+  _(SCSI_IOCTL_TAGGED_ENABLE, NONE, 0);
+  _(SNDCTL_DSP_GETISPACE, WRITE, struct_audio_buf_info_sz);
+  _(SNDCTL_DSP_GETOSPACE, WRITE, struct_audio_buf_info_sz);
+  _(TIOCGSERIAL, WRITE, struct_serial_struct_sz);
+  _(TIOCSERGETMULTI, WRITE, struct_serial_multiport_struct_sz);
+  _(TIOCSERSETMULTI, READ, struct_serial_multiport_struct_sz);
+  _(TIOCSSERIAL, READ, struct_serial_struct_sz);
+
+  // The following ioctl requests are shared between AX25, IPX, netrom and
+  // mrouted.
+  // _(SIOCAIPXITFCRT, READ, sizeof(char));
+  // _(SIOCAX25GETUID, READ, struct_sockaddr_ax25_sz);
+  // _(SIOCNRGETPARMS, WRITE, struct_nr_parms_struct_sz);
+  // _(SIOCAIPXPRISLT, READ, sizeof(char));
+  // _(SIOCNRSETPARMS, READ, struct_nr_parms_struct_sz);
+  // _(SIOCAX25ADDUID, READ, struct_sockaddr_ax25_sz);
+  // _(SIOCNRDECOBS, NONE, 0);
+  // _(SIOCAX25DELUID, READ, struct_sockaddr_ax25_sz);
+  // _(SIOCIPXCFGDATA, WRITE, struct_ipx_config_data_sz);
+  // _(SIOCAX25NOUID, READ, sizeof(int));
+  // _(SIOCNRRTCTL, READ, sizeof(int));
+  // _(SIOCAX25DIGCTL, READ, sizeof(int));
+  // _(SIOCAX25GETPARMS, WRITE, struct_ax25_parms_struct_sz);
+  // _(SIOCAX25SETPARMS, READ, struct_ax25_parms_struct_sz);
+#endif
+#undef _
+}
+
+static bool ioctl_initialized = false;
+
+struct ioctl_desc_compare {
+  bool operator()(const ioctl_desc& left, const ioctl_desc& right) const {
+    return left.req < right.req;
+  }
+};
+
+static void ioctl_init() {
+  ioctl_table_fill();
+  InternalSort(&ioctl_table, ioctl_table_size, ioctl_desc_compare());
+
+  bool bad = false;
+  for (unsigned i = 0; i < ioctl_table_size - 1; ++i) {
+    if (ioctl_table[i].req >= ioctl_table[i + 1].req) {
+      Printf("Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\n",
+             ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name,
+             ioctl_table[i + 1].name);
+      bad = true;
+    }
+  }
+
+  if (bad) Die();
+
+  ioctl_initialized = true;
+}
+
+// Handle the most evil ioctls that encode argument value as part of request id.
+static unsigned ioctl_request_fixup(unsigned req) {
+#if SANITIZER_LINUX
+  if ((req & ~0x3fff001fU) == IOCTL_EVIOCGBIT)
+    return IOCTL_EVIOCGBIT;
+  if ((req & ~0x3fU) == IOCTL_EVIOCGABS)
+    return IOCTL_EVIOCGABS;
+  if ((req & ~0x3fU) == IOCTL_EVIOCSABS)
+    return IOCTL_EVIOCSABS;
+#endif
+  return req;
+}
+
+static const ioctl_desc *ioctl_table_lookup(unsigned req) {
+  int left = 0;
+  int right = ioctl_table_size;
+  while (left < right) {
+    int mid = (left + right) / 2;
+    if (ioctl_table[mid].req < req)
+      left = mid + 1;
+    else
+      right = mid;
+  }
+  if (left == right && ioctl_table[left].req == req)
+    return ioctl_table + left;
+  else
+    return 0;
+}
+
+static const ioctl_desc *ioctl_lookup(unsigned req) {
+  req = ioctl_request_fixup(req);
+  const ioctl_desc *desc = ioctl_table_lookup(req);
+  if (desc) return desc;
+
+  // Try stripping access size from the request id.
+  desc = ioctl_table_lookup(req & ~0x3fff0000U);
+  // Sanity check: requests that encode access size are either read or write and
+  // have size of 0 in the table.
+  if (desc && desc->size == 0 &&
+      (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READ))
+    return desc;
+  return 0;
+}
+
+static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d,
+                             unsigned request, void *arg) {
+  if (desc->type == ioctl_desc::READ) {
+    unsigned size = desc->size ? desc->size : IOC_SIZE(request);
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size);
+  }
+  if (desc->type != ioctl_desc::CUSTOM)
+    return;
+  switch (request) {
+    case 0x00008912: {  // SIOCGIFCONF
+      struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, &ifc->ifc_len, sizeof(ifc->ifc_len));
+      break;
+    }
+  }
+  return;
+}
+
+static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d,
+                              unsigned request, void *arg) {
+  if (desc->type == ioctl_desc::WRITE) {
+    // FIXME: add verbose output
+    unsigned size = desc->size ? desc->size : IOC_SIZE(request);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size);
+  }
+  if (desc->type != ioctl_desc::CUSTOM)
+    return;
+  switch (request) {
+    case 0x00008912: {  // SIOCGIFCONF
+      struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len);
+      break;
+    }
+  }
+  return;
+}
diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc
new file mode 100644
index 0000000..c730ccf
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -0,0 +1,23 @@
+//===-- sanitizer_common_libcdep.cc ---------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+bool PrintsToTty() {
+  MaybeOpenReportFile();
+  return internal_isatty(report_fd) != 0;
+}
+
+}  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_common_syscalls.inc b/lib/sanitizer_common/sanitizer_common_syscalls.inc
new file mode 100644
index 0000000..1b32187
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_common_syscalls.inc
@@ -0,0 +1,191 @@
+//===-- sanitizer_common_syscalls.inc ---------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common syscalls handlers for tools like AddressSanitizer,
+// ThreadSanitizer, MemorySanitizer, etc.
+//
+// This file should be included into the tool's interceptor file,
+// which has to define it's own macros:
+//   COMMON_SYSCALL_PRE_READ_RANGE
+//          Called in prehook for regions that will be read by the kernel and
+//          must be initialized.
+//   COMMON_SYSCALL_PRE_WRITE_RANGE
+//          Called in prehook for regions that will be written to by the kernel
+//          and must be addressable. The actual write range may be smaller than
+//          reported in the prehook. See POST_WRITE_RANGE.
+//   COMMON_SYSCALL_POST_READ_RANGE
+//          Called in posthook for regions that were read by the kernel. Does
+//          not make much sense.
+//   COMMON_SYSCALL_POST_WRITE_RANGE
+//          Called in posthook for regions that were written to by the kernel
+//          and are now initialized.
+//===----------------------------------------------------------------------===//
+
+#define PRE_SYSCALL(name)                                                      \
+  SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_##name
+#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s)
+#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
+
+#define POST_SYSCALL(name)                                                     \
+  SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_##name
+#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)
+#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
+
+// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).
+
+extern "C" {
+struct sanitizer_kernel_iovec {
+  void *iov_base;
+  unsigned long iov_len;
+};
+
+struct sanitizer_kernel_msghdr {
+  void *msg_name;
+  int msg_namelen;
+  struct sanitizer_kernel_iovec *msg_iov;
+  unsigned long msg_iovlen;
+  void *msg_control;
+  unsigned long msg_controllen;
+  unsigned msg_flags;
+};
+
+struct sanitizer_kernel_timespec {
+  long tv_sec;
+  long tv_nsec;
+};
+
+struct sanitizer_kernel_timeval {
+  long tv_sec;
+  long tv_usec;
+};
+
+struct sanitizer_kernel_rusage {
+  struct sanitizer_kernel_timeval ru_timeval[2];
+  long ru_long[14];
+};
+
+PRE_SYSCALL(recvmsg)(int sockfd, struct sanitizer_kernel_msghdr *msg,
+                     int flags) {
+  PRE_READ(msg, sizeof(*msg));
+}
+
+POST_SYSCALL(recvmsg)(long res, int sockfd, struct sanitizer_kernel_msghdr *msg,
+                      int flags) {
+  if (res > 0)
+    for (unsigned long i = 0; i < msg->msg_iovlen; ++i) {
+      POST_WRITE(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
+    }
+  POST_WRITE(msg->msg_control, msg->msg_controllen);
+}
+
+PRE_SYSCALL(rt_sigpending)(void *p, unsigned long s) { PRE_WRITE(p, s); }
+
+POST_SYSCALL(rt_sigpending)(long res, void *p, unsigned long s) {
+  if (res == 0) {
+    POST_WRITE(p, s);
+  }
+}
+
+PRE_SYSCALL(getdents)(int fd, void *dirp, int count) { PRE_WRITE(dirp, count); }
+
+POST_SYSCALL(getdents)(long res, int fd, void *dirp, int count) {
+  if (res > 0) {
+    POST_WRITE(dirp, res);
+  }
+}
+
+PRE_SYSCALL(getdents64)(int fd, void *dirp, int count) {
+  PRE_WRITE(dirp, count);
+}
+
+POST_SYSCALL(getdents64)(long res, int fd, void *dirp, int count) {
+  if (res > 0) {
+    POST_WRITE(dirp, res);
+  }
+}
+
+PRE_SYSCALL(wait4)(int pid, int *status, int options,
+                   struct sanitizer_kernel_rusage *r) {
+  if (status) {
+    PRE_WRITE(status, sizeof(*status));
+  }
+  if (r) {
+    PRE_WRITE(r, sizeof(*r));
+  }
+}
+
+POST_SYSCALL(wait4)(long res, int pid, int *status, int options,
+                    struct sanitizer_kernel_rusage *r) {
+  if (res > 0) {
+    if (status) {
+      POST_WRITE(status, sizeof(*status));
+    }
+    if (r) {
+      POST_WRITE(r, sizeof(*r));
+    }
+  }
+}
+
+PRE_SYSCALL(waitpid)(int pid, int *status, int options) {
+  if (status) {
+    PRE_WRITE(status, sizeof(*status));
+  }
+}
+
+POST_SYSCALL(waitpid)(long res, int pid, int *status, int options) {
+  if (res > 0 && status) {
+    POST_WRITE(status, sizeof(*status));
+  }
+}
+
+PRE_SYSCALL(clock_gettime)(int clk_id, struct sanitizer_kernel_timespec *tp) {
+  if (tp) {
+    PRE_WRITE(tp, sizeof(*tp));
+  }
+}
+
+POST_SYSCALL(clock_gettime)(long res, int clk_id,
+                            struct sanitizer_kernel_timespec *tp) {
+  if (res == 0 && tp) {
+    POST_WRITE(tp, sizeof(*tp));
+  }
+}
+
+PRE_SYSCALL(clock_getres)(int clk_id, struct sanitizer_kernel_timespec *tp) {
+  if (tp) {
+    PRE_WRITE(tp, sizeof(*tp));
+  }
+}
+
+POST_SYSCALL(clock_getres)(long res, int clk_id,
+                           struct sanitizer_kernel_timespec *tp) {
+  if (res == 0 && tp) {
+    POST_WRITE(tp, sizeof(*tp));
+  }
+}
+
+PRE_SYSCALL(read)(unsigned int fd, void *buf, uptr count) {
+  if (buf) {
+    PRE_WRITE(buf, count);
+  }
+}
+
+POST_SYSCALL(read)(long res, unsigned int fd, void *buf, uptr count) {
+  if (res > 0 && buf) {
+    POST_WRITE(buf, res);
+  }
+}
+}  // extern "C"
+
+#undef PRE_SYSCALL
+#undef PRE_READ
+#undef PRE_WRITE
+#undef POST_SYSCALL
+#undef POST_READ
+#undef POST_WRITE
diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc
index 2ef4278..6ca3247 100644
--- a/lib/sanitizer_common/sanitizer_flags.cc
+++ b/lib/sanitizer_common/sanitizer_flags.cc
@@ -18,15 +18,39 @@
 
 namespace __sanitizer {
 
+CommonFlags common_flags_dont_use_directly;
+
+void ParseCommonFlagsFromString(const char *str) {
+  CommonFlags *f = common_flags();
+  ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
+  ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
+  ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal");
+  ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc");
+  ParseFlag(str, &f->symbolize, "symbolize");
+  ParseFlag(str, &f->handle_ioctl, "handle_ioctl");
+  ParseFlag(str, &f->log_path, "log_path");
+  ParseFlag(str, &f->detect_leaks, "detect_leaks");
+  ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit");
+}
+
 static bool GetFlagValue(const char *env, const char *name,
                          const char **value, int *value_length) {
   if (env == 0)
     return false;
-  const char *pos = internal_strstr(env, name);
-  const char *end;
-  if (pos == 0)
-    return false;
+  const char *pos = 0;
+  for (;;) {
+    pos = internal_strstr(env, name);
+    if (pos == 0)
+      return false;
+    if (pos != env && ((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) {
+      // Seems to be middle of another flag name or value.
+      env = pos + 1;
+      continue;
+    }
+    break;
+  }
   pos += internal_strlen(name);
+  const char *end;
   if (pos[0] != '=') {
     end = pos;
   } else {
@@ -77,7 +101,7 @@
   int value_length;
   if (!GetFlagValue(env, name, &value, &value_length))
     return;
-  *flag = internal_atoll(value);
+  *flag = static_cast<int>(internal_atoll(value));
 }
 
 static LowLevelAllocator allocator_for_flags;
diff --git a/lib/sanitizer_common/sanitizer_flags.h b/lib/sanitizer_common/sanitizer_flags.h
index b7ce452..d1a2961 100644
--- a/lib/sanitizer_common/sanitizer_flags.h
+++ b/lib/sanitizer_common/sanitizer_flags.h
@@ -22,6 +22,39 @@
 void ParseFlag(const char *env, int *flag, const char *name);
 void ParseFlag(const char *env, const char **flag, const char *name);
 
+struct CommonFlags {
+  // If set, use the online symbolizer from common sanitizer runtime.
+  bool symbolize;
+  // Path to external symbolizer.
+  const char *external_symbolizer_path;
+  // Strips this prefix from file paths in error reports.
+  const char *strip_path_prefix;
+  // Use fast (frame-pointer-based) unwinder on fatal errors (if available).
+  bool fast_unwind_on_fatal;
+  // Use fast (frame-pointer-based) unwinder on malloc/free (if available).
+  bool fast_unwind_on_malloc;
+  // Intercept and handle ioctl requests.
+  bool handle_ioctl;
+  // Max number of stack frames kept for each allocation/deallocation.
+  int malloc_context_size;
+  // Write logs to "log_path.pid" instead of stderr.
+  const char *log_path;
+  // Enable memory leak detection.
+  bool detect_leaks;
+  // Invoke leak checking in an atexit handler. Has no effect if
+  // detect_leaks=false, or if __lsan_do_leak_check() is called before the
+  // handler has a chance to run.
+  bool leak_check_at_exit;
+};
+
+extern CommonFlags common_flags_dont_use_directly;
+
+inline CommonFlags *common_flags() {
+  return &common_flags_dont_use_directly;
+}
+
+void ParseCommonFlagsFromString(const char *str);
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_FLAGS_H
diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h
index e052cbd..3e2c6d1 100644
--- a/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -13,7 +13,9 @@
 #ifndef SANITIZER_DEFS_H
 #define SANITIZER_DEFS_H
 
-#if defined(_WIN32)
+#include "sanitizer_platform.h"
+
+#if SANITIZER_WINDOWS
 // FIXME find out what we need on Windows. __declspec(dllexport) ?
 # define SANITIZER_INTERFACE_ATTRIBUTE
 # define SANITIZER_WEAK_ATTRIBUTE
@@ -25,7 +27,7 @@
 # define SANITIZER_WEAK_ATTRIBUTE  __attribute__((weak))
 #endif
 
-#ifdef __linux__
+#if SANITIZER_LINUX && !defined(SANITIZER_GO)
 # define SANITIZER_SUPPORTS_WEAK_HOOKS 1
 #else
 # define SANITIZER_SUPPORTS_WEAK_HOOKS 0
@@ -70,7 +72,7 @@
 // _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls
 // like pread and mmap, as opposed to pread64 and mmap64.
 // Mac and Linux/x86-64 are special.
-#if defined(__APPLE__) || (defined(__linux__) && defined(__x86_64__))
+#if SANITIZER_MAC || (SANITIZER_LINUX && defined(__x86_64__))
 typedef u64 OFF_T;
 #else
 typedef uptr OFF_T;
@@ -107,13 +109,13 @@
 // This header should NOT include any other headers to avoid portability issues.
 
 // Common defs.
-#define INLINE static inline
+#define INLINE inline
 #define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
 #define WEAK SANITIZER_WEAK_ATTRIBUTE
 
 // Platform-specific defs.
 #if defined(_MSC_VER)
-# define ALWAYS_INLINE __declspec(forceinline)
+# define ALWAYS_INLINE __forceinline
 // FIXME(timurrrr): do we need this on Windows?
 # define ALIAS(x)
 # define ALIGNED(x) __declspec(align(x))
@@ -128,8 +130,10 @@
 # define USED
 # define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */
 #else  // _MSC_VER
-# define ALWAYS_INLINE __attribute__((always_inline))
+# define ALWAYS_INLINE inline __attribute__((always_inline))
 # define ALIAS(x) __attribute__((alias(x)))
+// Please only use the ALIGNED macro before the type.
+// Using ALIGNED after the variable declaration is not portable!
 # define ALIGNED(x) __attribute__((aligned(x)))
 # define FORMAT(f, a)  __attribute__((format(printf, f, a)))
 # define NOINLINE __attribute__((noinline))
@@ -148,7 +152,15 @@
 # endif
 #endif  // _MSC_VER
 
-#if defined(_WIN32)
+// Unaligned versions of basic types.
+typedef ALIGNED(1) u16 uu16;
+typedef ALIGNED(1) u32 uu32;
+typedef ALIGNED(1) u64 uu64;
+typedef ALIGNED(1) s16 us16;
+typedef ALIGNED(1) s32 us32;
+typedef ALIGNED(1) s64 us64;
+
+#if SANITIZER_WINDOWS
 typedef unsigned long DWORD;  // NOLINT
 typedef DWORD thread_return_t;
 # define THREAD_CALLING_CONV __stdcall
@@ -271,10 +283,12 @@
 # define GET_CURRENT_FRAME() (uptr)0xDEADBEEF
 #endif
 
-#define HANDLE_EINTR(res, f) {                               \
-  do {                                                                  \
-    res = (f);                                                         \
-  } while (res == -1 && errno == EINTR); \
+#define HANDLE_EINTR(res, f)                                       \
+  {                                                                \
+    int rverrno;                                                   \
+    do {                                                           \
+      res = (f);                                                   \
+    } while (internal_iserror(res, &rverrno) && rverrno == EINTR); \
   }
 
 #endif  // SANITIZER_DEFS_H
diff --git a/lib/sanitizer_common/sanitizer_libc.cc b/lib/sanitizer_common/sanitizer_libc.cc
index 20c03c4..f875f1f 100644
--- a/lib/sanitizer_common/sanitizer_libc.cc
+++ b/lib/sanitizer_common/sanitizer_libc.cc
@@ -10,6 +10,7 @@
 // This file is shared between AddressSanitizer and ThreadSanitizer
 // run-time libraries. See sanitizer_libc.h for details.
 //===----------------------------------------------------------------------===//
+#include "sanitizer_allocator_internal.h"
 #include "sanitizer_common.h"
 #include "sanitizer_libc.h"
 
diff --git a/lib/sanitizer_common/sanitizer_libc.h b/lib/sanitizer_common/sanitizer_libc.h
index 7c2a1b8..82d809a 100644
--- a/lib/sanitizer_common/sanitizer_libc.h
+++ b/lib/sanitizer_common/sanitizer_libc.h
@@ -53,41 +53,46 @@
 
 
 // Memory
-void *internal_mmap(void *addr, uptr length, int prot, int flags,
-                    int fd, u64 offset);
-int internal_munmap(void *addr, uptr length);
+uptr internal_mmap(void *addr, uptr length, int prot, int flags,
+                   int fd, u64 offset);
+uptr internal_munmap(void *addr, uptr length);
 
 // I/O
 const fd_t kInvalidFd = -1;
 const fd_t kStdinFd = 0;
 const fd_t kStdoutFd = 1;
 const fd_t kStderrFd = 2;
-int internal_close(fd_t fd);
+uptr internal_close(fd_t fd);
 int internal_isatty(fd_t fd);
 
 // Use __sanitizer::OpenFile() instead.
-fd_t internal_open(const char *filename, int flags);
-fd_t internal_open(const char *filename, int flags, u32 mode);
+uptr internal_open(const char *filename, int flags);
+uptr internal_open(const char *filename, int flags, u32 mode);
 
 uptr internal_read(fd_t fd, void *buf, uptr count);
 uptr internal_write(fd_t fd, const void *buf, uptr count);
 
 // OS
 uptr internal_filesize(fd_t fd);  // -1 on error.
-int internal_stat(const char *path, void *buf);
-int internal_lstat(const char *path, void *buf);
-int internal_fstat(fd_t fd, void *buf);
-int internal_dup2(int oldfd, int newfd);
+uptr internal_stat(const char *path, void *buf);
+uptr internal_lstat(const char *path, void *buf);
+uptr internal_fstat(fd_t fd, void *buf);
+uptr internal_dup2(int oldfd, int newfd);
 uptr internal_readlink(const char *path, char *buf, uptr bufsize);
+uptr internal_unlink(const char *path);
 void NORETURN internal__exit(int exitcode);
-OFF_T internal_lseek(fd_t fd, OFF_T offset, int whence);
+uptr internal_lseek(fd_t fd, OFF_T offset, int whence);
 
-long internal_ptrace(int request, int pid, void *addr, void *data);
-int internal_waitpid(int pid, int *status, int options);
-int internal_getppid();
+uptr internal_ptrace(int request, int pid, void *addr, void *data);
+uptr internal_waitpid(int pid, int *status, int options);
+uptr internal_getpid();
+uptr internal_getppid();
 
 // Threading
-int internal_sched_yield();
+uptr internal_sched_yield();
+
+// Error handling
+bool internal_iserror(uptr retval, int *rverrno = 0);
 
 }  // namespace __sanitizer
 
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index dd36ca3..57aae1a 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -11,7 +11,9 @@
 // run-time libraries and implements linux-specific functions from
 // sanitizer_libc.h.
 //===----------------------------------------------------------------------===//
-#ifdef __linux__
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
@@ -21,10 +23,13 @@
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
 #include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
 
+#include <asm/param.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <link.h>
 #include <pthread.h>
 #include <sched.h>
 #include <sys/mman.h>
@@ -34,14 +39,19 @@
 #include <sys/syscall.h>
 #include <sys/time.h>
 #include <sys/types.h>
-#include <sys/prctl.h>
 #include <unistd.h>
 #include <unwind.h>
 
-#if !defined(__ANDROID__) && !defined(ANDROID)
+#if !SANITIZER_ANDROID
 #include <sys/signal.h>
 #endif
 
+// <linux/time.h>
+struct kernel_timeval {
+  long tv_sec;
+  long tv_usec;
+};
+
 // <linux/futex.h> is broken on some linux distributions.
 const int FUTEX_WAIT = 0;
 const int FUTEX_WAKE = 1;
@@ -57,165 +67,158 @@
 
 namespace __sanitizer {
 
+#ifdef __x86_64__
+#include "sanitizer_syscall_linux_x86_64.inc"
+#else
+#include "sanitizer_syscall_generic.inc"
+#endif
+
 // --------------- sanitizer_libc.h
-void *internal_mmap(void *addr, uptr length, int prot, int flags,
+uptr internal_mmap(void *addr, uptr length, int prot, int flags,
                     int fd, u64 offset) {
 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
+  return internal_syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
 #else
-  return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
+  return internal_syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
 #endif
 }
 
-int internal_munmap(void *addr, uptr length) {
-  return syscall(__NR_munmap, addr, length);
+uptr internal_munmap(void *addr, uptr length) {
+  return internal_syscall(__NR_munmap, addr, length);
 }
 
-int internal_close(fd_t fd) {
-  return syscall(__NR_close, fd);
+uptr internal_close(fd_t fd) {
+  return internal_syscall(__NR_close, fd);
 }
 
-fd_t internal_open(const char *filename, int flags) {
-  return syscall(__NR_open, filename, flags);
+uptr internal_open(const char *filename, int flags) {
+  return internal_syscall(__NR_open, filename, flags);
 }
 
-fd_t internal_open(const char *filename, int flags, u32 mode) {
-  return syscall(__NR_open, filename, flags, mode);
+uptr internal_open(const char *filename, int flags, u32 mode) {
+  return internal_syscall(__NR_open, filename, flags, mode);
 }
 
-fd_t OpenFile(const char *filename, bool write) {
+uptr OpenFile(const char *filename, bool write) {
   return internal_open(filename,
       write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
 }
 
 uptr internal_read(fd_t fd, void *buf, uptr count) {
   sptr res;
-  HANDLE_EINTR(res, (sptr)syscall(__NR_read, fd, buf, count));
+  HANDLE_EINTR(res, (sptr)internal_syscall(__NR_read, fd, buf, count));
   return res;
 }
 
 uptr internal_write(fd_t fd, const void *buf, uptr count) {
   sptr res;
-  HANDLE_EINTR(res, (sptr)syscall(__NR_write, fd, buf, count));
+  HANDLE_EINTR(res, (sptr)internal_syscall(__NR_write, fd, buf, count));
   return res;
 }
 
-int internal_stat(const char *path, void *buf) {
+#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS
+static void stat64_to_stat(struct stat64 *in, struct stat *out) {
+  internal_memset(out, 0, sizeof(*out));
+  out->st_dev = in->st_dev;
+  out->st_ino = in->st_ino;
+  out->st_mode = in->st_mode;
+  out->st_nlink = in->st_nlink;
+  out->st_uid = in->st_uid;
+  out->st_gid = in->st_gid;
+  out->st_rdev = in->st_rdev;
+  out->st_size = in->st_size;
+  out->st_blksize = in->st_blksize;
+  out->st_blocks = in->st_blocks;
+  out->st_atime = in->st_atime;
+  out->st_mtime = in->st_mtime;
+  out->st_ctime = in->st_ctime;
+  out->st_ino = in->st_ino;
+}
+#endif
+
+uptr internal_stat(const char *path, void *buf) {
 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return syscall(__NR_stat, path, buf);
+  return internal_syscall(__NR_stat, path, buf);
 #else
-  return syscall(__NR_stat64, path, buf);
+  struct stat64 buf64;
+  int res = internal_syscall(__NR_stat64, path, &buf64);
+  stat64_to_stat(&buf64, (struct stat *)buf);
+  return res;
 #endif
 }
 
-int internal_lstat(const char *path, void *buf) {
+uptr internal_lstat(const char *path, void *buf) {
 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return syscall(__NR_lstat, path, buf);
+  return internal_syscall(__NR_lstat, path, buf);
 #else
-  return syscall(__NR_lstat64, path, buf);
+  struct stat64 buf64;
+  int res = internal_syscall(__NR_lstat64, path, &buf64);
+  stat64_to_stat(&buf64, (struct stat *)buf);
+  return res;
 #endif
 }
 
-int internal_fstat(fd_t fd, void *buf) {
+uptr internal_fstat(fd_t fd, void *buf) {
 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return syscall(__NR_fstat, fd, buf);
+  return internal_syscall(__NR_fstat, fd, buf);
 #else
-  return syscall(__NR_fstat64, fd, buf);
+  struct stat64 buf64;
+  int res = internal_syscall(__NR_fstat64, fd, &buf64);
+  stat64_to_stat(&buf64, (struct stat *)buf);
+  return res;
 #endif
 }
 
 uptr internal_filesize(fd_t fd) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
   struct stat st;
-#else
-  struct stat64 st;
-#endif
   if (internal_fstat(fd, &st))
     return -1;
   return (uptr)st.st_size;
 }
 
-int internal_dup2(int oldfd, int newfd) {
-  return syscall(__NR_dup2, oldfd, newfd);
+uptr internal_dup2(int oldfd, int newfd) {
+  return internal_syscall(__NR_dup2, oldfd, newfd);
 }
 
 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
-  return (uptr)syscall(__NR_readlink, path, buf, bufsize);
+  return internal_syscall(__NR_readlink, path, buf, bufsize);
 }
 
-int internal_sched_yield() {
-  return syscall(__NR_sched_yield);
+uptr internal_unlink(const char *path) {
+  return internal_syscall(__NR_unlink, path);
+}
+
+uptr internal_sched_yield() {
+  return internal_syscall(__NR_sched_yield);
 }
 
 void internal__exit(int exitcode) {
-  syscall(__NR_exit_group, exitcode);
+  internal_syscall(__NR_exit_group, exitcode);
   Die();  // Unreachable.
 }
 
+uptr internal_execve(const char *filename, char *const argv[],
+                     char *const envp[]) {
+  return internal_syscall(__NR_execve, filename, argv, envp);
+}
+
 // ----------------- sanitizer_common.h
 bool FileExists(const char *filename) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
   struct stat st;
-  if (syscall(__NR_stat, filename, &st))
+  if (internal_stat(filename, &st))
     return false;
-#else
-  struct stat64 st;
-  if (syscall(__NR_stat64, filename, &st))
-    return false;
-#endif
   // Sanity check: filename is a regular file.
   return S_ISREG(st.st_mode);
 }
 
 uptr GetTid() {
-  return syscall(__NR_gettid);
+  return internal_syscall(__NR_gettid);
 }
 
-void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
-                                uptr *stack_bottom) {
-  static const uptr kMaxThreadStackSize = 256 * (1 << 20);  // 256M
-  CHECK(stack_top);
-  CHECK(stack_bottom);
-  if (at_initialization) {
-    // This is the main thread. Libpthread may not be initialized yet.
-    struct rlimit rl;
-    CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
-
-    // Find the mapping that contains a stack variable.
-    MemoryMappingLayout proc_maps;
-    uptr start, end, offset;
-    uptr prev_end = 0;
-    while (proc_maps.Next(&start, &end, &offset, 0, 0, /* protection */0)) {
-      if ((uptr)&rl < end)
-        break;
-      prev_end = end;
-    }
-    CHECK((uptr)&rl >= start && (uptr)&rl < end);
-
-    // Get stacksize from rlimit, but clip it so that it does not overlap
-    // with other mappings.
-    uptr stacksize = rl.rlim_cur;
-    if (stacksize > end - prev_end)
-      stacksize = end - prev_end;
-    // When running with unlimited stack size, we still want to set some limit.
-    // The unlimited stack size is caused by 'ulimit -s unlimited'.
-    // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
-    if (stacksize > kMaxThreadStackSize)
-      stacksize = kMaxThreadStackSize;
-    *stack_top = end;
-    *stack_bottom = end - stacksize;
-    return;
-  }
-  pthread_attr_t attr;
-  CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
-  uptr stacksize = 0;
-  void *stackaddr = 0;
-  pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
-  pthread_attr_destroy(&attr);
-
-  *stack_top = (uptr)stackaddr + stacksize;
-  *stack_bottom = (uptr)stackaddr;
-  CHECK(stacksize < kMaxThreadStackSize);  // Sanity check.
+u64 NanoTime() {
+  kernel_timeval tv = {};
+  internal_syscall(__NR_gettimeofday, &tv, 0);
+  return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
 }
 
 // Like getenv, but reads env directly from /proc and does not use libc.
@@ -246,21 +249,11 @@
   return 0;  // Not found.
 }
 
-#ifdef __GLIBC__
-
 extern "C" {
-  extern void *__libc_stack_end;
+  extern void *__libc_stack_end SANITIZER_WEAK_ATTRIBUTE;
 }
 
-static void GetArgsAndEnv(char ***argv, char ***envp) {
-  uptr *stack_end = (uptr *)__libc_stack_end;
-  int argc = *stack_end;
-  *argv = (char**)(stack_end + 1);
-  *envp = (char**)(stack_end + argc + 2);
-}
-
-#else  // __GLIBC__
-
+#if !SANITIZER_GO
 static void ReadNullSepFileToArray(const char *path, char ***arr,
                                    int arr_size) {
   char *buff;
@@ -279,20 +272,32 @@
   }
   (*arr)[count] = 0;
 }
+#endif
 
-static void GetArgsAndEnv(char ***argv, char ***envp) {
-  static const int kMaxArgv = 2000, kMaxEnvp = 2000;
-  ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
-  ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
+static void GetArgsAndEnv(char*** argv, char*** envp) {
+#if !SANITIZER_GO
+  if (&__libc_stack_end) {
+#endif
+    uptr* stack_end = (uptr*)__libc_stack_end;
+    int argc = *stack_end;
+    *argv = (char**)(stack_end + 1);
+    *envp = (char**)(stack_end + argc + 2);
+#if !SANITIZER_GO
+  } else {
+    static const int kMaxArgv = 2000, kMaxEnvp = 2000;
+    ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
+    ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
+  }
+#endif
 }
 
-#endif  // __GLIBC__
-
 void ReExec() {
   char **argv, **envp;
   GetArgsAndEnv(&argv, &envp);
-  execve("/proc/self/exe", argv, envp);
-  Printf("execve failed, errno %d\n", errno);
+  uptr rv = internal_execve("/proc/self/exe", argv, envp);
+  int rverrno;
+  CHECK_EQ(internal_iserror(rv, &rverrno), true);
+  Printf("execve failed, errno %d\n", rverrno);
   Die();
 }
 
@@ -302,6 +307,8 @@
   // process will be able to load additional libraries, so it's fine to use the
   // cached mappings.
   MemoryMappingLayout::CacheMemoryMappings();
+  // Same for /proc/self/exe in the symbolizer.
+  SymbolizerPrepareForSandboxing();
 }
 
 // ----------------- sanitizer_procmaps.h
@@ -309,18 +316,22 @@
 ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
 StaticSpinMutex MemoryMappingLayout::cache_lock_;  // Linker initialized.
 
-MemoryMappingLayout::MemoryMappingLayout() {
+MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
   proc_self_maps_.len =
       ReadFileToBuffer("/proc/self/maps", &proc_self_maps_.data,
                        &proc_self_maps_.mmaped_size, 1 << 26);
-  if (proc_self_maps_.mmaped_size == 0) {
-    LoadFromCache();
-    CHECK_GT(proc_self_maps_.len, 0);
+  if (cache_enabled) {
+    if (proc_self_maps_.mmaped_size == 0) {
+      LoadFromCache();
+      CHECK_GT(proc_self_maps_.len, 0);
+    }
+  } else {
+    CHECK_GT(proc_self_maps_.mmaped_size, 0);
   }
-  // internal_write(2, proc_self_maps_.data, proc_self_maps_.len);
   Reset();
   // FIXME: in the future we may want to cache the mappings on demand only.
-  CacheMemoryMappings();
+  if (cache_enabled)
+    CacheMemoryMappings();
 }
 
 MemoryMappingLayout::~MemoryMappingLayout() {
@@ -432,7 +443,9 @@
   CHECK_EQ(*current_++, ' ');
   while (IsDecimal(*current_))
     current_++;
-  CHECK_EQ(*current_++, ' ');
+  // Qemu may lack the trailing space.
+  // http://code.google.com/p/address-sanitizer/issues/detail?id=160
+  // CHECK_EQ(*current_++, ' ');
   // Skip spaces.
   while (current_ < next_line && *current_ == ' ')
     current_++;
@@ -458,83 +471,6 @@
                                        protection);
 }
 
-bool SanitizerSetThreadName(const char *name) {
-#ifdef PR_SET_NAME
-  return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);  // NOLINT
-#else
-  return false;
-#endif
-}
-
-bool SanitizerGetThreadName(char *name, int max_len) {
-#ifdef PR_GET_NAME
-  char buff[17];
-  if (prctl(PR_GET_NAME, (unsigned long)buff, 0, 0, 0))  // NOLINT
-    return false;
-  internal_strncpy(name, buff, max_len);
-  name[max_len] = 0;
-  return true;
-#else
-  return false;
-#endif
-}
-
-#ifndef SANITIZER_GO
-//------------------------- SlowUnwindStack -----------------------------------
-#ifdef __arm__
-#define UNWIND_STOP _URC_END_OF_STACK
-#define UNWIND_CONTINUE _URC_NO_REASON
-#else
-#define UNWIND_STOP _URC_NORMAL_STOP
-#define UNWIND_CONTINUE _URC_NO_REASON
-#endif
-
-uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
-#ifdef __arm__
-  uptr val;
-  _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
-      15 /* r15 = PC */, _UVRSD_UINT32, &val);
-  CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
-  // Clear the Thumb bit.
-  return val & ~(uptr)1;
-#else
-  return _Unwind_GetIP(ctx);
-#endif
-}
-
-_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
-  StackTrace *b = (StackTrace*)param;
-  CHECK(b->size < b->max_size);
-  uptr pc = Unwind_GetIP(ctx);
-  b->trace[b->size++] = pc;
-  if (b->size == b->max_size) return UNWIND_STOP;
-  return UNWIND_CONTINUE;
-}
-
-static bool MatchPc(uptr cur_pc, uptr trace_pc) {
-  return cur_pc - trace_pc <= 64 || trace_pc - cur_pc <= 64;
-}
-
-void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
-  this->size = 0;
-  this->max_size = max_depth;
-  if (max_depth > 1) {
-    _Unwind_Backtrace(Unwind_Trace, this);
-    // We need to pop a few frames so that pc is on top.
-    // trace[0] belongs to the current function so we always pop it.
-    int to_pop = 1;
-    /**/ if (size > 1 && MatchPc(pc, trace[1])) to_pop = 1;
-    else if (size > 2 && MatchPc(pc, trace[2])) to_pop = 2;
-    else if (size > 3 && MatchPc(pc, trace[3])) to_pop = 3;
-    else if (size > 4 && MatchPc(pc, trace[4])) to_pop = 4;
-    else if (size > 5 && MatchPc(pc, trace[5])) to_pop = 5;
-    this->PopStackFrames(to_pop);
-  }
-  this->trace[0] = pc;
-}
-
-#endif  // #ifndef SANITIZER_GO
-
 enum MutexState {
   MtxUnlocked = 0,
   MtxLocked = 1,
@@ -554,7 +490,7 @@
   if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
     return;
   while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked)
-    syscall(__NR_futex, m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
+    internal_syscall(__NR_futex, m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
 }
 
 void BlockingMutex::Unlock() {
@@ -562,7 +498,7 @@
   u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
   CHECK_NE(v, MtxUnlocked);
   if (v == MtxSleeping)
-    syscall(__NR_futex, m, FUTEX_WAKE, 1, 0, 0, 0);
+    internal_syscall(__NR_futex, m, FUTEX_WAKE, 1, 0, 0, 0);
 }
 
 void BlockingMutex::CheckLocked() {
@@ -582,52 +518,57 @@
 };
 
 // Syscall wrappers.
-long internal_ptrace(int request, int pid, void *addr, void *data) {
-  return syscall(__NR_ptrace, request, pid, addr, data);
+uptr internal_ptrace(int request, int pid, void *addr, void *data) {
+  return internal_syscall(__NR_ptrace, request, pid, addr, data);
 }
 
-int internal_waitpid(int pid, int *status, int options) {
-  return syscall(__NR_wait4, pid, status, options, NULL /* rusage */);
+uptr internal_waitpid(int pid, int *status, int options) {
+  return internal_syscall(__NR_wait4, pid, status, options, 0 /* rusage */);
 }
 
-int internal_getppid() {
-  return syscall(__NR_getppid);
+uptr internal_getpid() {
+  return internal_syscall(__NR_getpid);
 }
 
-int internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
-  return syscall(__NR_getdents, fd, dirp, count);
+uptr internal_getppid() {
+  return internal_syscall(__NR_getppid);
 }
 
-OFF_T internal_lseek(fd_t fd, OFF_T offset, int whence) {
-  return syscall(__NR_lseek, fd, offset, whence);
+uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
+  return internal_syscall(__NR_getdents, fd, dirp, count);
 }
 
-int internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
-  return syscall(__NR_prctl, option, arg2, arg3, arg4, arg5);
+uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
+  return internal_syscall(__NR_lseek, fd, offset, whence);
 }
 
-int internal_sigaltstack(const struct sigaltstack *ss,
+uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
+  return internal_syscall(__NR_prctl, option, arg2, arg3, arg4, arg5);
+}
+
+uptr internal_sigaltstack(const struct sigaltstack *ss,
                          struct sigaltstack *oss) {
-  return syscall(__NR_sigaltstack, ss, oss);
+  return internal_syscall(__NR_sigaltstack, ss, oss);
 }
 
-
 // ThreadLister implementation.
 ThreadLister::ThreadLister(int pid)
   : pid_(pid),
     descriptor_(-1),
+    buffer_(4096),
     error_(true),
-    entry_((linux_dirent *)buffer_),
+    entry_((struct linux_dirent *)buffer_.data()),
     bytes_read_(0) {
   char task_directory_path[80];
   internal_snprintf(task_directory_path, sizeof(task_directory_path),
                     "/proc/%d/task/", pid);
-  descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
-  if (descriptor_ < 0) {
+  uptr openrv = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
+  if (internal_iserror(openrv)) {
     error_ = true;
     Report("Can't open /proc/%d/task for reading.\n", pid);
   } else {
     error_ = false;
+    descriptor_ = openrv;
   }
 }
 
@@ -665,47 +606,77 @@
   CHECK_GE(descriptor_, 0);
   CHECK_NE(error_, true);
   bytes_read_ = internal_getdents(descriptor_,
-                                  (struct linux_dirent *)buffer_,
-                                  sizeof(buffer_));
-  if (bytes_read_ < 0) {
+                                  (struct linux_dirent *)buffer_.data(),
+                                  buffer_.size());
+  if (internal_iserror(bytes_read_)) {
     Report("Can't read directory entries from /proc/%d/task.\n", pid_);
     error_ = true;
     return false;
   } else if (bytes_read_ == 0) {
     return false;
   }
-  entry_ = (struct linux_dirent *)buffer_;
+  entry_ = (struct linux_dirent *)buffer_.data();
   return true;
 }
 
-static uptr g_tls_size;
-
-#ifdef __i386__
-# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
+uptr GetPageSize() {
+#if defined(__x86_64__) || defined(__i386__)
+  return EXEC_PAGESIZE;
 #else
-# define DL_INTERNAL_FUNCTION
-#endif
-
-void InitTlsSize() {
-#ifndef SANITIZER_GO
-  typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
-  get_tls_func get_tls;
-  void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
-  CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr));
-  internal_memcpy(&get_tls, &get_tls_static_info_ptr,
-                  sizeof(get_tls_static_info_ptr));
-  CHECK_NE(get_tls, 0);
-  size_t tls_size = 0;
-  size_t tls_align = 0;
-  get_tls(&tls_size, &tls_align);
-  g_tls_size = tls_size;
+  return sysconf(_SC_PAGESIZE);  // EXEC_PAGESIZE may not be trustworthy.
 #endif
 }
 
-uptr GetTlsSize() {
-  return g_tls_size;
+// Match full names of the form /path/to/base_name{-,.}*
+bool LibraryNameIs(const char *full_name, const char *base_name) {
+  const char *name = full_name;
+  // Strip path.
+  while (*name != '\0') name++;
+  while (name > full_name && *name != '/') name--;
+  if (*name == '/') name++;
+  uptr base_name_length = internal_strlen(base_name);
+  if (internal_strncmp(name, base_name, base_name_length)) return false;
+  return (name[base_name_length] == '-' || name[base_name_length] == '.');
 }
 
+#if !SANITIZER_ANDROID
+// Call cb for each region mapped by map.
+void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
+  typedef ElfW(Phdr) Elf_Phdr;
+  typedef ElfW(Ehdr) Elf_Ehdr;
+  char *base = (char *)map->l_addr;
+  Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
+  char *phdrs = base + ehdr->e_phoff;
+  char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
+
+  // Find the segment with the minimum base so we can "relocate" the p_vaddr
+  // fields.  Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
+  // objects have a non-zero base.
+  uptr preferred_base = (uptr)-1;
+  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
+    Elf_Phdr *phdr = (Elf_Phdr *)iter;
+    if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr)
+      preferred_base = (uptr)phdr->p_vaddr;
+  }
+
+  // Compute the delta from the real base to get a relocation delta.
+  sptr delta = (uptr)base - preferred_base;
+  // Now we can figure out what the loader really mapped.
+  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
+    Elf_Phdr *phdr = (Elf_Phdr *)iter;
+    if (phdr->p_type == PT_LOAD) {
+      uptr seg_start = phdr->p_vaddr + delta;
+      uptr seg_end = seg_start + phdr->p_memsz;
+      // None of these values are aligned.  We consider the ragged edges of the
+      // load command as defined, since they are mapped from the file.
+      seg_start = RoundDownTo(seg_start, GetPageSizeCached());
+      seg_end = RoundUpTo(seg_end, GetPageSizeCached());
+      cb((void *)seg_start, seg_end - seg_start);
+    }
+  }
+}
+#endif
+
 }  // namespace __sanitizer
 
-#endif  // __linux__
+#endif  // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index b4ac310..edb95fe 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -13,8 +13,10 @@
 #ifndef SANITIZER_LINUX_H
 #define SANITIZER_LINUX_H
 
+#include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 
+struct link_map;  // Opaque type returned by dlopen().
 struct sigaltstack;
 
 namespace __sanitizer {
@@ -23,9 +25,10 @@
 struct linux_dirent;
 
 // Syscall wrappers.
-int internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
-int internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
-int internal_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
+uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
+uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
+uptr internal_sigaltstack(const struct sigaltstack* ss,
+                          struct sigaltstack* oss);
 
 // This class reads thread IDs from /proc/<pid>/task using only syscalls.
 class ThreadLister {
@@ -43,11 +46,29 @@
 
   int pid_;
   int descriptor_;
-  char buffer_[4096];
+  InternalScopedBuffer<char> buffer_;
   bool error_;
   struct linux_dirent* entry_;
   int bytes_read_;
 };
+
+void AdjustStackSizeLinux(void *attr, int verbosity);
+
+// Exposed for testing.
+uptr ThreadDescriptorSize();
+uptr ThreadSelf();
+uptr ThreadSelfOffset();
+
+// Matches a library's file name against a base name (stripping path and version
+// information).
+bool LibraryNameIs(const char *full_name, const char *base_name);
+
+// Read the name of the current binary from /proc/self/exe.
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
+
+// Call cb for each region mapped by map.
+void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_LINUX_H
diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
new file mode 100644
index 0000000..2f9b685
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -0,0 +1,290 @@
+//===-- sanitizer_linux_libcdep.cc ----------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and implements linux-specific functions from
+// sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include "sanitizer_common.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <unwind.h>
+
+namespace __sanitizer {
+
+void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
+                                uptr *stack_bottom) {
+  static const uptr kMaxThreadStackSize = 1 << 30;  // 1Gb
+  CHECK(stack_top);
+  CHECK(stack_bottom);
+  if (at_initialization) {
+    // This is the main thread. Libpthread may not be initialized yet.
+    struct rlimit rl;
+    CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
+
+    // Find the mapping that contains a stack variable.
+    MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+    uptr start, end, offset;
+    uptr prev_end = 0;
+    while (proc_maps.Next(&start, &end, &offset, 0, 0, /* protection */0)) {
+      if ((uptr)&rl < end)
+        break;
+      prev_end = end;
+    }
+    CHECK((uptr)&rl >= start && (uptr)&rl < end);
+
+    // Get stacksize from rlimit, but clip it so that it does not overlap
+    // with other mappings.
+    uptr stacksize = rl.rlim_cur;
+    if (stacksize > end - prev_end)
+      stacksize = end - prev_end;
+    // When running with unlimited stack size, we still want to set some limit.
+    // The unlimited stack size is caused by 'ulimit -s unlimited'.
+    // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
+    if (stacksize > kMaxThreadStackSize)
+      stacksize = kMaxThreadStackSize;
+    *stack_top = end;
+    *stack_bottom = end - stacksize;
+    return;
+  }
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
+  uptr stacksize = 0;
+  void *stackaddr = 0;
+  pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
+  pthread_attr_destroy(&attr);
+
+  CHECK_LE(stacksize, kMaxThreadStackSize);  // Sanity check.
+  *stack_top = (uptr)stackaddr + stacksize;
+  *stack_bottom = (uptr)stackaddr;
+}
+
+// Does not compile for Go because dlsym() requires -ldl
+#ifndef SANITIZER_GO
+bool SetEnv(const char *name, const char *value) {
+  void *f = dlsym(RTLD_NEXT, "setenv");
+  if (f == 0)
+    return false;
+  typedef int(*setenv_ft)(const char *name, const char *value, int overwrite);
+  setenv_ft setenv_f;
+  CHECK_EQ(sizeof(setenv_f), sizeof(f));
+  internal_memcpy(&setenv_f, &f, sizeof(f));
+  return setenv_f(name, value, 1) == 0;
+}
+#endif
+
+bool SanitizerSetThreadName(const char *name) {
+#ifdef PR_SET_NAME
+  return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);  // NOLINT
+#else
+  return false;
+#endif
+}
+
+bool SanitizerGetThreadName(char *name, int max_len) {
+#ifdef PR_GET_NAME
+  char buff[17];
+  if (prctl(PR_GET_NAME, (unsigned long)buff, 0, 0, 0))  // NOLINT
+    return false;
+  internal_strncpy(name, buff, max_len);
+  name[max_len] = 0;
+  return true;
+#else
+  return false;
+#endif
+}
+
+#ifndef SANITIZER_GO
+//------------------------- SlowUnwindStack -----------------------------------
+#ifdef __arm__
+#define UNWIND_STOP _URC_END_OF_STACK
+#define UNWIND_CONTINUE _URC_NO_REASON
+#else
+#define UNWIND_STOP _URC_NORMAL_STOP
+#define UNWIND_CONTINUE _URC_NO_REASON
+#endif
+
+uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
+#ifdef __arm__
+  uptr val;
+  _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
+      15 /* r15 = PC */, _UVRSD_UINT32, &val);
+  CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
+  // Clear the Thumb bit.
+  return val & ~(uptr)1;
+#else
+  return _Unwind_GetIP(ctx);
+#endif
+}
+
+_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
+  StackTrace *b = (StackTrace*)param;
+  CHECK(b->size < b->max_size);
+  uptr pc = Unwind_GetIP(ctx);
+  b->trace[b->size++] = pc;
+  if (b->size == b->max_size) return UNWIND_STOP;
+  return UNWIND_CONTINUE;
+}
+
+static bool MatchPc(uptr cur_pc, uptr trace_pc) {
+  return cur_pc - trace_pc <= 64 || trace_pc - cur_pc <= 64;
+}
+
+void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
+  this->size = 0;
+  this->max_size = max_depth;
+  if (max_depth > 1) {
+    _Unwind_Backtrace(Unwind_Trace, this);
+    // We need to pop a few frames so that pc is on top.
+    // trace[0] belongs to the current function so we always pop it.
+    int to_pop = 1;
+    /**/ if (size > 1 && MatchPc(pc, trace[1])) to_pop = 1;
+    else if (size > 2 && MatchPc(pc, trace[2])) to_pop = 2;
+    else if (size > 3 && MatchPc(pc, trace[3])) to_pop = 3;
+    else if (size > 4 && MatchPc(pc, trace[4])) to_pop = 4;
+    else if (size > 5 && MatchPc(pc, trace[5])) to_pop = 5;
+    this->PopStackFrames(to_pop);
+  }
+  this->trace[0] = pc;
+}
+
+#endif  // !SANITIZER_GO
+
+static uptr g_tls_size;
+
+#ifdef __i386__
+# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
+#else
+# define DL_INTERNAL_FUNCTION
+#endif
+
+void InitTlsSize() {
+#if !defined(SANITIZER_GO) && !SANITIZER_ANDROID
+  typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
+  get_tls_func get_tls;
+  void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
+  CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr));
+  internal_memcpy(&get_tls, &get_tls_static_info_ptr,
+                  sizeof(get_tls_static_info_ptr));
+  CHECK_NE(get_tls, 0);
+  size_t tls_size = 0;
+  size_t tls_align = 0;
+  get_tls(&tls_size, &tls_align);
+  g_tls_size = tls_size;
+#endif
+}
+
+uptr GetTlsSize() {
+  return g_tls_size;
+}
+
+#if defined(__x86_64__) || defined(__i386__)
+// sizeof(struct thread) from glibc.
+// There has been a report of this being different on glibc 2.11. We don't know
+// when this change happened, so 2.12 is a conservative estimate.
+#if __GLIBC_PREREQ(2, 12)
+const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1216, 2304);
+#else
+const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1168, 2304);
+#endif
+
+uptr ThreadDescriptorSize() {
+  return kThreadDescriptorSize;
+}
+
+// The offset at which pointer to self is located in the thread descriptor.
+const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
+
+uptr ThreadSelfOffset() {
+  return kThreadSelfOffset;
+}
+
+uptr ThreadSelf() {
+  uptr descr_addr;
+#ifdef __i386__
+  asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
+#else
+  asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
+#endif
+  return descr_addr;
+}
+#endif  // defined(__x86_64__) || defined(__i386__)
+
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+                          uptr *tls_addr, uptr *tls_size) {
+#ifndef SANITIZER_GO
+#if defined(__x86_64__) || defined(__i386__)
+  *tls_addr = ThreadSelf();
+  *tls_size = GetTlsSize();
+  *tls_addr -= *tls_size;
+  *tls_addr += kThreadDescriptorSize;
+#else
+  *tls_addr = 0;
+  *tls_size = 0;
+#endif
+
+  uptr stack_top, stack_bottom;
+  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
+  *stk_addr = stack_bottom;
+  *stk_size = stack_top - stack_bottom;
+
+  if (!main) {
+    // If stack and tls intersect, make them non-intersecting.
+    if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
+      CHECK_GT(*tls_addr + *tls_size, *stk_addr);
+      CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
+      *stk_size -= *tls_size;
+      *tls_addr = *stk_addr + *stk_size;
+    }
+  }
+#else  // SANITIZER_GO
+  *stk_addr = 0;
+  *stk_size = 0;
+  *tls_addr = 0;
+  *tls_size = 0;
+#endif  // SANITIZER_GO
+}
+
+void AdjustStackSizeLinux(void *attr_, int verbosity) {
+  pthread_attr_t *attr = (pthread_attr_t *)attr_;
+  uptr stackaddr = 0;
+  size_t stacksize = 0;
+  pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
+  // GLibC will return (0 - stacksize) as the stack address in the case when
+  // stacksize is set, but stackaddr is not.
+  bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0);
+  // We place a lot of tool data into TLS, account for that.
+  const uptr minstacksize = GetTlsSize() + 128*1024;
+  if (stacksize < minstacksize) {
+    if (!stack_set) {
+      if (verbosity && stacksize != 0)
+        Printf("Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
+               minstacksize);
+      pthread_attr_setstacksize(attr, minstacksize);
+    } else {
+      Printf("Sanitizer: pre-allocated stack size is insufficient: "
+             "%zu < %zu\n", stacksize, minstacksize);
+      Printf("Sanitizer: pthread_create is likely to fail.\n");
+    }
+  }
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index 3990f26..ea87128 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -12,7 +12,9 @@
 // sanitizer_libc.h.
 //===----------------------------------------------------------------------===//
 
-#ifdef __APPLE__
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+
 // Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
 // the clients will most certainly use 64-bit ones as well.
 #ifndef _DARWIN_USE_64_BIT_INODE
@@ -37,32 +39,35 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <libkern/OSAtomic.h>
+#include <errno.h>
 
 namespace __sanitizer {
 
+#include "sanitizer_syscall_generic.inc"
+
 // ---------------------- sanitizer_libc.h
-void *internal_mmap(void *addr, size_t length, int prot, int flags,
-                    int fd, u64 offset) {
-  return mmap(addr, length, prot, flags, fd, offset);
+uptr internal_mmap(void *addr, size_t length, int prot, int flags,
+                   int fd, u64 offset) {
+  return (uptr)mmap(addr, length, prot, flags, fd, offset);
 }
 
-int internal_munmap(void *addr, uptr length) {
+uptr internal_munmap(void *addr, uptr length) {
   return munmap(addr, length);
 }
 
-int internal_close(fd_t fd) {
+uptr internal_close(fd_t fd) {
   return close(fd);
 }
 
-fd_t internal_open(const char *filename, int flags) {
+uptr internal_open(const char *filename, int flags) {
   return open(filename, flags);
 }
 
-fd_t internal_open(const char *filename, int flags, u32 mode) {
+uptr internal_open(const char *filename, int flags, u32 mode) {
   return open(filename, flags, mode);
 }
 
-fd_t OpenFile(const char *filename, bool write) {
+uptr OpenFile(const char *filename, bool write) {
   return internal_open(filename,
       write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
 }
@@ -75,15 +80,15 @@
   return write(fd, buf, count);
 }
 
-int internal_stat(const char *path, void *buf) {
+uptr internal_stat(const char *path, void *buf) {
   return stat(path, (struct stat *)buf);
 }
 
-int internal_lstat(const char *path, void *buf) {
+uptr internal_lstat(const char *path, void *buf) {
   return lstat(path, (struct stat *)buf);
 }
 
-int internal_fstat(fd_t fd, void *buf) {
+uptr internal_fstat(fd_t fd, void *buf) {
   return fstat(fd, (struct stat *)buf);
 }
 
@@ -94,7 +99,7 @@
   return (uptr)st.st_size;
 }
 
-int internal_dup2(int oldfd, int newfd) {
+uptr internal_dup2(int oldfd, int newfd) {
   return dup2(oldfd, newfd);
 }
 
@@ -102,7 +107,7 @@
   return readlink(path, buf, bufsize);
 }
 
-int internal_sched_yield() {
+uptr internal_sched_yield() {
   return sched_yield();
 }
 
@@ -110,6 +115,10 @@
   _exit(exitcode);
 }
 
+uptr internal_getpid() {
+  return getpid();
+}
+
 // ----------------- sanitizer_common.h
 bool FileExists(const char *filename) {
   struct stat st;
@@ -161,9 +170,13 @@
   // Nothing here for now.
 }
 
+uptr GetPageSize() {
+  return sysconf(_SC_PAGESIZE);
+}
+
 // ----------------- sanitizer_procmaps.h
 
-MemoryMappingLayout::MemoryMappingLayout() {
+MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
   Reset();
 }
 
@@ -330,6 +343,10 @@
   CHECK_EQ((uptr)pthread_self(), owner_);
 }
 
+u64 NanoTime() {
+  return 0;
+}
+
 uptr GetTlsSize() {
   return 0;
 }
@@ -337,6 +354,23 @@
 void InitTlsSize() {
 }
 
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+                          uptr *tls_addr, uptr *tls_size) {
+#ifndef SANITIZER_GO
+  uptr stack_top, stack_bottom;
+  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
+  *stk_addr = stack_bottom;
+  *stk_size = stack_top - stack_bottom;
+  *tls_addr = 0;
+  *tls_size = 0;
+#else
+  *stk_addr = 0;
+  *stk_size = 0;
+  *tls_addr = 0;
+  *tls_size = 0;
+#endif
+}
+
 }  // namespace __sanitizer
 
-#endif  // __APPLE__
+#endif  // SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_placement_new.h b/lib/sanitizer_common/sanitizer_placement_new.h
index c0b85e1..a42301a 100644
--- a/lib/sanitizer_common/sanitizer_placement_new.h
+++ b/lib/sanitizer_common/sanitizer_placement_new.h
@@ -19,7 +19,7 @@
 #include "sanitizer_internal_defs.h"
 
 namespace __sanitizer {
-#if (SANITIZER_WORDSIZE == 64) || defined(__APPLE__)
+#if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC
 typedef uptr operator_new_ptr_type;
 #else
 typedef u32 operator_new_ptr_type;
diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h
new file mode 100644
index 0000000..acb9971
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_platform.h
@@ -0,0 +1,46 @@
+//===-- sanitizer_platform.h ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common platform macros.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PLATFORM_H
+#define SANITIZER_PLATFORM_H
+
+#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
+# error "This operating system is not supported"
+#endif
+
+#if defined(__linux__)
+# define SANITIZER_LINUX   1
+#else
+# define SANITIZER_LINUX   0
+#endif
+
+#if defined(__APPLE__)
+# define SANITIZER_MAC     1
+#else
+# define SANITIZER_MAC     0
+#endif
+
+#if defined(_WIN32)
+# define SANITIZER_WINDOWS 1
+#else
+# define SANITIZER_WINDOWS 0
+#endif
+
+#if defined(__ANDROID__) || defined(ANDROID)
+# define SANITIZER_ANDROID 1
+#else
+# define SANITIZER_ANDROID 0
+#endif
+
+#define SANITIZER_POSIX (SANITIZER_LINUX || SANITIZER_MAC)
+
+#endif // SANITIZER_PLATFORM_H
diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 63a54d1..e3aaf21 100644
--- a/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -11,35 +11,55 @@
 // given library functions on a given platform.
 //
 //===----------------------------------------------------------------------===//
+#ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
+#define SANITIZER_PLATFORM_INTERCEPTORS_H
 
 #include "sanitizer_internal_defs.h"
 
-#if !defined(_WIN32)
+#if !SANITIZER_WINDOWS
 # define SI_NOT_WINDOWS 1
 # include "sanitizer_platform_limits_posix.h"
 #else
 # define SI_NOT_WINDOWS 0
 #endif
 
-#if defined(__linux__) && !defined(ANDROID)
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
 # define SI_LINUX_NOT_ANDROID 1
 #else
 # define SI_LINUX_NOT_ANDROID 0
 #endif
 
-#if defined(__linux__)
+#if SANITIZER_LINUX
 # define SI_LINUX 1
 #else
 # define SI_LINUX 0
 #endif
 
+#if SANITIZER_MAC
+# define SI_MAC 1
+#else
+# define SI_MAC 0
+#endif
+
+# define SANITIZER_INTERCEPT_STRCMP 1
+# define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
+
 # define SANITIZER_INTERCEPT_READ   SI_NOT_WINDOWS
 # define SANITIZER_INTERCEPT_PREAD  SI_NOT_WINDOWS
 # define SANITIZER_INTERCEPT_WRITE  SI_NOT_WINDOWS
 # define SANITIZER_INTERCEPT_PWRITE SI_NOT_WINDOWS
 
-# define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_READV SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_WRITEV SI_NOT_WINDOWS
+
+#define SANITIZER_INTERCEPT_PREADV SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID
+
 # define SANITIZER_INTERCEPT_PRCTL   SI_LINUX
 
 # define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_NOT_WINDOWS
@@ -49,3 +69,47 @@
 
 # define SANITIZER_INTERCEPT_FREXP 1
 # define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_NOT_WINDOWS
+
+# define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
+    SI_MAC || SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_LINUX
+# define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_WAIT SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_INET SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GETADDRINFO SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GETNAMEINFO SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GETHOSTBYNAME_R SI_LINUX
+# define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX
+# define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_IOCTL SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_INET_ATON SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_SYSINFO SI_LINUX
+# define SANITIZER_INTERCEPT_READDIR SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \
+  (defined(__i386) || defined (__x86_64))  // NOLINT
+# define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX
+# define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_WCSNRTOMBS SI_MAC || SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX
+# define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_CONFSTR SI_MAC || SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
+
+#endif  // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index 1046b62..b60b99b 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -12,25 +12,91 @@
 // Sizes and layouts of platform-specific POSIX data structures.
 //===----------------------------------------------------------------------===//
 
-#if defined(__linux__) || defined(__APPLE__)
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX || SANITIZER_MAC
 
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_platform_limits_posix.h"
 
+#include <arpa/inet.h>
 #include <dirent.h>
+#include <grp.h>
+#include <limits.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/route.h>
+#include <netdb.h>
 #include <pthread.h>
-#include <sys/utsname.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stddef.h>
 #include <sys/resource.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <termios.h>
 #include <time.h>
+#include <wchar.h>
 
-#if defined(__linux__)
+#if SANITIZER_LINUX
+#include <sys/mount.h>
+#include <sys/ptrace.h>
+#include <sys/sysinfo.h>
+#include <sys/vt.h>
+#include <linux/cdrom.h>
+#include <linux/fd.h>
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <linux/input.h>
+#include <linux/ioctl.h>
+#include <linux/soundcard.h>
+#endif
+
+#if !SANITIZER_ANDROID
+#include <sys/ucontext.h>
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#include <glob.h>
+#include <net/if_ppp.h>
+#include <netax25/ax25.h>
+#include <netipx/ipx.h>
+#include <netrom/netrom.h>
+#include <scsi/scsi.h>
+#include <sys/mtio.h>
+#include <sys/kd.h>
+#include <sys/user.h>
+#include <linux/cyclades.h>
+#include <linux/if_eql.h>
+#include <linux/if_plip.h>
+#include <linux/lp.h>
+#include <linux/mroute.h>
+#include <linux/mroute6.h>
+#include <linux/scc.h>
+#include <linux/serial.h>
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if SANITIZER_ANDROID
+#include <linux/kd.h>
+#include <linux/mtio.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#endif
+
+#if SANITIZER_LINUX
+#include <link.h>
 #include <sys/vfs.h>
 #include <sys/epoll.h>
-#endif // __linux__
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_MAC
+#include <netinet/ip_mroute.h>
+#include <sys/filio.h>
+#include <sys/sockio.h>
+#endif
 
 namespace __sanitizer {
   unsigned struct_utsname_sz = sizeof(struct utsname);
@@ -38,37 +104,716 @@
   unsigned struct_stat64_sz = sizeof(struct stat64);
   unsigned struct_rusage_sz = sizeof(struct rusage);
   unsigned struct_tm_sz = sizeof(struct tm);
+  unsigned struct_passwd_sz = sizeof(struct passwd);
+  unsigned struct_group_sz = sizeof(struct group);
+  unsigned siginfo_t_sz = sizeof(siginfo_t);
+  unsigned struct_sigaction_sz = sizeof(struct sigaction);
+  unsigned struct_itimerval_sz = sizeof(struct itimerval);
+  unsigned pthread_t_sz = sizeof(pthread_t);
+  unsigned pid_t_sz = sizeof(pid_t);
+  unsigned timeval_sz = sizeof(timeval);
+  unsigned uid_t_sz = sizeof(uid_t);
+  unsigned mbstate_t_sz = sizeof(mbstate_t);
 
-#if defined(__linux__)
+#if !SANITIZER_ANDROID
+  unsigned ucontext_t_sz = sizeof(ucontext_t);
+#endif // !SANITIZER_ANDROID
+
+#if SANITIZER_LINUX
   unsigned struct_rlimit_sz = sizeof(struct rlimit);
-  unsigned struct_dirent_sz = sizeof(struct dirent);
   unsigned struct_statfs_sz = sizeof(struct statfs);
   unsigned struct_epoll_event_sz = sizeof(struct epoll_event);
-#endif // __linux__
+  unsigned struct_sysinfo_sz = sizeof(struct sysinfo);
+  unsigned struct_timespec_sz = sizeof(struct timespec);
+#endif // SANITIZER_LINUX
 
-#if defined(__linux__) && !defined(__ANDROID__)
-  unsigned struct_dirent64_sz = sizeof(struct dirent64);
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
   unsigned struct_statfs64_sz = sizeof(struct statfs64);
-#endif // __linux__ && !__ANDROID__
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
 
-  void* __sanitizer_get_msghdr_iov_iov_base(void* msg, int idx) {
-    return ((struct msghdr *)msg)->msg_iov[idx].iov_base;
+  uptr sig_ign = (uptr)SIG_IGN;
+  uptr sig_dfl = (uptr)SIG_DFL;
+
+#if SANITIZER_LINUX
+  int e_tabsz = (int)E_TABSZ;
+#endif
+
+  uptr __sanitizer_get_sigaction_sa_sigaction(void *act) {
+    struct sigaction *a = (struct sigaction *)act;
+    // Check that sa_sigaction and sa_handler are the same.
+    CHECK((void *)&(a->sa_sigaction) == (void *)&(a->sa_handler));
+    return (uptr) a->sa_sigaction;
+  }
+  void __sanitizer_set_sigaction_sa_sigaction(void *act, uptr cb) {
+    struct sigaction *a = (struct sigaction *)act;
+    a->sa_sigaction = (void (*)(int, siginfo_t *, void *))cb;
+  }
+  bool __sanitizer_get_sigaction_sa_siginfo(void *act) {
+    struct sigaction *a = (struct sigaction *)act;
+    return a->sa_flags & SA_SIGINFO;
   }
 
-  uptr __sanitizer_get_msghdr_iov_iov_len(void* msg, int idx) {
-    return ((struct msghdr *)msg)->msg_iov[idx].iov_len;
+  int af_inet = (int)AF_INET;
+  int af_inet6 = (int)AF_INET6;
+
+  uptr __sanitizer_in_addr_sz(int af) {
+    if (af == AF_INET)
+      return sizeof(struct in_addr);
+    else if (af == AF_INET6)
+      return sizeof(struct in6_addr);
+    else
+      return 0;
   }
 
-  uptr __sanitizer_get_msghdr_iovlen(void* msg) {
-    return ((struct msghdr *)msg)->msg_iovlen;
-  }
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  int glob_nomatch = GLOB_NOMATCH;
+  int glob_altdirfunc = GLOB_ALTDIRFUNC;
+#endif
 
-  uptr __sanitizer_get_socklen_t(void* socklen_ptr) {
-    return *(socklen_t*)socklen_ptr;
-  }
+#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
+      (defined(__i386) || defined (__x86_64))  // NOLINT
+  unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct);
+  unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
+#if __WORDSIZE == 64
+  unsigned struct_user_fpxregs_struct_sz = 0;
+#else
+  unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
+#endif
+
+  int ptrace_getregs = PTRACE_GETREGS;
+  int ptrace_setregs = PTRACE_SETREGS;
+  int ptrace_getfpregs = PTRACE_GETFPREGS;
+  int ptrace_setfpregs = PTRACE_SETFPREGS;
+  int ptrace_getfpxregs = PTRACE_GETFPXREGS;
+  int ptrace_setfpxregs = PTRACE_SETFPXREGS;
+  int ptrace_getsiginfo = PTRACE_GETSIGINFO;
+  int ptrace_setsiginfo = PTRACE_SETSIGINFO;
+#if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET)
+  int ptrace_getregset = PTRACE_GETREGSET;
+  int ptrace_setregset = PTRACE_SETREGSET;
+#else
+  int ptrace_getregset = -1;
+  int ptrace_setregset = -1;
+#endif
+#endif
+
+  unsigned path_max = PATH_MAX;
+
+  // ioctl arguments
+  unsigned struct_arpreq_sz = sizeof(struct arpreq);
+  unsigned struct_ifreq_sz = sizeof(struct ifreq);
+  unsigned struct_termios_sz = sizeof(struct termios);
+  unsigned struct_winsize_sz = sizeof(struct winsize);
+
+#if SANITIZER_LINUX
+  unsigned struct_cdrom_msf_sz = sizeof(struct cdrom_msf);
+  unsigned struct_cdrom_multisession_sz = sizeof(struct cdrom_multisession);
+  unsigned struct_cdrom_read_audio_sz = sizeof(struct cdrom_read_audio);
+  unsigned struct_cdrom_subchnl_sz = sizeof(struct cdrom_subchnl);
+  unsigned struct_cdrom_ti_sz = sizeof(struct cdrom_ti);
+  unsigned struct_cdrom_tocentry_sz = sizeof(struct cdrom_tocentry);
+  unsigned struct_cdrom_tochdr_sz = sizeof(struct cdrom_tochdr);
+  unsigned struct_cdrom_volctrl_sz = sizeof(struct cdrom_volctrl);
+#if SOUND_VERSION >= 0x040000
+  unsigned struct_copr_buffer_sz = 0;
+  unsigned struct_copr_debug_buf_sz = 0;
+  unsigned struct_copr_msg_sz = 0;
+#else
+  unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
+  unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
+  unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
+#endif
+  unsigned struct_ff_effect_sz = sizeof(struct ff_effect);
+  unsigned struct_floppy_drive_params_sz = sizeof(struct floppy_drive_params);
+  unsigned struct_floppy_drive_struct_sz = sizeof(struct floppy_drive_struct);
+  unsigned struct_floppy_fdc_state_sz = sizeof(struct floppy_fdc_state);
+  unsigned struct_floppy_max_errors_sz = sizeof(struct floppy_max_errors);
+  unsigned struct_floppy_raw_cmd_sz = sizeof(struct floppy_raw_cmd);
+  unsigned struct_floppy_struct_sz = sizeof(struct floppy_struct);
+  unsigned struct_floppy_write_errors_sz = sizeof(struct floppy_write_errors);
+  unsigned struct_format_descr_sz = sizeof(struct format_descr);
+  unsigned struct_hd_driveid_sz = sizeof(struct hd_driveid);
+  unsigned struct_hd_geometry_sz = sizeof(struct hd_geometry);
+  unsigned struct_input_absinfo_sz = sizeof(struct input_absinfo);
+  unsigned struct_input_id_sz = sizeof(struct input_id);
+  unsigned struct_midi_info_sz = sizeof(struct midi_info);
+  unsigned struct_mtget_sz = sizeof(struct mtget);
+  unsigned struct_mtop_sz = sizeof(struct mtop);
+  unsigned struct_mtpos_sz = sizeof(struct mtpos);
+  unsigned struct_rtentry_sz = sizeof(struct rtentry);
+  unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
+  unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
+  unsigned struct_synth_info_sz = sizeof(struct synth_info);
+  unsigned struct_termio_sz = sizeof(struct termio);
+  unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
+  unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
+  unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
+  unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
+  unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
+  unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor);
+#if EV_VERSION > (0x010000)
+  unsigned struct_input_keymap_entry_sz = sizeof(struct input_keymap_entry);
+#else
+  unsigned struct_input_keymap_entry_sz = 0;
+#endif
+  unsigned struct_ipx_config_data_sz = sizeof(struct ipx_config_data);
+  unsigned struct_kbdiacrs_sz = sizeof(struct kbdiacrs);
+  unsigned struct_kbentry_sz = sizeof(struct kbentry);
+  unsigned struct_kbkeycode_sz = sizeof(struct kbkeycode);
+  unsigned struct_kbsentry_sz = sizeof(struct kbsentry);
+  unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo);
+  unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct);
+  unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
+  unsigned struct_scc_modem_sz = sizeof(struct scc_modem);
+  unsigned struct_scc_stat_sz = sizeof(struct scc_stat);
+  unsigned struct_serial_multiport_struct_sz
+      = sizeof(struct serial_multiport_struct);
+  unsigned struct_serial_struct_sz = sizeof(struct serial_struct);
+  unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
+  unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
+  unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
+#endif
+
+#if !SANITIZER_ANDROID
+  unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
+  unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
+#endif
+
+  unsigned IOCTL_NOT_PRESENT = 0;
+
+  unsigned IOCTL_FIOASYNC = FIOASYNC;
+  unsigned IOCTL_FIOCLEX = FIOCLEX;
+  unsigned IOCTL_FIOGETOWN = FIOGETOWN;
+  unsigned IOCTL_FIONBIO = FIONBIO;
+  unsigned IOCTL_FIONCLEX = FIONCLEX;
+  unsigned IOCTL_FIOSETOWN = FIOSETOWN;
+  unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
+  unsigned IOCTL_SIOCATMARK = SIOCATMARK;
+  unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
+  unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
+  unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
+  unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
+  unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
+  unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
+  unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
+  unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
+  unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
+  unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
+  unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
+  unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
+  unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
+  unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
+  unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
+  unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
+  unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
+  unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
+  unsigned IOCTL_TIOCCONS = TIOCCONS;
+  unsigned IOCTL_TIOCEXCL = TIOCEXCL;
+  unsigned IOCTL_TIOCGETD = TIOCGETD;
+  unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
+  unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
+  unsigned IOCTL_TIOCMBIC = TIOCMBIC;
+  unsigned IOCTL_TIOCMBIS = TIOCMBIS;
+  unsigned IOCTL_TIOCMGET = TIOCMGET;
+  unsigned IOCTL_TIOCMSET = TIOCMSET;
+  unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
+  unsigned IOCTL_TIOCNXCL = TIOCNXCL;
+  unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
+  unsigned IOCTL_TIOCPKT = TIOCPKT;
+  unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
+  unsigned IOCTL_TIOCSETD = TIOCSETD;
+  unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
+  unsigned IOCTL_TIOCSTI = TIOCSTI;
+  unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_MAC
+  unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
+  unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
+#endif
+#if SANITIZER_LINUX
+  unsigned IOCTL_EVIOCGABS = EVIOCGABS(0);
+  unsigned IOCTL_EVIOCGBIT = EVIOCGBIT(0, 0);
+  unsigned IOCTL_EVIOCGEFFECTS = EVIOCGEFFECTS;
+  unsigned IOCTL_EVIOCGID = EVIOCGID;
+  unsigned IOCTL_EVIOCGKEY = EVIOCGKEY(0);
+  unsigned IOCTL_EVIOCGKEYCODE = EVIOCGKEYCODE;
+  unsigned IOCTL_EVIOCGLED = EVIOCGLED(0);
+  unsigned IOCTL_EVIOCGNAME = EVIOCGNAME(0);
+  unsigned IOCTL_EVIOCGPHYS = EVIOCGPHYS(0);
+  unsigned IOCTL_EVIOCGRAB = EVIOCGRAB;
+  unsigned IOCTL_EVIOCGREP = EVIOCGREP;
+  unsigned IOCTL_EVIOCGSND = EVIOCGSND(0);
+  unsigned IOCTL_EVIOCGSW = EVIOCGSW(0);
+  unsigned IOCTL_EVIOCGUNIQ = EVIOCGUNIQ(0);
+  unsigned IOCTL_EVIOCGVERSION = EVIOCGVERSION;
+  unsigned IOCTL_EVIOCRMFF = EVIOCRMFF;
+  unsigned IOCTL_EVIOCSABS = EVIOCSABS(0);
+  unsigned IOCTL_EVIOCSFF = EVIOCSFF;
+  unsigned IOCTL_EVIOCSKEYCODE = EVIOCSKEYCODE;
+  unsigned IOCTL_EVIOCSREP = EVIOCSREP;
+  unsigned IOCTL_BLKFLSBUF = BLKFLSBUF;
+  unsigned IOCTL_BLKGETSIZE = BLKGETSIZE;
+  unsigned IOCTL_BLKRAGET = BLKRAGET;
+  unsigned IOCTL_BLKRASET = BLKRASET;
+  unsigned IOCTL_BLKROGET = BLKROGET;
+  unsigned IOCTL_BLKROSET = BLKROSET;
+  unsigned IOCTL_BLKRRPART = BLKRRPART;
+  unsigned IOCTL_CDROMAUDIOBUFSIZ = CDROMAUDIOBUFSIZ;
+  unsigned IOCTL_CDROMEJECT = CDROMEJECT;
+  unsigned IOCTL_CDROMEJECT_SW = CDROMEJECT_SW;
+  unsigned IOCTL_CDROMMULTISESSION = CDROMMULTISESSION;
+  unsigned IOCTL_CDROMPAUSE = CDROMPAUSE;
+  unsigned IOCTL_CDROMPLAYMSF = CDROMPLAYMSF;
+  unsigned IOCTL_CDROMPLAYTRKIND = CDROMPLAYTRKIND;
+  unsigned IOCTL_CDROMREADAUDIO = CDROMREADAUDIO;
+  unsigned IOCTL_CDROMREADCOOKED = CDROMREADCOOKED;
+  unsigned IOCTL_CDROMREADMODE1 = CDROMREADMODE1;
+  unsigned IOCTL_CDROMREADMODE2 = CDROMREADMODE2;
+  unsigned IOCTL_CDROMREADRAW = CDROMREADRAW;
+  unsigned IOCTL_CDROMREADTOCENTRY = CDROMREADTOCENTRY;
+  unsigned IOCTL_CDROMREADTOCHDR = CDROMREADTOCHDR;
+  unsigned IOCTL_CDROMRESET = CDROMRESET;
+  unsigned IOCTL_CDROMRESUME = CDROMRESUME;
+  unsigned IOCTL_CDROMSEEK = CDROMSEEK;
+  unsigned IOCTL_CDROMSTART = CDROMSTART;
+  unsigned IOCTL_CDROMSTOP = CDROMSTOP;
+  unsigned IOCTL_CDROMSUBCHNL = CDROMSUBCHNL;
+  unsigned IOCTL_CDROMVOLCTRL = CDROMVOLCTRL;
+  unsigned IOCTL_CDROMVOLREAD = CDROMVOLREAD;
+  unsigned IOCTL_CDROM_GET_UPC = CDROM_GET_UPC;
+  unsigned IOCTL_FDCLRPRM = FDCLRPRM;
+  unsigned IOCTL_FDDEFPRM = FDDEFPRM;
+  unsigned IOCTL_FDFLUSH = FDFLUSH;
+  unsigned IOCTL_FDFMTBEG = FDFMTBEG;
+  unsigned IOCTL_FDFMTEND = FDFMTEND;
+  unsigned IOCTL_FDFMTTRK = FDFMTTRK;
+  unsigned IOCTL_FDGETDRVPRM = FDGETDRVPRM;
+  unsigned IOCTL_FDGETDRVSTAT = FDGETDRVSTAT;
+  unsigned IOCTL_FDGETDRVTYP = FDGETDRVTYP;
+  unsigned IOCTL_FDGETFDCSTAT = FDGETFDCSTAT;
+  unsigned IOCTL_FDGETMAXERRS = FDGETMAXERRS;
+  unsigned IOCTL_FDGETPRM = FDGETPRM;
+  unsigned IOCTL_FDMSGOFF = FDMSGOFF;
+  unsigned IOCTL_FDMSGON = FDMSGON;
+  unsigned IOCTL_FDPOLLDRVSTAT = FDPOLLDRVSTAT;
+  unsigned IOCTL_FDRAWCMD = FDRAWCMD;
+  unsigned IOCTL_FDRESET = FDRESET;
+  unsigned IOCTL_FDSETDRVPRM = FDSETDRVPRM;
+  unsigned IOCTL_FDSETEMSGTRESH = FDSETEMSGTRESH;
+  unsigned IOCTL_FDSETMAXERRS = FDSETMAXERRS;
+  unsigned IOCTL_FDSETPRM = FDSETPRM;
+  unsigned IOCTL_FDTWADDLE = FDTWADDLE;
+  unsigned IOCTL_FDWERRORCLR = FDWERRORCLR;
+  unsigned IOCTL_FDWERRORGET = FDWERRORGET;
+  unsigned IOCTL_HDIO_DRIVE_CMD = HDIO_DRIVE_CMD;
+  unsigned IOCTL_HDIO_GETGEO = HDIO_GETGEO;
+  unsigned IOCTL_HDIO_GET_32BIT = HDIO_GET_32BIT;
+  unsigned IOCTL_HDIO_GET_DMA = HDIO_GET_DMA;
+  unsigned IOCTL_HDIO_GET_IDENTITY = HDIO_GET_IDENTITY;
+  unsigned IOCTL_HDIO_GET_KEEPSETTINGS = HDIO_GET_KEEPSETTINGS;
+  unsigned IOCTL_HDIO_GET_MULTCOUNT = HDIO_GET_MULTCOUNT;
+  unsigned IOCTL_HDIO_GET_NOWERR = HDIO_GET_NOWERR;
+  unsigned IOCTL_HDIO_GET_UNMASKINTR = HDIO_GET_UNMASKINTR;
+  unsigned IOCTL_HDIO_SET_32BIT = HDIO_SET_32BIT;
+  unsigned IOCTL_HDIO_SET_DMA = HDIO_SET_DMA;
+  unsigned IOCTL_HDIO_SET_KEEPSETTINGS = HDIO_SET_KEEPSETTINGS;
+  unsigned IOCTL_HDIO_SET_MULTCOUNT = HDIO_SET_MULTCOUNT;
+  unsigned IOCTL_HDIO_SET_NOWERR = HDIO_SET_NOWERR;
+  unsigned IOCTL_HDIO_SET_UNMASKINTR = HDIO_SET_UNMASKINTR;
+  unsigned IOCTL_MTIOCGET = MTIOCGET;
+  unsigned IOCTL_MTIOCPOS = MTIOCPOS;
+  unsigned IOCTL_MTIOCTOP = MTIOCTOP;
+  unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP;
+  unsigned IOCTL_PPPIOCGDEBUG = PPPIOCGDEBUG;
+  unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS;
+  unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT;
+  unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP;
+  unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP;
+  unsigned IOCTL_PPPIOCSDEBUG = PPPIOCSDEBUG;
+  unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS;
+  unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID;
+  unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU;
+  unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP;
+  unsigned IOCTL_SIOCADDRT = SIOCADDRT;
+  unsigned IOCTL_SIOCDARP = SIOCDARP;
+  unsigned IOCTL_SIOCDELRT = SIOCDELRT;
+  unsigned IOCTL_SIOCDRARP = SIOCDRARP;
+  unsigned IOCTL_SIOCGARP = SIOCGARP;
+  unsigned IOCTL_SIOCGIFENCAP = SIOCGIFENCAP;
+  unsigned IOCTL_SIOCGIFHWADDR = SIOCGIFHWADDR;
+  unsigned IOCTL_SIOCGIFMAP = SIOCGIFMAP;
+  unsigned IOCTL_SIOCGIFMEM = SIOCGIFMEM;
+  unsigned IOCTL_SIOCGIFNAME = SIOCGIFNAME;
+  unsigned IOCTL_SIOCGIFSLAVE = SIOCGIFSLAVE;
+  unsigned IOCTL_SIOCGRARP = SIOCGRARP;
+  unsigned IOCTL_SIOCGSTAMP = SIOCGSTAMP;
+  unsigned IOCTL_SIOCSARP = SIOCSARP;
+  unsigned IOCTL_SIOCSIFENCAP = SIOCSIFENCAP;
+  unsigned IOCTL_SIOCSIFHWADDR = SIOCSIFHWADDR;
+  unsigned IOCTL_SIOCSIFLINK = SIOCSIFLINK;
+  unsigned IOCTL_SIOCSIFMAP = SIOCSIFMAP;
+  unsigned IOCTL_SIOCSIFMEM = SIOCSIFMEM;
+  unsigned IOCTL_SIOCSIFSLAVE = SIOCSIFSLAVE;
+  unsigned IOCTL_SIOCSRARP = SIOCSRARP;
+#if SOUND_VERSION >= 0x040000
+  unsigned IOCTL_SNDCTL_COPR_HALT = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SNDCTL_COPR_LOAD = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SNDCTL_COPR_RCODE = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SNDCTL_COPR_RCVMSG = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SNDCTL_COPR_RDATA = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SNDCTL_COPR_RESET = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SNDCTL_COPR_RUN = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SNDCTL_COPR_SENDMSG = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SNDCTL_COPR_WCODE = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SNDCTL_COPR_WDATA = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SOUND_PCM_READ_BITS = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SOUND_PCM_READ_CHANNELS = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SOUND_PCM_READ_FILTER = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SOUND_PCM_READ_RATE = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_SOUND_PCM_WRITE_FILTER = IOCTL_NOT_PRESENT;
+#else
+  unsigned IOCTL_SNDCTL_COPR_HALT = SNDCTL_COPR_HALT;
+  unsigned IOCTL_SNDCTL_COPR_LOAD = SNDCTL_COPR_LOAD;
+  unsigned IOCTL_SNDCTL_COPR_RCODE = SNDCTL_COPR_RCODE;
+  unsigned IOCTL_SNDCTL_COPR_RCVMSG = SNDCTL_COPR_RCVMSG;
+  unsigned IOCTL_SNDCTL_COPR_RDATA = SNDCTL_COPR_RDATA;
+  unsigned IOCTL_SNDCTL_COPR_RESET = SNDCTL_COPR_RESET;
+  unsigned IOCTL_SNDCTL_COPR_RUN = SNDCTL_COPR_RUN;
+  unsigned IOCTL_SNDCTL_COPR_SENDMSG = SNDCTL_COPR_SENDMSG;
+  unsigned IOCTL_SNDCTL_COPR_WCODE = SNDCTL_COPR_WCODE;
+  unsigned IOCTL_SNDCTL_COPR_WDATA = SNDCTL_COPR_WDATA;
+  unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS;
+  unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS;
+  unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER;
+  unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE;
+  unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = SOUND_PCM_WRITE_CHANNELS;
+  unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER;
+#endif
+  unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
+  unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
+  unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
+  unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
+  unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
+  unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
+  unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
+  unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
+  unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
+  unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
+  unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
+  unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
+  unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
+  unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
+  unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
+  unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
+  unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
+  unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
+  unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
+  unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
+  unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
+  unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
+  unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
+  unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
+  unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
+  unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
+  unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
+  unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
+  unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
+  unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
+  unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
+  unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
+  unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
+  unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
+  unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
+  unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
+  unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
+  unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
+  unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
+  unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
+  unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
+  unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
+  unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
+  unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
+  unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
+  unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
+  unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
+  unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
+  unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
+  unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
+  unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
+  unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
+  unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
+  unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
+  unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
+  unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
+  unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
+  unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
+  unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
+  unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS;
+  unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
+  unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
+  unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
+  unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
+  unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
+  unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
+  unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
+  unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
+  unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
+  unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
+  unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
+  unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
+  unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
+  unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
+  unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
+  unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
+  unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
+  unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
+  unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
+  unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
+  unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
+  unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
+  unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
+  unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
+  unsigned IOCTL_TCFLSH = TCFLSH;
+  unsigned IOCTL_TCGETA = TCGETA;
+  unsigned IOCTL_TCGETS = TCGETS;
+  unsigned IOCTL_TCSBRK = TCSBRK;
+  unsigned IOCTL_TCSBRKP = TCSBRKP;
+  unsigned IOCTL_TCSETA = TCSETA;
+  unsigned IOCTL_TCSETAF = TCSETAF;
+  unsigned IOCTL_TCSETAW = TCSETAW;
+  unsigned IOCTL_TCSETS = TCSETS;
+  unsigned IOCTL_TCSETSF = TCSETSF;
+  unsigned IOCTL_TCSETSW = TCSETSW;
+  unsigned IOCTL_TCXONC = TCXONC;
+  unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS;
+  unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR;
+  unsigned IOCTL_TIOCINQ = TIOCINQ;
+  unsigned IOCTL_TIOCLINUX = TIOCLINUX;
+  unsigned IOCTL_TIOCSERCONFIG = TIOCSERCONFIG;
+  unsigned IOCTL_TIOCSERGETLSR = TIOCSERGETLSR;
+  unsigned IOCTL_TIOCSERGWILD = TIOCSERGWILD;
+  unsigned IOCTL_TIOCSERSWILD = TIOCSERSWILD;
+  unsigned IOCTL_TIOCSLCKTRMIOS = TIOCSLCKTRMIOS;
+  unsigned IOCTL_TIOCSSOFTCAR = TIOCSSOFTCAR;
+  unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
+  unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE;
+  unsigned IOCTL_VT_GETMODE = VT_GETMODE;
+  unsigned IOCTL_VT_GETSTATE = VT_GETSTATE;
+  unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
+  unsigned IOCTL_VT_RELDISP = VT_RELDISP;
+  unsigned IOCTL_VT_RESIZE = VT_RESIZE;
+  unsigned IOCTL_VT_RESIZEX = VT_RESIZEX;
+  unsigned IOCTL_VT_SENDSIG = VT_SENDSIG;
+  unsigned IOCTL_VT_SETMODE = VT_SETMODE;
+  unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
+#endif
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH;
+  unsigned IOCTL_CYGETDEFTIMEOUT = CYGETDEFTIMEOUT;
+  unsigned IOCTL_CYGETMON = CYGETMON;
+  unsigned IOCTL_CYGETTHRESH = CYGETTHRESH;
+  unsigned IOCTL_CYGETTIMEOUT = CYGETTIMEOUT;
+  unsigned IOCTL_CYSETDEFTHRESH = CYSETDEFTHRESH;
+  unsigned IOCTL_CYSETDEFTIMEOUT = CYSETDEFTIMEOUT;
+  unsigned IOCTL_CYSETTHRESH = CYSETTHRESH;
+  unsigned IOCTL_CYSETTIMEOUT = CYSETTIMEOUT;
+  unsigned IOCTL_EQL_EMANCIPATE = EQL_EMANCIPATE;
+  unsigned IOCTL_EQL_ENSLAVE = EQL_ENSLAVE;
+  unsigned IOCTL_EQL_GETMASTRCFG = EQL_GETMASTRCFG;
+  unsigned IOCTL_EQL_GETSLAVECFG = EQL_GETSLAVECFG;
+  unsigned IOCTL_EQL_SETMASTRCFG = EQL_SETMASTRCFG;
+  unsigned IOCTL_EQL_SETSLAVECFG = EQL_SETSLAVECFG;
+#if EV_VERSION > (0x010000)
+  unsigned IOCTL_EVIOCGKEYCODE_V2 = EVIOCGKEYCODE_V2;
+  unsigned IOCTL_EVIOCGPROP = EVIOCGPROP(0);
+  unsigned IOCTL_EVIOCSKEYCODE_V2 = EVIOCSKEYCODE_V2;
+#else
+  unsigned IOCTL_EVIOCGKEYCODE_V2 = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_EVIOCGPROP = IOCTL_NOT_PRESENT;
+  unsigned IOCTL_EVIOCSKEYCODE_V2 = IOCTL_NOT_PRESENT;
+#endif
+  unsigned IOCTL_FS_IOC_GETFLAGS = FS_IOC_GETFLAGS;
+  unsigned IOCTL_FS_IOC_GETVERSION = FS_IOC_GETVERSION;
+  unsigned IOCTL_FS_IOC_SETFLAGS = FS_IOC_SETFLAGS;
+  unsigned IOCTL_FS_IOC_SETVERSION = FS_IOC_SETVERSION;
+  unsigned IOCTL_GIO_CMAP = GIO_CMAP;
+  unsigned IOCTL_GIO_FONT = GIO_FONT;
+  unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
+  unsigned IOCTL_GIO_UNIMAP = GIO_UNIMAP;
+  unsigned IOCTL_GIO_UNISCRNMAP = GIO_UNISCRNMAP;
+  unsigned IOCTL_KDADDIO = KDADDIO;
+  unsigned IOCTL_KDDELIO = KDDELIO;
+  unsigned IOCTL_KDDISABIO = KDDISABIO;
+  unsigned IOCTL_KDENABIO = KDENABIO;
+  unsigned IOCTL_KDGETKEYCODE = KDGETKEYCODE;
+  unsigned IOCTL_KDGETLED = KDGETLED;
+  unsigned IOCTL_KDGETMODE = KDGETMODE;
+  unsigned IOCTL_KDGKBDIACR = KDGKBDIACR;
+  unsigned IOCTL_KDGKBENT = KDGKBENT;
+  unsigned IOCTL_KDGKBLED = KDGKBLED;
+  unsigned IOCTL_KDGKBMETA = KDGKBMETA;
+  unsigned IOCTL_KDGKBMODE = KDGKBMODE;
+  unsigned IOCTL_KDGKBSENT = KDGKBSENT;
+  unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
+  unsigned IOCTL_KDMAPDISP = KDMAPDISP;
+  unsigned IOCTL_KDMKTONE = KDMKTONE;
+  unsigned IOCTL_KDSETKEYCODE = KDSETKEYCODE;
+  unsigned IOCTL_KDSETLED = KDSETLED;
+  unsigned IOCTL_KDSETMODE = KDSETMODE;
+  unsigned IOCTL_KDSIGACCEPT = KDSIGACCEPT;
+  unsigned IOCTL_KDSKBDIACR = KDSKBDIACR;
+  unsigned IOCTL_KDSKBENT = KDSKBENT;
+  unsigned IOCTL_KDSKBLED = KDSKBLED;
+  unsigned IOCTL_KDSKBMETA = KDSKBMETA;
+  unsigned IOCTL_KDSKBMODE = KDSKBMODE;
+  unsigned IOCTL_KDSKBSENT = KDSKBSENT;
+  unsigned IOCTL_KDUNMAPDISP = KDUNMAPDISP;
+  unsigned IOCTL_KIOCSOUND = KIOCSOUND;
+  unsigned IOCTL_LPABORT = LPABORT;
+  unsigned IOCTL_LPABORTOPEN = LPABORTOPEN;
+  unsigned IOCTL_LPCAREFUL = LPCAREFUL;
+  unsigned IOCTL_LPCHAR = LPCHAR;
+  unsigned IOCTL_LPGETIRQ = LPGETIRQ;
+  unsigned IOCTL_LPGETSTATUS = LPGETSTATUS;
+  unsigned IOCTL_LPRESET = LPRESET;
+  unsigned IOCTL_LPSETIRQ = LPSETIRQ;
+  unsigned IOCTL_LPTIME = LPTIME;
+  unsigned IOCTL_LPWAIT = LPWAIT;
+  unsigned IOCTL_MTIOCGETCONFIG = MTIOCGETCONFIG;
+  unsigned IOCTL_MTIOCSETCONFIG = MTIOCSETCONFIG;
+  unsigned IOCTL_PIO_CMAP = PIO_CMAP;
+  unsigned IOCTL_PIO_FONT = PIO_FONT;
+  unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
+  unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP;
+  unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR;
+  unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP;
+  unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN;
+  unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST;
+  unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE;
+  unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE = SCSI_IOCTL_TAGGED_ENABLE;
+  unsigned IOCTL_SIOCAIPXITFCRT = SIOCAIPXITFCRT;
+  unsigned IOCTL_SIOCAIPXPRISLT = SIOCAIPXPRISLT;
+  unsigned IOCTL_SIOCAX25ADDUID = SIOCAX25ADDUID;
+  unsigned IOCTL_SIOCAX25DELUID = SIOCAX25DELUID;
+  unsigned IOCTL_SIOCAX25GETPARMS = SIOCAX25GETPARMS;
+  unsigned IOCTL_SIOCAX25GETUID = SIOCAX25GETUID;
+  unsigned IOCTL_SIOCAX25NOUID = SIOCAX25NOUID;
+  unsigned IOCTL_SIOCAX25SETPARMS = SIOCAX25SETPARMS;
+  unsigned IOCTL_SIOCDEVPLIP = SIOCDEVPLIP;
+  unsigned IOCTL_SIOCIPXCFGDATA = SIOCIPXCFGDATA;
+  unsigned IOCTL_SIOCNRDECOBS = SIOCNRDECOBS;
+  unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS;
+  unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL;
+  unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS;
+  unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
+  unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE;
+  unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL;
+  unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
+  unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
+  unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL;
+#endif
 }  // namespace __sanitizer
 
-COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
+#define CHECK_TYPE_SIZE(TYPE) \
+  COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE))
 
-#endif  // __linux__ || __APPLE__
+#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER)                       \
+  COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \
+                 sizeof(((CLASS *) NULL)->MEMBER));                \
+  COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) ==          \
+                 offsetof(CLASS, MEMBER))
+
+COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
+COMPILER_CHECK(sizeof(__sanitizer::struct_sigaction_max_sz) >=
+                   sizeof(__sanitizer::struct_sigaction_sz));
+
+COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned));
+CHECK_TYPE_SIZE(pthread_key_t);
+
+#if SANITIZER_LINUX
+// There are more undocumented fields in dl_phdr_info that we are not interested
+// in.
+COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info));
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
+
+COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678));
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(glob_t);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_offs);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_flags);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
+#endif
+
+CHECK_TYPE_SIZE(addrinfo);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_family);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr);
+
+CHECK_TYPE_SIZE(hostent);
+CHECK_SIZE_AND_OFFSET(hostent, h_name);
+CHECK_SIZE_AND_OFFSET(hostent, h_aliases);
+CHECK_SIZE_AND_OFFSET(hostent, h_addrtype);
+CHECK_SIZE_AND_OFFSET(hostent, h_length);
+CHECK_SIZE_AND_OFFSET(hostent, h_addr_list);
+
+CHECK_TYPE_SIZE(iovec);
+CHECK_SIZE_AND_OFFSET(iovec, iov_base);
+CHECK_SIZE_AND_OFFSET(iovec, iov_len);
+
+CHECK_TYPE_SIZE(msghdr);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
+
+CHECK_TYPE_SIZE(cmsghdr);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
+
+COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));
+CHECK_SIZE_AND_OFFSET(dirent, d_ino);
+#if SANITIZER_MAC
+CHECK_SIZE_AND_OFFSET(dirent, d_seekoff);
+#else
+CHECK_SIZE_AND_OFFSET(dirent, d_off);
+#endif
+CHECK_SIZE_AND_OFFSET(dirent, d_reclen);
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64));
+CHECK_SIZE_AND_OFFSET(dirent64, d_ino);
+CHECK_SIZE_AND_OFFSET(dirent64, d_off);
+CHECK_SIZE_AND_OFFSET(dirent64, d_reclen);
+#endif
+
+CHECK_TYPE_SIZE(ifconf);
+CHECK_SIZE_AND_OFFSET(ifconf, ifc_len);
+CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu);
+
+#endif  // SANITIZER_LINUX || SANITIZER_MAC
+
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index 2eac016..e47f82e 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -15,30 +15,116 @@
 #ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H
 #define SANITIZER_PLATFORM_LIMITS_POSIX_H
 
+#include "sanitizer_platform.h"
+
 namespace __sanitizer {
   extern unsigned struct_utsname_sz;
   extern unsigned struct_stat_sz;
   extern unsigned struct_stat64_sz;
   extern unsigned struct_rusage_sz;
   extern unsigned struct_tm_sz;
+  extern unsigned struct_passwd_sz;
+  extern unsigned struct_group_sz;
+  extern unsigned struct_sigaction_sz;
+  extern unsigned siginfo_t_sz;
+  extern unsigned struct_itimerval_sz;
+  extern unsigned pthread_t_sz;
+  extern unsigned pid_t_sz;
+  extern unsigned timeval_sz;
+  extern unsigned uid_t_sz;
+  extern unsigned mbstate_t_sz;
 
-#if defined(__linux__)
+#if !SANITIZER_ANDROID
+  extern unsigned ucontext_t_sz;
+#endif // !SANITIZER_ANDROID
+
+#if SANITIZER_LINUX
   extern unsigned struct_rlimit_sz;
-  extern unsigned struct_dirent_sz;
   extern unsigned struct_statfs_sz;
   extern unsigned struct_epoll_event_sz;
-#endif // __linux__
+  extern unsigned struct_sysinfo_sz;
+  extern unsigned struct_timespec_sz;
+#endif // SANITIZER_LINUX
 
-#if defined(__linux__) && !defined(__ANDROID__)
-  extern unsigned struct_dirent64_sz;
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   extern unsigned struct_rlimit64_sz;
   extern unsigned struct_statfs64_sz;
-#endif // __linux__ && !__ANDROID__
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
 
-  void* __sanitizer_get_msghdr_iov_iov_base(void* msg, int idx);
-  uptr __sanitizer_get_msghdr_iov_iov_len(void* msg, int idx);
-  uptr __sanitizer_get_msghdr_iovlen(void* msg);
-  uptr __sanitizer_get_socklen_t(void* socklen_ptr);
+  struct __sanitizer_iovec {
+    void  *iov_base;
+    uptr iov_len;
+  };
+
+#if SANITIZER_MAC
+  typedef unsigned long __sanitizer_pthread_key_t;
+#else
+  typedef unsigned __sanitizer_pthread_key_t;
+#endif
+
+#if SANITIZER_ANDROID || SANITIZER_MAC
+  struct __sanitizer_msghdr {
+    void *msg_name;
+    unsigned msg_namelen;
+    struct __sanitizer_iovec *msg_iov;
+    unsigned msg_iovlen;
+    void *msg_control;
+    unsigned msg_controllen;
+    int msg_flags;
+  };
+  struct __sanitizer_cmsghdr {
+    unsigned cmsg_len;
+    int cmsg_level;
+    int cmsg_type;
+  };
+#else
+  struct __sanitizer_msghdr {
+    void *msg_name;
+    unsigned msg_namelen;
+    struct __sanitizer_iovec *msg_iov;
+    uptr msg_iovlen;
+    void *msg_control;
+    uptr msg_controllen;
+    int msg_flags;
+  };
+  struct __sanitizer_cmsghdr {
+    uptr cmsg_len;
+    int cmsg_level;
+    int cmsg_type;
+  };
+#endif
+
+#if SANITIZER_MAC
+  struct __sanitizer_dirent {
+    unsigned long long d_ino;
+    unsigned long long d_seekoff;
+    unsigned short d_reclen;
+    // more fields that we don't care about
+  };
+#elif SANITIZER_ANDROID
+  struct __sanitizer_dirent {
+    unsigned long long d_ino;
+    unsigned long long d_off;
+    unsigned short d_reclen;
+    // more fields that we don't care about
+  };
+#else
+  struct __sanitizer_dirent {
+    uptr d_ino;
+    uptr d_off;
+    unsigned short d_reclen;
+    // more fields that we don't care about
+  };
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  struct __sanitizer_dirent64 {
+    unsigned long long d_ino;
+    unsigned long long d_off;
+    unsigned short d_reclen;
+    // more fields that we don't care about
+  };
+#endif
 
   // This thing depends on the platform. We are only interested in the upper
   // limit. Verified with a compiler assert in .cc.
@@ -47,6 +133,598 @@
     char size[pthread_attr_t_max_sz]; // NOLINT
     void *align;
   };
+
+  uptr __sanitizer_get_sigaction_sa_sigaction(void *act);
+  void __sanitizer_set_sigaction_sa_sigaction(void *act, uptr cb);
+  bool __sanitizer_get_sigaction_sa_siginfo(void *act);
+
+  const unsigned struct_sigaction_max_sz = 256;
+  union __sanitizer_sigaction {
+    char size[struct_sigaction_max_sz]; // NOLINT
+  };
+
+  extern uptr sig_ign;
+  extern uptr sig_dfl;
+
+#if SANITIZER_LINUX
+  extern int e_tabsz;
+#endif
+
+  extern int af_inet;
+  extern int af_inet6;
+  uptr __sanitizer_in_addr_sz(int af);
+
+#if SANITIZER_LINUX
+  struct __sanitizer_dl_phdr_info {
+    uptr dlpi_addr;
+    const char *dlpi_name;
+    const void *dlpi_phdr;
+    short dlpi_phnum;
+  };
+#endif
+
+  struct __sanitizer_addrinfo {
+    int ai_flags;
+    int ai_family;
+    int ai_socktype;
+    int ai_protocol;
+#if SANITIZER_ANDROID || SANITIZER_MAC
+    unsigned ai_addrlen;
+    char *ai_canonname;
+    void *ai_addr;
+#else // LINUX
+    unsigned ai_addrlen;
+    void *ai_addr;
+    char *ai_canonname;
+#endif
+    struct __sanitizer_addrinfo *ai_next;
+  };
+
+  struct __sanitizer_hostent {
+    char *h_name;
+    char **h_aliases;
+    int h_addrtype;
+    int h_length;
+    char **h_addr_list;
+  };
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  struct __sanitizer_glob_t {
+    uptr gl_pathc;
+    char **gl_pathv;
+    uptr gl_offs;
+    int gl_flags;
+
+    void (*gl_closedir)(void *dirp);
+    void *(*gl_readdir)(void *dirp);
+    void *(*gl_opendir)(const char *);
+    int (*gl_lstat)(const char *, void *);
+    int (*gl_stat)(const char *, void *);
+  };
+
+  extern int glob_nomatch;
+  extern int glob_altdirfunc;
+#endif
+
+  extern unsigned path_max;
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
+      (defined(__i386) || defined (__x86_64))  // NOLINT
+  extern unsigned struct_user_regs_struct_sz;
+  extern unsigned struct_user_fpregs_struct_sz;
+  extern unsigned struct_user_fpxregs_struct_sz;
+
+  extern int ptrace_getregs;
+  extern int ptrace_setregs;
+  extern int ptrace_getfpregs;
+  extern int ptrace_setfpregs;
+  extern int ptrace_getfpxregs;
+  extern int ptrace_setfpxregs;
+  extern int ptrace_getsiginfo;
+  extern int ptrace_setsiginfo;
+  extern int ptrace_getregset;
+  extern int ptrace_setregset;
+#endif
+
+  // ioctl arguments
+  struct __sanitizer_ifconf {
+    int ifc_len;
+    union {
+      void *ifcu_req;
+    } ifc_ifcu;
+#if SANITIZER_MAC
+  } __attribute__((packed));
+#else
+  };
+#endif
+
+#define IOC_SIZE(nr) (((nr) >> 16) & 0x3fff)
+
+  extern unsigned struct_arpreq_sz;
+  extern unsigned struct_ifreq_sz;
+  extern unsigned struct_termios_sz;
+  extern unsigned struct_winsize_sz;
+
+#if SANITIZER_LINUX
+  extern unsigned struct_cdrom_msf_sz;
+  extern unsigned struct_cdrom_multisession_sz;
+  extern unsigned struct_cdrom_read_audio_sz;
+  extern unsigned struct_cdrom_subchnl_sz;
+  extern unsigned struct_cdrom_ti_sz;
+  extern unsigned struct_cdrom_tocentry_sz;
+  extern unsigned struct_cdrom_tochdr_sz;
+  extern unsigned struct_cdrom_volctrl_sz;
+  extern unsigned struct_copr_buffer_sz;
+  extern unsigned struct_copr_debug_buf_sz;
+  extern unsigned struct_copr_msg_sz;
+  extern unsigned struct_ff_effect_sz;
+  extern unsigned struct_floppy_drive_params_sz;
+  extern unsigned struct_floppy_drive_struct_sz;
+  extern unsigned struct_floppy_fdc_state_sz;
+  extern unsigned struct_floppy_max_errors_sz;
+  extern unsigned struct_floppy_raw_cmd_sz;
+  extern unsigned struct_floppy_struct_sz;
+  extern unsigned struct_floppy_write_errors_sz;
+  extern unsigned struct_format_descr_sz;
+  extern unsigned struct_hd_driveid_sz;
+  extern unsigned struct_hd_geometry_sz;
+  extern unsigned struct_input_absinfo_sz;
+  extern unsigned struct_input_id_sz;
+  extern unsigned struct_midi_info_sz;
+  extern unsigned struct_mtget_sz;
+  extern unsigned struct_mtop_sz;
+  extern unsigned struct_mtpos_sz;
+  extern unsigned struct_rtentry_sz;
+  extern unsigned struct_sbi_instrument_sz;
+  extern unsigned struct_seq_event_rec_sz;
+  extern unsigned struct_synth_info_sz;
+  extern unsigned struct_termio_sz;
+  extern unsigned struct_vt_consize_sz;
+  extern unsigned struct_vt_mode_sz;
+  extern unsigned struct_vt_sizes_sz;
+  extern unsigned struct_vt_stat_sz;
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  extern unsigned struct_audio_buf_info_sz;
+  extern unsigned struct_ax25_parms_struct_sz;
+  extern unsigned struct_cyclades_monitor_sz;
+  extern unsigned struct_input_keymap_entry_sz;
+  extern unsigned struct_ipx_config_data_sz;
+  extern unsigned struct_kbdiacrs_sz;
+  extern unsigned struct_kbentry_sz;
+  extern unsigned struct_kbkeycode_sz;
+  extern unsigned struct_kbsentry_sz;
+  extern unsigned struct_mtconfiginfo_sz;
+  extern unsigned struct_nr_parms_struct_sz;
+  extern unsigned struct_ppp_stats_sz;
+  extern unsigned struct_scc_modem_sz;
+  extern unsigned struct_scc_stat_sz;
+  extern unsigned struct_serial_multiport_struct_sz;
+  extern unsigned struct_serial_struct_sz;
+  extern unsigned struct_sockaddr_ax25_sz;
+  extern unsigned struct_unimapdesc_sz;
+  extern unsigned struct_unimapinit_sz;
+#endif
+
+#if !SANITIZER_ANDROID
+  extern unsigned struct_sioc_sg_req_sz;
+  extern unsigned struct_sioc_vif_req_sz;
+#endif
+
+  // ioctl request identifiers
+
+  // A special value to mark ioctls that are not present on the target platform,
+  // when it can not be determined without including any system headers.
+  extern unsigned IOCTL_NOT_PRESENT;
+
+  extern unsigned IOCTL_FIOASYNC;
+  extern unsigned IOCTL_FIOCLEX;
+  extern unsigned IOCTL_FIOGETOWN;
+  extern unsigned IOCTL_FIONBIO;
+  extern unsigned IOCTL_FIONCLEX;
+  extern unsigned IOCTL_FIOSETOWN;
+  extern unsigned IOCTL_SIOCADDMULTI;
+  extern unsigned IOCTL_SIOCATMARK;
+  extern unsigned IOCTL_SIOCDELMULTI;
+  extern unsigned IOCTL_SIOCGIFADDR;
+  extern unsigned IOCTL_SIOCGIFBRDADDR;
+  extern unsigned IOCTL_SIOCGIFCONF;
+  extern unsigned IOCTL_SIOCGIFDSTADDR;
+  extern unsigned IOCTL_SIOCGIFFLAGS;
+  extern unsigned IOCTL_SIOCGIFMETRIC;
+  extern unsigned IOCTL_SIOCGIFMTU;
+  extern unsigned IOCTL_SIOCGIFNETMASK;
+  extern unsigned IOCTL_SIOCGPGRP;
+  extern unsigned IOCTL_SIOCSIFADDR;
+  extern unsigned IOCTL_SIOCSIFBRDADDR;
+  extern unsigned IOCTL_SIOCSIFDSTADDR;
+  extern unsigned IOCTL_SIOCSIFFLAGS;
+  extern unsigned IOCTL_SIOCSIFMETRIC;
+  extern unsigned IOCTL_SIOCSIFMTU;
+  extern unsigned IOCTL_SIOCSIFNETMASK;
+  extern unsigned IOCTL_SIOCSPGRP;
+  extern unsigned IOCTL_TIOCCONS;
+  extern unsigned IOCTL_TIOCEXCL;
+  extern unsigned IOCTL_TIOCGETD;
+  extern unsigned IOCTL_TIOCGPGRP;
+  extern unsigned IOCTL_TIOCGWINSZ;
+  extern unsigned IOCTL_TIOCMBIC;
+  extern unsigned IOCTL_TIOCMBIS;
+  extern unsigned IOCTL_TIOCMGET;
+  extern unsigned IOCTL_TIOCMSET;
+  extern unsigned IOCTL_TIOCNOTTY;
+  extern unsigned IOCTL_TIOCNXCL;
+  extern unsigned IOCTL_TIOCOUTQ;
+  extern unsigned IOCTL_TIOCPKT;
+  extern unsigned IOCTL_TIOCSCTTY;
+  extern unsigned IOCTL_TIOCSETD;
+  extern unsigned IOCTL_TIOCSPGRP;
+  extern unsigned IOCTL_TIOCSTI;
+  extern unsigned IOCTL_TIOCSWINSZ;
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_MAC
+  extern unsigned IOCTL_SIOCGETSGCNT;
+  extern unsigned IOCTL_SIOCGETVIFCNT;
+#endif
+#if SANITIZER_LINUX
+  extern unsigned IOCTL_EVIOCGABS;
+  extern unsigned IOCTL_EVIOCGBIT;
+  extern unsigned IOCTL_EVIOCGEFFECTS;
+  extern unsigned IOCTL_EVIOCGID;
+  extern unsigned IOCTL_EVIOCGKEY;
+  extern unsigned IOCTL_EVIOCGKEYCODE;
+  extern unsigned IOCTL_EVIOCGLED;
+  extern unsigned IOCTL_EVIOCGNAME;
+  extern unsigned IOCTL_EVIOCGPHYS;
+  extern unsigned IOCTL_EVIOCGRAB;
+  extern unsigned IOCTL_EVIOCGREP;
+  extern unsigned IOCTL_EVIOCGSND;
+  extern unsigned IOCTL_EVIOCGSW;
+  extern unsigned IOCTL_EVIOCGUNIQ;
+  extern unsigned IOCTL_EVIOCGVERSION;
+  extern unsigned IOCTL_EVIOCRMFF;
+  extern unsigned IOCTL_EVIOCSABS;
+  extern unsigned IOCTL_EVIOCSFF;
+  extern unsigned IOCTL_EVIOCSKEYCODE;
+  extern unsigned IOCTL_EVIOCSREP;
+  extern unsigned IOCTL_BLKFLSBUF;
+  extern unsigned IOCTL_BLKGETSIZE;
+  extern unsigned IOCTL_BLKRAGET;
+  extern unsigned IOCTL_BLKRASET;
+  extern unsigned IOCTL_BLKROGET;
+  extern unsigned IOCTL_BLKROSET;
+  extern unsigned IOCTL_BLKRRPART;
+  extern unsigned IOCTL_CDROMAUDIOBUFSIZ;
+  extern unsigned IOCTL_CDROMEJECT;
+  extern unsigned IOCTL_CDROMEJECT_SW;
+  extern unsigned IOCTL_CDROMMULTISESSION;
+  extern unsigned IOCTL_CDROMPAUSE;
+  extern unsigned IOCTL_CDROMPLAYMSF;
+  extern unsigned IOCTL_CDROMPLAYTRKIND;
+  extern unsigned IOCTL_CDROMREADAUDIO;
+  extern unsigned IOCTL_CDROMREADCOOKED;
+  extern unsigned IOCTL_CDROMREADMODE1;
+  extern unsigned IOCTL_CDROMREADMODE2;
+  extern unsigned IOCTL_CDROMREADRAW;
+  extern unsigned IOCTL_CDROMREADTOCENTRY;
+  extern unsigned IOCTL_CDROMREADTOCHDR;
+  extern unsigned IOCTL_CDROMRESET;
+  extern unsigned IOCTL_CDROMRESUME;
+  extern unsigned IOCTL_CDROMSEEK;
+  extern unsigned IOCTL_CDROMSTART;
+  extern unsigned IOCTL_CDROMSTOP;
+  extern unsigned IOCTL_CDROMSUBCHNL;
+  extern unsigned IOCTL_CDROMVOLCTRL;
+  extern unsigned IOCTL_CDROMVOLREAD;
+  extern unsigned IOCTL_CDROM_GET_UPC;
+  extern unsigned IOCTL_FDCLRPRM;
+  extern unsigned IOCTL_FDDEFPRM;
+  extern unsigned IOCTL_FDFLUSH;
+  extern unsigned IOCTL_FDFMTBEG;
+  extern unsigned IOCTL_FDFMTEND;
+  extern unsigned IOCTL_FDFMTTRK;
+  extern unsigned IOCTL_FDGETDRVPRM;
+  extern unsigned IOCTL_FDGETDRVSTAT;
+  extern unsigned IOCTL_FDGETDRVTYP;
+  extern unsigned IOCTL_FDGETFDCSTAT;
+  extern unsigned IOCTL_FDGETMAXERRS;
+  extern unsigned IOCTL_FDGETPRM;
+  extern unsigned IOCTL_FDMSGOFF;
+  extern unsigned IOCTL_FDMSGON;
+  extern unsigned IOCTL_FDPOLLDRVSTAT;
+  extern unsigned IOCTL_FDRAWCMD;
+  extern unsigned IOCTL_FDRESET;
+  extern unsigned IOCTL_FDSETDRVPRM;
+  extern unsigned IOCTL_FDSETEMSGTRESH;
+  extern unsigned IOCTL_FDSETMAXERRS;
+  extern unsigned IOCTL_FDSETPRM;
+  extern unsigned IOCTL_FDTWADDLE;
+  extern unsigned IOCTL_FDWERRORCLR;
+  extern unsigned IOCTL_FDWERRORGET;
+  extern unsigned IOCTL_HDIO_DRIVE_CMD;
+  extern unsigned IOCTL_HDIO_GETGEO;
+  extern unsigned IOCTL_HDIO_GET_32BIT;
+  extern unsigned IOCTL_HDIO_GET_DMA;
+  extern unsigned IOCTL_HDIO_GET_IDENTITY;
+  extern unsigned IOCTL_HDIO_GET_KEEPSETTINGS;
+  extern unsigned IOCTL_HDIO_GET_MULTCOUNT;
+  extern unsigned IOCTL_HDIO_GET_NOWERR;
+  extern unsigned IOCTL_HDIO_GET_UNMASKINTR;
+  extern unsigned IOCTL_HDIO_SET_32BIT;
+  extern unsigned IOCTL_HDIO_SET_DMA;
+  extern unsigned IOCTL_HDIO_SET_KEEPSETTINGS;
+  extern unsigned IOCTL_HDIO_SET_MULTCOUNT;
+  extern unsigned IOCTL_HDIO_SET_NOWERR;
+  extern unsigned IOCTL_HDIO_SET_UNMASKINTR;
+  extern unsigned IOCTL_MTIOCGET;
+  extern unsigned IOCTL_MTIOCPOS;
+  extern unsigned IOCTL_MTIOCTOP;
+  extern unsigned IOCTL_PPPIOCGASYNCMAP;
+  extern unsigned IOCTL_PPPIOCGDEBUG;
+  extern unsigned IOCTL_PPPIOCGFLAGS;
+  extern unsigned IOCTL_PPPIOCGUNIT;
+  extern unsigned IOCTL_PPPIOCGXASYNCMAP;
+  extern unsigned IOCTL_PPPIOCSASYNCMAP;
+  extern unsigned IOCTL_PPPIOCSDEBUG;
+  extern unsigned IOCTL_PPPIOCSFLAGS;
+  extern unsigned IOCTL_PPPIOCSMAXCID;
+  extern unsigned IOCTL_PPPIOCSMRU;
+  extern unsigned IOCTL_PPPIOCSXASYNCMAP;
+  extern unsigned IOCTL_SIOCADDRT;
+  extern unsigned IOCTL_SIOCDARP;
+  extern unsigned IOCTL_SIOCDELRT;
+  extern unsigned IOCTL_SIOCDRARP;
+  extern unsigned IOCTL_SIOCGARP;
+  extern unsigned IOCTL_SIOCGIFENCAP;
+  extern unsigned IOCTL_SIOCGIFHWADDR;
+  extern unsigned IOCTL_SIOCGIFMAP;
+  extern unsigned IOCTL_SIOCGIFMEM;
+  extern unsigned IOCTL_SIOCGIFNAME;
+  extern unsigned IOCTL_SIOCGIFSLAVE;
+  extern unsigned IOCTL_SIOCGRARP;
+  extern unsigned IOCTL_SIOCGSTAMP;
+  extern unsigned IOCTL_SIOCSARP;
+  extern unsigned IOCTL_SIOCSIFENCAP;
+  extern unsigned IOCTL_SIOCSIFHWADDR;
+  extern unsigned IOCTL_SIOCSIFLINK;
+  extern unsigned IOCTL_SIOCSIFMAP;
+  extern unsigned IOCTL_SIOCSIFMEM;
+  extern unsigned IOCTL_SIOCSIFSLAVE;
+  extern unsigned IOCTL_SIOCSRARP;
+  extern unsigned IOCTL_SNDCTL_COPR_HALT;
+  extern unsigned IOCTL_SNDCTL_COPR_LOAD;
+  extern unsigned IOCTL_SNDCTL_COPR_RCODE;
+  extern unsigned IOCTL_SNDCTL_COPR_RCVMSG;
+  extern unsigned IOCTL_SNDCTL_COPR_RDATA;
+  extern unsigned IOCTL_SNDCTL_COPR_RESET;
+  extern unsigned IOCTL_SNDCTL_COPR_RUN;
+  extern unsigned IOCTL_SNDCTL_COPR_SENDMSG;
+  extern unsigned IOCTL_SNDCTL_COPR_WCODE;
+  extern unsigned IOCTL_SNDCTL_COPR_WDATA;
+  extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE;
+  extern unsigned IOCTL_SNDCTL_DSP_GETFMTS;
+  extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK;
+  extern unsigned IOCTL_SNDCTL_DSP_POST;
+  extern unsigned IOCTL_SNDCTL_DSP_RESET;
+  extern unsigned IOCTL_SNDCTL_DSP_SETFMT;
+  extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT;
+  extern unsigned IOCTL_SNDCTL_DSP_SPEED;
+  extern unsigned IOCTL_SNDCTL_DSP_STEREO;
+  extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE;
+  extern unsigned IOCTL_SNDCTL_DSP_SYNC;
+  extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE;
+  extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR;
+  extern unsigned IOCTL_SNDCTL_MIDI_INFO;
+  extern unsigned IOCTL_SNDCTL_MIDI_PRETIME;
+  extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE;
+  extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT;
+  extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT;
+  extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS;
+  extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS;
+  extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND;
+  extern unsigned IOCTL_SNDCTL_SEQ_PANIC;
+  extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE;
+  extern unsigned IOCTL_SNDCTL_SEQ_RESET;
+  extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES;
+  extern unsigned IOCTL_SNDCTL_SEQ_SYNC;
+  extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI;
+  extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD;
+  extern unsigned IOCTL_SNDCTL_SYNTH_INFO;
+  extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL;
+  extern unsigned IOCTL_SNDCTL_TMR_CONTINUE;
+  extern unsigned IOCTL_SNDCTL_TMR_METRONOME;
+  extern unsigned IOCTL_SNDCTL_TMR_SELECT;
+  extern unsigned IOCTL_SNDCTL_TMR_SOURCE;
+  extern unsigned IOCTL_SNDCTL_TMR_START;
+  extern unsigned IOCTL_SNDCTL_TMR_STOP;
+  extern unsigned IOCTL_SNDCTL_TMR_TEMPO;
+  extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE;
+  extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM;
+  extern unsigned IOCTL_SOUND_MIXER_READ_BASS;
+  extern unsigned IOCTL_SOUND_MIXER_READ_CAPS;
+  extern unsigned IOCTL_SOUND_MIXER_READ_CD;
+  extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK;
+  extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE;
+  extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN;
+  extern unsigned IOCTL_SOUND_MIXER_READ_IMIX;
+  extern unsigned IOCTL_SOUND_MIXER_READ_LINE1;
+  extern unsigned IOCTL_SOUND_MIXER_READ_LINE2;
+  extern unsigned IOCTL_SOUND_MIXER_READ_LINE3;
+  extern unsigned IOCTL_SOUND_MIXER_READ_LINE;
+  extern unsigned IOCTL_SOUND_MIXER_READ_LOUD;
+  extern unsigned IOCTL_SOUND_MIXER_READ_MIC;
+  extern unsigned IOCTL_SOUND_MIXER_READ_MUTE;
+  extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN;
+  extern unsigned IOCTL_SOUND_MIXER_READ_PCM;
+  extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV;
+  extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK;
+  extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC;
+  extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER;
+  extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS;
+  extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH;
+  extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE;
+  extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_CD;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME;
+  extern unsigned IOCTL_SOUND_PCM_READ_BITS;
+  extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS;
+  extern unsigned IOCTL_SOUND_PCM_READ_FILTER;
+  extern unsigned IOCTL_SOUND_PCM_READ_RATE;
+  extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS;
+  extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER;
+  extern unsigned IOCTL_TCFLSH;
+  extern unsigned IOCTL_TCGETA;
+  extern unsigned IOCTL_TCGETS;
+  extern unsigned IOCTL_TCSBRK;
+  extern unsigned IOCTL_TCSBRKP;
+  extern unsigned IOCTL_TCSETA;
+  extern unsigned IOCTL_TCSETAF;
+  extern unsigned IOCTL_TCSETAW;
+  extern unsigned IOCTL_TCSETS;
+  extern unsigned IOCTL_TCSETSF;
+  extern unsigned IOCTL_TCSETSW;
+  extern unsigned IOCTL_TCXONC;
+  extern unsigned IOCTL_TIOCGLCKTRMIOS;
+  extern unsigned IOCTL_TIOCGSOFTCAR;
+  extern unsigned IOCTL_TIOCINQ;
+  extern unsigned IOCTL_TIOCLINUX;
+  extern unsigned IOCTL_TIOCSERCONFIG;
+  extern unsigned IOCTL_TIOCSERGETLSR;
+  extern unsigned IOCTL_TIOCSERGWILD;
+  extern unsigned IOCTL_TIOCSERSWILD;
+  extern unsigned IOCTL_TIOCSLCKTRMIOS;
+  extern unsigned IOCTL_TIOCSSOFTCAR;
+  extern unsigned IOCTL_VT_ACTIVATE;
+  extern unsigned IOCTL_VT_DISALLOCATE;
+  extern unsigned IOCTL_VT_GETMODE;
+  extern unsigned IOCTL_VT_GETSTATE;
+  extern unsigned IOCTL_VT_OPENQRY;
+  extern unsigned IOCTL_VT_RELDISP;
+  extern unsigned IOCTL_VT_RESIZE;
+  extern unsigned IOCTL_VT_RESIZEX;
+  extern unsigned IOCTL_VT_SENDSIG;
+  extern unsigned IOCTL_VT_SETMODE;
+  extern unsigned IOCTL_VT_WAITACTIVE;
+#endif
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  extern unsigned IOCTL_CYGETDEFTHRESH;
+  extern unsigned IOCTL_CYGETDEFTIMEOUT;
+  extern unsigned IOCTL_CYGETMON;
+  extern unsigned IOCTL_CYGETTHRESH;
+  extern unsigned IOCTL_CYGETTIMEOUT;
+  extern unsigned IOCTL_CYSETDEFTHRESH;
+  extern unsigned IOCTL_CYSETDEFTIMEOUT;
+  extern unsigned IOCTL_CYSETTHRESH;
+  extern unsigned IOCTL_CYSETTIMEOUT;
+  extern unsigned IOCTL_EQL_EMANCIPATE;
+  extern unsigned IOCTL_EQL_ENSLAVE;
+  extern unsigned IOCTL_EQL_GETMASTRCFG;
+  extern unsigned IOCTL_EQL_GETSLAVECFG;
+  extern unsigned IOCTL_EQL_SETMASTRCFG;
+  extern unsigned IOCTL_EQL_SETSLAVECFG;
+  extern unsigned IOCTL_EVIOCGKEYCODE_V2;
+  extern unsigned IOCTL_EVIOCGPROP;
+  extern unsigned IOCTL_EVIOCSKEYCODE_V2;
+  extern unsigned IOCTL_FS_IOC_GETFLAGS;
+  extern unsigned IOCTL_FS_IOC_GETVERSION;
+  extern unsigned IOCTL_FS_IOC_SETFLAGS;
+  extern unsigned IOCTL_FS_IOC_SETVERSION;
+  extern unsigned IOCTL_GIO_CMAP;
+  extern unsigned IOCTL_GIO_FONT;
+  extern unsigned IOCTL_GIO_SCRNMAP;
+  extern unsigned IOCTL_GIO_UNIMAP;
+  extern unsigned IOCTL_GIO_UNISCRNMAP;
+  extern unsigned IOCTL_KDADDIO;
+  extern unsigned IOCTL_KDDELIO;
+  extern unsigned IOCTL_KDDISABIO;
+  extern unsigned IOCTL_KDENABIO;
+  extern unsigned IOCTL_KDGETKEYCODE;
+  extern unsigned IOCTL_KDGETLED;
+  extern unsigned IOCTL_KDGETMODE;
+  extern unsigned IOCTL_KDGKBDIACR;
+  extern unsigned IOCTL_KDGKBENT;
+  extern unsigned IOCTL_KDGKBLED;
+  extern unsigned IOCTL_KDGKBMETA;
+  extern unsigned IOCTL_KDGKBMODE;
+  extern unsigned IOCTL_KDGKBSENT;
+  extern unsigned IOCTL_KDGKBTYPE;
+  extern unsigned IOCTL_KDMAPDISP;
+  extern unsigned IOCTL_KDMKTONE;
+  extern unsigned IOCTL_KDSETKEYCODE;
+  extern unsigned IOCTL_KDSETLED;
+  extern unsigned IOCTL_KDSETMODE;
+  extern unsigned IOCTL_KDSIGACCEPT;
+  extern unsigned IOCTL_KDSKBDIACR;
+  extern unsigned IOCTL_KDSKBENT;
+  extern unsigned IOCTL_KDSKBLED;
+  extern unsigned IOCTL_KDSKBMETA;
+  extern unsigned IOCTL_KDSKBMODE;
+  extern unsigned IOCTL_KDSKBSENT;
+  extern unsigned IOCTL_KDUNMAPDISP;
+  extern unsigned IOCTL_KIOCSOUND;
+  extern unsigned IOCTL_LPABORT;
+  extern unsigned IOCTL_LPABORTOPEN;
+  extern unsigned IOCTL_LPCAREFUL;
+  extern unsigned IOCTL_LPCHAR;
+  extern unsigned IOCTL_LPGETIRQ;
+  extern unsigned IOCTL_LPGETSTATUS;
+  extern unsigned IOCTL_LPRESET;
+  extern unsigned IOCTL_LPSETIRQ;
+  extern unsigned IOCTL_LPTIME;
+  extern unsigned IOCTL_LPWAIT;
+  extern unsigned IOCTL_MTIOCGETCONFIG;
+  extern unsigned IOCTL_MTIOCSETCONFIG;
+  extern unsigned IOCTL_PIO_CMAP;
+  extern unsigned IOCTL_PIO_FONT;
+  extern unsigned IOCTL_PIO_SCRNMAP;
+  extern unsigned IOCTL_PIO_UNIMAP;
+  extern unsigned IOCTL_PIO_UNIMAPCLR;
+  extern unsigned IOCTL_PIO_UNISCRNMAP;
+  extern unsigned IOCTL_SCSI_IOCTL_GET_IDLUN;
+  extern unsigned IOCTL_SCSI_IOCTL_PROBE_HOST;
+  extern unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE;
+  extern unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE;
+  extern unsigned IOCTL_SIOCAIPXITFCRT;
+  extern unsigned IOCTL_SIOCAIPXPRISLT;
+  extern unsigned IOCTL_SIOCAX25ADDUID;
+  extern unsigned IOCTL_SIOCAX25DELUID;
+  extern unsigned IOCTL_SIOCAX25GETPARMS;
+  extern unsigned IOCTL_SIOCAX25GETUID;
+  extern unsigned IOCTL_SIOCAX25NOUID;
+  extern unsigned IOCTL_SIOCAX25SETPARMS;
+  extern unsigned IOCTL_SIOCDEVPLIP;
+  extern unsigned IOCTL_SIOCIPXCFGDATA;
+  extern unsigned IOCTL_SIOCNRDECOBS;
+  extern unsigned IOCTL_SIOCNRGETPARMS;
+  extern unsigned IOCTL_SIOCNRRTCTL;
+  extern unsigned IOCTL_SIOCNRSETPARMS;
+  extern unsigned IOCTL_SNDCTL_DSP_GETISPACE;
+  extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE;
+  extern unsigned IOCTL_TIOCGSERIAL;
+  extern unsigned IOCTL_TIOCSERGETMULTI;
+  extern unsigned IOCTL_TIOCSERSETMULTI;
+  extern unsigned IOCTL_TIOCSSERIAL;
+#endif
 }  // namespace __sanitizer
 
 #endif
+
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
index 27f0977..02f031b 100644
--- a/lib/sanitizer_common/sanitizer_posix.cc
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -11,53 +11,49 @@
 // run-time libraries and implements POSIX-specific functions from
 // sanitizer_libc.h.
 //===----------------------------------------------------------------------===//
-#if defined(__linux__) || defined(__APPLE__)
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX || SANITIZER_MAC
 
 #include "sanitizer_common.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
 
-#include <errno.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <sys/mman.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
 
 namespace __sanitizer {
 
 // ------------- sanitizer_common.h
-uptr GetPageSize() {
-  return sysconf(_SC_PAGESIZE);
-}
-
 uptr GetMmapGranularity() {
   return GetPageSize();
 }
 
-int GetPid() {
-  return getpid();
-}
-
-u32 GetUid() {
-  return getuid();
-}
-
-uptr GetThreadSelf() {
-  return (uptr)pthread_self();
+uptr GetMaxVirtualAddress() {
+#if SANITIZER_WORDSIZE == 64
+# if defined(__powerpc64__)
+  // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
+  // We somehow need to figure our which one we are using now and choose
+  // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
+  // Note that with 'ulimit -s unlimited' the stack is moved away from the top
+  // of the address space, so simply checking the stack address is not enough.
+  return (1ULL << 44) - 1;  // 0x00000fffffffffffUL
+# else
+  return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
+# endif
+#else  // SANITIZER_WORDSIZE == 32
+  // FIXME: We can probably lower this on Android?
+  return (1ULL << 32) - 1;  // 0xffffffff;
+#endif  // SANITIZER_WORDSIZE
 }
 
 void *MmapOrDie(uptr size, const char *mem_type) {
   size = RoundUpTo(size, GetPageSizeCached());
-  void *res = internal_mmap(0, size,
+  uptr res = internal_mmap(0, size,
                             PROT_READ | PROT_WRITE,
                             MAP_PRIVATE | MAP_ANON, -1, 0);
-  if (res == (void*)-1) {
+  int reserrno;
+  if (internal_iserror(res, &reserrno)) {
     static int recursion_count;
     if (recursion_count) {
       // The Report() and CHECK calls below may call mmap recursively and fail.
@@ -67,17 +63,17 @@
     }
     recursion_count++;
     Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
-           SanitizerToolName, size, size, mem_type, errno);
+           SanitizerToolName, size, size, mem_type, reserrno);
     DumpProcessMap();
     CHECK("unable to mmap" && 0);
   }
-  return res;
+  return (void *)res;
 }
 
 void UnmapOrDie(void *addr, uptr size) {
   if (!addr || !size) return;
-  int res = internal_munmap(addr, size);
-  if (res != 0) {
+  uptr res = internal_munmap(addr, size);
+  if (internal_iserror(res)) {
     Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
            SanitizerToolName, size, size, addr);
     CHECK("unable to unmap" && 0);
@@ -86,54 +82,53 @@
 
 void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
   uptr PageSize = GetPageSizeCached();
-  void *p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
+  uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
       RoundUpTo(size, PageSize),
       PROT_READ | PROT_WRITE,
       MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
       -1, 0);
-  if (p == (void*)-1)
+  int reserrno;
+  if (internal_iserror(p, &reserrno))
     Report("ERROR: "
            "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
-           SanitizerToolName, size, size, fixed_addr, errno);
-  return p;
+           SanitizerToolName, size, size, fixed_addr, reserrno);
+  return (void *)p;
 }
 
 void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
   uptr PageSize = GetPageSizeCached();
-  void *p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
+  uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
       RoundUpTo(size, PageSize),
       PROT_READ | PROT_WRITE,
       MAP_PRIVATE | MAP_ANON | MAP_FIXED,
       -1, 0);
-  if (p == (void*)-1) {
+  int reserrno;
+  if (internal_iserror(p, &reserrno)) {
     Report("ERROR:"
            " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
-           SanitizerToolName, size, size, fixed_addr, errno);
+           SanitizerToolName, size, size, fixed_addr, reserrno);
     CHECK("unable to mmap" && 0);
   }
-  return p;
+  return (void *)p;
 }
 
 void *Mprotect(uptr fixed_addr, uptr size) {
-  return internal_mmap((void*)fixed_addr, size,
-                       PROT_NONE,
-                       MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
-                       -1, 0);
-}
-
-void FlushUnneededShadowMemory(uptr addr, uptr size) {
-  madvise((void*)addr, size, MADV_DONTNEED);
+  return (void *)internal_mmap((void*)fixed_addr, size,
+                               PROT_NONE,
+                               MAP_PRIVATE | MAP_ANON | MAP_FIXED |
+                               MAP_NORESERVE, -1, 0);
 }
 
 void *MapFileToMemory(const char *file_name, uptr *buff_size) {
-  fd_t fd = OpenFile(file_name, false);
-  CHECK_NE(fd, kInvalidFd);
+  uptr openrv = OpenFile(file_name, false);
+  CHECK(!internal_iserror(openrv));
+  fd_t fd = openrv;
   uptr fsize = internal_filesize(fd);
   CHECK_NE(fsize, (uptr)-1);
   CHECK_GT(fsize, 0);
   *buff_size = RoundUpTo(fsize, GetPageSizeCached());
-  void *map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
-  return (map == MAP_FAILED) ? 0 : map;
+  uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
+  return internal_iserror(map) ? 0 : (void *)map;
 }
 
 
@@ -149,11 +144,11 @@
 // several worker threads on Mac, which aren't expected to map big chunks of
 // memory).
 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
-  MemoryMappingLayout procmaps;
+  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
   uptr start, end;
-  while (procmaps.Next(&start, &end,
-                       /*offset*/0, /*filename*/0, /*filename_size*/0,
-                       /*protection*/0)) {
+  while (proc_maps.Next(&start, &end,
+                        /*offset*/0, /*filename*/0, /*filename_size*/0,
+                        /*protection*/0)) {
     if (!IntervalsAreSeparate(start, end, range_start, range_end))
       return false;
   }
@@ -161,7 +156,7 @@
 }
 
 void DumpProcessMap() {
-  MemoryMappingLayout proc_maps;
+  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
   uptr start, end;
   const sptr kBufSize = 4095;
   char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
@@ -178,54 +173,6 @@
   return GetEnv("PWD");
 }
 
-void DisableCoreDumper() {
-  struct rlimit nocore;
-  nocore.rlim_cur = 0;
-  nocore.rlim_max = 0;
-  setrlimit(RLIMIT_CORE, &nocore);
-}
-
-bool StackSizeIsUnlimited() {
-  struct rlimit rlim;
-  CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim));
-  return (rlim.rlim_cur == (uptr)-1);
-}
-
-void SetStackSizeLimitInBytes(uptr limit) {
-  struct rlimit rlim;
-  rlim.rlim_cur = limit;
-  rlim.rlim_max = limit;
-  if (setrlimit(RLIMIT_STACK, &rlim)) {
-    Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
-    Die();
-  }
-  CHECK(!StackSizeIsUnlimited());
-}
-
-void SleepForSeconds(int seconds) {
-  sleep(seconds);
-}
-
-void SleepForMillis(int millis) {
-  usleep(millis * 1000);
-}
-
-void Abort() {
-  abort();
-}
-
-int Atexit(void (*function)(void)) {
-#ifndef SANITIZER_GO
-  return atexit(function);
-#else
-  return 0;
-#endif
-}
-
-int internal_isatty(fd_t fd) {
-  return isatty(fd);
-}
-
 }  // namespace __sanitizer
 
-#endif  // __linux__ || __APPLE_
+#endif  // SANITIZER_LINUX || SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
new file mode 100644
index 0000000..429f5de
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -0,0 +1,116 @@
+//===-- sanitizer_posix_libcdep.cc ----------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and implements libc-dependent POSIX-specific functions
+// from sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_LINUX || SANITIZER_MAC
+#include "sanitizer_common.h"
+#include "sanitizer_stacktrace.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace __sanitizer {
+
+u32 GetUid() {
+  return getuid();
+}
+
+uptr GetThreadSelf() {
+  return (uptr)pthread_self();
+}
+
+void FlushUnneededShadowMemory(uptr addr, uptr size) {
+  madvise((void*)addr, size, MADV_DONTNEED);
+}
+
+void DisableCoreDumper() {
+  struct rlimit nocore;
+  nocore.rlim_cur = 0;
+  nocore.rlim_max = 0;
+  setrlimit(RLIMIT_CORE, &nocore);
+}
+
+bool StackSizeIsUnlimited() {
+  struct rlimit rlim;
+  CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim));
+  return (rlim.rlim_cur == (uptr)-1);
+}
+
+void SetStackSizeLimitInBytes(uptr limit) {
+  struct rlimit rlim;
+  rlim.rlim_cur = limit;
+  rlim.rlim_max = limit;
+  if (setrlimit(RLIMIT_STACK, &rlim)) {
+    Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
+    Die();
+  }
+  CHECK(!StackSizeIsUnlimited());
+}
+
+void SleepForSeconds(int seconds) {
+  sleep(seconds);
+}
+
+void SleepForMillis(int millis) {
+  usleep(millis * 1000);
+}
+
+void Abort() {
+  abort();
+}
+
+int Atexit(void (*function)(void)) {
+#ifndef SANITIZER_GO
+  return atexit(function);
+#else
+  return 0;
+#endif
+}
+
+int internal_isatty(fd_t fd) {
+  return isatty(fd);
+}
+
+#ifndef SANITIZER_GO
+void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+                   uptr stack_top, uptr stack_bottom, bool fast) {
+#if !SANITIZER_CAN_FAST_UNWIND
+  fast = false;
+#endif
+#if SANITIZER_MAC
+  // Always unwind fast on Mac.
+  (void)fast;
+#else
+  if (!fast)
+    return stack->SlowUnwindStack(pc, max_s);
+#endif  // SANITIZER_MAC
+  stack->size = 0;
+  stack->trace[0] = pc;
+  if (max_s > 1) {
+    stack->max_size = max_s;
+    stack->FastUnwindStack(pc, bp, stack_top, stack_bottom);
+  }
+}
+#endif  // SANITIZER_GO
+
+}  // namespace __sanitizer
+
+#endif
diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc
index 4b5a8b4..2d8c04a 100644
--- a/lib/sanitizer_common/sanitizer_printf.cc
+++ b/lib/sanitizer_common/sanitizer_printf.cc
@@ -21,8 +21,14 @@
 #include <stdio.h>
 #include <stdarg.h>
 
+#if SANITIZER_WINDOWS && !defined(va_copy)
+# define va_copy(dst, src) ((dst) = (src))
+#endif
+
 namespace __sanitizer {
 
+StaticSpinMutex CommonSanitizerReportMutex;
+
 static int AppendChar(char **buff, const char *buff_end, char c) {
   if (*buff < buff_end) {
     **buff = c;
@@ -32,45 +38,60 @@
 }
 
 // Appends number in a given base to buffer. If its length is less than
-// "minimal_num_length", it is padded with leading zeroes.
-static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
-                          u8 base, u8 minimal_num_length) {
+// |minimal_num_length|, it is padded with leading zeroes or spaces, depending
+// on the value of |pad_with_zero|.
+static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value,
+                        u8 base, u8 minimal_num_length, bool pad_with_zero,
+                        bool negative) {
   uptr const kMaxLen = 30;
   RAW_CHECK(base == 10 || base == 16);
+  RAW_CHECK(base == 10 || !negative);
+  RAW_CHECK(absolute_value || !negative);
   RAW_CHECK(minimal_num_length < kMaxLen);
+  int result = 0;
+  if (negative && minimal_num_length)
+    --minimal_num_length;
+  if (negative && pad_with_zero)
+    result += AppendChar(buff, buff_end, '-');
   uptr num_buffer[kMaxLen];
-  uptr pos = 0;
+  int pos = 0;
   do {
-    RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow");
-    num_buffer[pos++] = num % base;
-    num /= base;
-  } while (num > 0);
+    RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow");
+    num_buffer[pos++] = absolute_value % base;
+    absolute_value /= base;
+  } while (absolute_value > 0);
   if (pos < minimal_num_length) {
     // Make sure compiler doesn't insert call to memset here.
     internal_memset(&num_buffer[pos], 0,
                     sizeof(num_buffer[0]) * (minimal_num_length - pos));
     pos = minimal_num_length;
   }
-  int result = 0;
-  while (pos-- > 0) {
-    uptr digit = num_buffer[pos];
+  RAW_CHECK(pos > 0);
+  pos--;
+  for (; pos >= 0 && num_buffer[pos] == 0; pos--) {
+    char c = (pad_with_zero || pos == 0) ? '0' : ' ';
+    result += AppendChar(buff, buff_end, c);
+  }
+  if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-');
+  for (; pos >= 0; pos--) {
+    char digit = static_cast<char>(num_buffer[pos]);
     result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
                                                       : 'a' + digit - 10);
   }
   return result;
 }
 
+static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base,
+                          u8 minimal_num_length, bool pad_with_zero) {
+  return AppendNumber(buff, buff_end, num, base, minimal_num_length,
+                      pad_with_zero, false /* negative */);
+}
+
 static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
-                               u8 minimal_num_length) {
-  int result = 0;
-  if (num < 0) {
-    result += AppendChar(buff, buff_end, '-');
-    num = -num;
-    if (minimal_num_length)
-      --minimal_num_length;
-  }
-  result += AppendUnsigned(buff, buff_end, (u64)num, 10, minimal_num_length);
-  return result;
+                               u8 minimal_num_length, bool pad_with_zero) {
+  bool negative = (num < 0);
+  return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10,
+                      minimal_num_length, pad_with_zero, negative);
 }
 
 static int AppendString(char **buff, const char *buff_end, const char *s) {
@@ -87,14 +108,14 @@
   int result = 0;
   result += AppendString(buff, buff_end, "0x");
   result += AppendUnsigned(buff, buff_end, ptr_value, 16,
-                           (SANITIZER_WORDSIZE == 64) ? 12 : 8);
+                           (SANITIZER_WORDSIZE == 64) ? 12 : 8, true);
   return result;
 }
 
 int VSNPrintf(char *buff, int buff_length,
               const char *format, va_list args) {
   static const char *kPrintfFormatsHelp =
-    "Supported Printf formats: %(0[0-9]*)?(z|ll)?{d,u,x}; %p; %s; %c\n";
+    "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %s; %c\n";
   RAW_CHECK(format);
   RAW_CHECK(buff_length > 0);
   const char *buff_end = &buff[buff_length - 1];
@@ -106,11 +127,11 @@
       continue;
     }
     cur++;
-    bool have_width = (*cur == '0');
+    bool have_width = (*cur >= '0' && *cur <= '9');
+    bool pad_with_zero = (*cur == '0');
     int width = 0;
     if (have_width) {
       while (*cur >= '0' && *cur <= '9') {
-        have_width = true;
         width = width * 10 + *cur++ - '0';
       }
     }
@@ -126,7 +147,8 @@
         dval = have_ll ? va_arg(args, s64)
              : have_z ? va_arg(args, sptr)
              : va_arg(args, int);
-        result += AppendSignedDecimal(&buff, buff_end, dval, width);
+        result += AppendSignedDecimal(&buff, buff_end, dval, width,
+                                      pad_with_zero);
         break;
       }
       case 'u':
@@ -135,7 +157,7 @@
              : have_z ? va_arg(args, uptr)
              : va_arg(args, unsigned);
         result += AppendUnsigned(&buff, buff_end, uval,
-                                 (*cur == 'u') ? 10 : 16, width);
+                                 (*cur == 'u') ? 10 : 16, width, pad_with_zero);
         break;
       }
       case 'p': {
@@ -173,17 +195,86 @@
   PrintfAndReportCallback = callback;
 }
 
-void Printf(const char *format, ...) {
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+// Can be overriden in frontend.
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+void OnPrint(const char *str);
+#endif
+
+static void CallPrintfAndReportCallback(const char *str) {
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+  if (&OnPrint != NULL)
+    OnPrint(str);
+#endif
+  if (PrintfAndReportCallback)
+    PrintfAndReportCallback(str);
+}
+
+static void SharedPrintfCode(bool append_pid, const char *format,
+                             va_list args) {
+  va_list args2;
+  va_copy(args2, args);
   const int kLen = 16 * 1024;
-  InternalScopedBuffer<char> buffer(kLen);
+  // |local_buffer| is small enough not to overflow the stack and/or violate
+  // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other
+  // hand, the bigger the buffer is, the more the chance the error report will
+  // fit into it.
+  char local_buffer[400];
+  int needed_length;
+  char *buffer = local_buffer;
+  int buffer_size = ARRAY_SIZE(local_buffer);
+  // First try to print a message using a local buffer, and then fall back to
+  // mmaped buffer.
+  for (int use_mmap = 0; use_mmap < 2; use_mmap++) {
+    if (use_mmap) {
+      va_end(args);
+      va_copy(args, args2);
+      buffer = (char*)MmapOrDie(kLen, "Report");
+      buffer_size = kLen;
+    }
+    needed_length = 0;
+    if (append_pid) {
+      int pid = internal_getpid();
+      needed_length += internal_snprintf(buffer, buffer_size, "==%d==", pid);
+      if (needed_length >= buffer_size) {
+        // The pid doesn't fit into the current buffer.
+        if (!use_mmap)
+          continue;
+        RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
+      }
+    }
+    needed_length += VSNPrintf(buffer + needed_length,
+                               buffer_size - needed_length, format, args);
+    if (needed_length >= buffer_size) {
+      // The message doesn't fit into the current buffer.
+      if (!use_mmap)
+        continue;
+      RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
+    }
+    // If the message fit into the buffer, print it and exit.
+    break;
+  }
+  RawWrite(buffer);
+  CallPrintfAndReportCallback(buffer);
+  // If we had mapped any memory, clean up.
+  if (buffer != local_buffer)
+    UnmapOrDie((void *)buffer, buffer_size);
+  va_end(args2);
+}
+
+void Printf(const char *format, ...) {
   va_list args;
   va_start(args, format);
-  int needed_length = VSNPrintf(buffer.data(), kLen, format, args);
+  SharedPrintfCode(false, format, args);
   va_end(args);
-  RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
-  RawWrite(buffer.data());
-  if (PrintfAndReportCallback)
-    PrintfAndReportCallback(buffer.data());
+}
+
+// Like Printf, but prints the current PID before the output string.
+void Report(const char *format, ...) {
+  va_list args;
+  va_start(args, format);
+  SharedPrintfCode(true, format, args);
+  va_end(args);
 }
 
 // Writes at most "length" symbols to "buffer" (including trailing '\0').
@@ -198,55 +289,4 @@
   return needed_length;
 }
 
-// Like Printf, but prints the current PID before the output string.
-void Report(const char *format, ...) {
-  const int kLen = 16 * 1024;
-  // |local_buffer| is small enough not to overflow the stack and/or violate
-  // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other
-  // hand, the bigger the buffer is, the more the chance the error report will
-  // fit into it.
-  char local_buffer[400];
-  int needed_length;
-  int pid = GetPid();
-  char *buffer = local_buffer;
-  int cur_size = sizeof(local_buffer) / sizeof(char);
-  for (int use_mmap = 0; use_mmap < 2; use_mmap++) {
-    needed_length = internal_snprintf(buffer, cur_size,
-                                      "==%d==", pid);
-    if (needed_length >= cur_size) {
-      if (use_mmap) {
-        RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
-      } else {
-        // The pid doesn't fit into the local buffer.
-        continue;
-      }
-    }
-    va_list args;
-    va_start(args, format);
-    needed_length += VSNPrintf(buffer + needed_length,
-                               cur_size - needed_length, format, args);
-    va_end(args);
-    if (needed_length >= cur_size) {
-      if (use_mmap) {
-        RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
-      } else {
-        // The error message doesn't fit into the local buffer - allocate a
-        // bigger one.
-        buffer = (char*)MmapOrDie(kLen, "Report");
-        cur_size = kLen;
-        continue;
-      }
-    } else {
-      RawWrite(buffer);
-      if (PrintfAndReportCallback)
-        PrintfAndReportCallback(buffer);
-      // Don't do anything for the second time if the first iteration
-      // succeeded.
-      break;
-    }
-  }
-  // If we had mapped any memory, clean up.
-  if (buffer != local_buffer) UnmapOrDie((void*)buffer, cur_size);
-}
-
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h
index 8df215d..b96f09e 100644
--- a/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/lib/sanitizer_common/sanitizer_procmaps.h
@@ -19,10 +19,12 @@
 
 namespace __sanitizer {
 
-#ifdef _WIN32
+#if SANITIZER_WINDOWS
 class MemoryMappingLayout {
  public:
-  MemoryMappingLayout() {}
+  explicit MemoryMappingLayout(bool cache_enabled) {
+    (void)cache_enabled;
+  }
   bool GetObjectNameAndOffset(uptr addr, uptr *offset,
                               char filename[], uptr filename_size,
                               uptr *protection) {
@@ -31,17 +33,17 @@
 };
 
 #else  // _WIN32
-#if defined(__linux__)
+#if SANITIZER_LINUX
 struct ProcSelfMapsBuff {
   char *data;
   uptr mmaped_size;
   uptr len;
 };
-#endif  // defined(__linux__)
+#endif  // SANITIZER_LINUX
 
 class MemoryMappingLayout {
  public:
-  MemoryMappingLayout();
+  explicit MemoryMappingLayout(bool cache_enabled);
   bool Next(uptr *start, uptr *end, uptr *offset,
             char filename[], uptr filename_size, uptr *protection);
   void Reset();
@@ -96,14 +98,14 @@
     return false;
   }
 
-# if defined __linux__
+# if SANITIZER_LINUX
   ProcSelfMapsBuff proc_self_maps_;
   char *current_;
 
   // Static mappings cache.
   static ProcSelfMapsBuff cached_proc_self_maps_;
   static StaticSpinMutex cache_lock_;  // protects cached_proc_self_maps_.
-# elif defined __APPLE__
+# elif SANITIZER_MAC
   template<u32 kLCSegment, typename SegmentCommand>
   bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset,
                        char filename[], uptr filename_size,
diff --git a/lib/sanitizer_common/sanitizer_quarantine.h b/lib/sanitizer_common/sanitizer_quarantine.h
index 599d136..b21ab23 100644
--- a/lib/sanitizer_common/sanitizer_quarantine.h
+++ b/lib/sanitizer_common/sanitizer_quarantine.h
@@ -147,7 +147,9 @@
       return 0;
     QuarantineBatch *b = list_.front();
     list_.pop_front();
-    SizeAdd(-b->size);
+    // FIXME: should probably add SizeSub method?
+    // See https://code.google.com/p/thread-sanitizer/issues/detail?id=20
+    SizeAdd(0 - b->size);
     return b;
   }
 
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc
index 1b3a1f5..e279a9f 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.cc
+++ b/lib/sanitizer_common/sanitizer_stacktrace.cc
@@ -20,8 +20,9 @@
 const char *StripPathPrefix(const char *filepath,
                             const char *strip_file_prefix) {
   if (filepath == 0) return 0;
-  if (filepath == internal_strstr(filepath, strip_file_prefix))
-    return filepath + internal_strlen(strip_file_prefix);
+  const char *prefix_beg = internal_strstr(filepath, strip_file_prefix);
+  if (prefix_beg)
+    return prefix_beg + internal_strlen(strip_file_prefix);
   return filepath;
 }
 
@@ -64,7 +65,7 @@
 void StackTrace::PrintStack(const uptr *addr, uptr size,
                             bool symbolize, const char *strip_file_prefix,
                             SymbolizeCallback symbolize_callback ) {
-  MemoryMappingLayout proc_maps;
+  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
   InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
   InternalScopedBuffer<AddressInfo> addr_frames(64);
   uptr frame_num = 0;
@@ -85,7 +86,7 @@
         frame_num++;
       }
     }
-    if (symbolize && addr_frames_num == 0) {
+    if (symbolize && addr_frames_num == 0 && &SymbolizeCode) {
       // Use our own (online) symbolizer, if necessary.
       addr_frames_num = SymbolizeCode(pc, addr_frames.data(),
                                       addr_frames.size());
@@ -133,10 +134,12 @@
   size = 1;
   uhwptr *frame = (uhwptr *)bp;
   uhwptr *prev_frame = frame - 1;
+  if (stack_top < 4096) return;  // Sanity check for stack top.
   // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
   while (frame > prev_frame &&
          frame < (uhwptr *)stack_top - 2 &&
          frame > (uhwptr *)stack_bottom &&
+         IsAligned((uptr)frame, sizeof(*frame)) &&
          size < max_size) {
     uhwptr pc1 = frame[1];
     if (pc1 != pc) {
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h
index b9ea9b4..76d52bd 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.h
+++ b/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -19,6 +19,15 @@
 
 static const uptr kStackTraceMax = 256;
 
+#if SANITIZER_LINUX && (defined(__arm__) || \
+    defined(__powerpc__) || defined(__powerpc64__) || \
+    defined(__sparc__) || \
+    defined(__mips__))
+#define SANITIZER_CAN_FAST_UNWIND 0
+#else
+#define SANITIZER_CAN_FAST_UNWIND 1
+#endif
+
 struct StackTrace {
   typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
                                      int out_size);
@@ -61,6 +70,9 @@
 const char *StripPathPrefix(const char *filepath,
                             const char *strip_file_prefix);
 
+void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+                   uptr stack_top, uptr stack_bottom, bool fast);
+
 }  // namespace __sanitizer
 
 // Use this macro if you want to print stack trace with the caller
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld.h b/lib/sanitizer_common/sanitizer_stoptheworld.h
index 5dd3498..a326467 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld.h
+++ b/lib/sanitizer_common/sanitizer_stoptheworld.h
@@ -20,21 +20,21 @@
 namespace __sanitizer {
 typedef int SuspendedThreadID;
 
-// Holds the list of suspended threads. Also provides register dumping
-// functionality (to be implemented).
+// Holds the list of suspended threads and provides an interface to dump their
+// register contexts.
 class SuspendedThreadsList {
  public:
   SuspendedThreadsList()
     : thread_ids_(1024) {}
-  SuspendedThreadID GetThreadID(uptr index) {
+  SuspendedThreadID GetThreadID(uptr index) const {
     CHECK_LT(index, thread_ids_.size());
     return thread_ids_[index];
   }
-  void DumpRegisters(uptr index) const {
-    UNIMPLEMENTED();
-  }
-  uptr thread_count() { return thread_ids_.size(); }
-  bool Contains(SuspendedThreadID thread_id) {
+  int GetRegistersAndSP(uptr index, uptr *buffer, uptr *sp) const;
+  // The buffer in GetRegistersAndSP should be at least this big.
+  static uptr RegisterCount();
+  uptr thread_count() const { return thread_ids_.size(); }
+  bool Contains(SuspendedThreadID thread_id) const {
     for (uptr i = 0; i < thread_ids_.size(); i++) {
       if (thread_ids_[i] == thread_id)
         return true;
@@ -46,7 +46,7 @@
   }
 
  private:
-  InternalVector<SuspendedThreadID> thread_ids_;
+  InternalMmapVector<SuspendedThreadID> thread_ids_;
 
   // Prohibit copy and assign.
   SuspendedThreadsList(const SuspendedThreadsList&);
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
similarity index 75%
rename from lib/sanitizer_common/sanitizer_stoptheworld_linux.cc
rename to lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index e072780..d8f3ca5 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -1,4 +1,4 @@
-//===-- sanitizer_stoptheworld_linux.cc -----------------------------------===//
+//===-- sanitizer_stoptheworld_linux_libcdep.cc ---------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -12,7 +12,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifdef __linux__
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "sanitizer_stoptheworld.h"
 
@@ -22,6 +24,11 @@
 #include <sys/prctl.h> // for PR_* definitions
 #include <sys/ptrace.h> // for PTRACE_* definitions
 #include <sys/types.h> // for pid_t
+#if SANITIZER_ANDROID && defined(__arm__)
+# include <linux/user.h>  // for pt_regs
+#else
+# include <sys/user.h>  // for user_regs_struct
+#endif
 #include <sys/wait.h> // for signal-related stuff
 
 #include "sanitizer_common.h"
@@ -94,23 +101,26 @@
   // usually small.
   if (suspended_threads_list_.Contains(thread_id))
     return false;
-  if (internal_ptrace(PTRACE_ATTACH, thread_id, NULL, NULL) != 0) {
+  int pterrno;
+  if (internal_iserror(internal_ptrace(PTRACE_ATTACH, thread_id, NULL, NULL),
+                       &pterrno)) {
     // Either the thread is dead, or something prevented us from attaching.
     // Log this event and move on.
-    Report("Could not attach to thread %d (errno %d).\n", thread_id, errno);
+    Report("Could not attach to thread %d (errno %d).\n", thread_id, pterrno);
     return false;
   } else {
     if (SanitizerVerbosity > 0)
       Report("Attached to thread %d.\n", thread_id);
     // The thread is not guaranteed to stop before ptrace returns, so we must
     // wait on it.
-    int waitpid_status;
+    uptr waitpid_status;
     HANDLE_EINTR(waitpid_status, internal_waitpid(thread_id, NULL, __WALL));
-    if (waitpid_status < 0) {
+    int wperrno;
+    if (internal_iserror(waitpid_status, &wperrno)) {
       // Got a ECHILD error. I don't think this situation is possible, but it
       // doesn't hurt to report it.
       Report("Waiting on thread %d failed, detaching (errno %d).\n", thread_id,
-             errno);
+             wperrno);
       internal_ptrace(PTRACE_DETACH, thread_id, NULL, NULL);
       return false;
     }
@@ -122,14 +132,16 @@
 void ThreadSuspender::ResumeAllThreads() {
   for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) {
     pid_t tid = suspended_threads_list_.GetThreadID(i);
-    if (internal_ptrace(PTRACE_DETACH, tid, NULL, NULL) == 0) {
+    int pterrno;
+    if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL),
+                          &pterrno)) {
       if (SanitizerVerbosity > 0)
         Report("Detached from thread %d.\n", tid);
     } else {
       // Either the thread is dead, or we are already detached.
       // The latter case is possible, for instance, if this function was called
       // from a signal handler.
-      Report("Could not detach from thread %d (errno %d).\n", tid, errno);
+      Report("Could not detach from thread %d (errno %d).\n", tid, pterrno);
     }
   }
 }
@@ -141,27 +153,24 @@
 }
 
 bool ThreadSuspender::SuspendAllThreads() {
-  void *mem = InternalAlloc(sizeof(ThreadLister));
-  ThreadLister *thread_lister = new(mem) ThreadLister(pid_);
+  ThreadLister thread_lister(pid_);
   bool added_threads;
   do {
     // Run through the directory entries once.
     added_threads = false;
-    pid_t tid = thread_lister->GetNextTID();
+    pid_t tid = thread_lister.GetNextTID();
     while (tid >= 0) {
       if (SuspendThread(tid))
         added_threads = true;
-      tid = thread_lister->GetNextTID();
+      tid = thread_lister.GetNextTID();
     }
-    if (thread_lister->error()) {
+    if (thread_lister.error()) {
       // Detach threads and fail.
       ResumeAllThreads();
-      InternalFree(mem);
       return false;
     }
-    thread_lister->Reset();
+    thread_lister.Reset();
   } while (added_threads);
-  InternalFree(mem);
   return true;
 }
 
@@ -245,11 +254,44 @@
   return exit_code;
 }
 
+class ScopedStackSpaceWithGuard {
+ public:
+  explicit ScopedStackSpaceWithGuard(uptr stack_size) {
+    stack_size_ = stack_size;
+    guard_size_ = GetPageSizeCached();
+    // FIXME: Omitting MAP_STACK here works in current kernels but might break
+    // in the future.
+    guard_start_ = (uptr)MmapOrDie(stack_size_ + guard_size_,
+                                   "ScopedStackWithGuard");
+    CHECK_EQ(guard_start_, (uptr)Mprotect((uptr)guard_start_, guard_size_));
+  }
+  ~ScopedStackSpaceWithGuard() {
+    UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_);
+  }
+  void *Bottom() const {
+    return (void *)(guard_start_ + stack_size_ + guard_size_);
+  }
+
+ private:
+  uptr stack_size_;
+  uptr guard_size_;
+  uptr guard_start_;
+};
+
+NOINLINE static void WipeStack() {
+  char arr[256];
+  internal_memset(arr, 0, sizeof(arr));
+}
+
 static sigset_t blocked_sigset;
 static sigset_t old_sigset;
 static struct sigaction old_sigactions[ARRAY_SIZE(kUnblockedSignals)];
 
 void StopTheWorld(StopTheWorldCallback callback, void *argument) {
+  // Glibc's sigaction() has a side-effect where it copies garbage stack values
+  // into oldact, which can cause false negatives in LSan. As a quick workaround
+  // we zero some stack space here.
+  WipeStack();
   // Block all signals that can be blocked safely, and install default handlers
   // for the remaining signals.
   // We cannot allow user-defined handlers to run while the ThreadSuspender
@@ -279,18 +321,14 @@
   struct TracerThreadArgument tracer_thread_argument;
   tracer_thread_argument.callback = callback;
   tracer_thread_argument.callback_argument = argument;
+  const uptr kTracerStackSize = 2 * 1024 * 1024;
+  ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize);
   // Block the execution of TracerThread until after we have set ptrace
   // permissions.
   tracer_thread_argument.mutex.Lock();
-  // The tracer thread will run on the same stack, so we must reserve some
-  // stack space for the caller thread to run in as it waits on the tracer.
-  const uptr kReservedStackSize = 4096;
-  // Get a 16-byte aligned pointer for stack.
-  int a_local_variable __attribute__((__aligned__(16)));
-  pid_t tracer_pid = clone(TracerThread,
-                          (char *)&a_local_variable - kReservedStackSize,
-                          CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED,
-                          &tracer_thread_argument, 0, 0, 0);
+  pid_t tracer_pid = clone(TracerThread, tracer_stack.Bottom(),
+                           CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED,
+                           &tracer_thread_argument);
   if (tracer_pid < 0) {
     Report("Failed spawning a tracer thread (errno %d).\n", errno);
     tracer_thread_argument.mutex.Unlock();
@@ -306,9 +344,10 @@
     // must avoid using errno while the tracer thread is running.
     // At this point, any signal will either be blocked or kill us, so waitpid
     // should never return (and set errno) while the tracer thread is alive.
-    int waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
-    if (waitpid_status < 0)
-      Report("Waiting on the tracer thread failed (errno %d).\n", errno);
+    uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
+    int wperrno;
+    if (internal_iserror(waitpid_status, &wperrno))
+      Report("Waiting on the tracer thread failed (errno %d).\n", wperrno);
   }
   // Restore the dumpable flag.
   if (!process_was_dumpable)
@@ -322,6 +361,56 @@
   sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
 }
 
+// Platform-specific methods from SuspendedThreadsList.
+#if SANITIZER_ANDROID && defined(__arm__)
+typedef pt_regs regs_struct;
+#define REG_SP ARM_sp
+
+#elif SANITIZER_LINUX && defined(__arm__)
+typedef user_regs regs_struct;
+#define REG_SP uregs[13]
+
+#elif defined(__i386__) || defined(__x86_64__)
+typedef user_regs_struct regs_struct;
+#if defined(__i386__)
+#define REG_SP esp
+#else
+#define REG_SP rsp
+#endif
+
+#elif defined(__powerpc__) || defined(__powerpc64__)
+typedef pt_regs regs_struct;
+#define REG_SP gpr[PT_R1]
+
+#elif defined(__mips__)
+typedef struct user regs_struct;
+#define REG_SP regs[EF_REG29]
+
+#else
+#error "Unsupported architecture"
+#endif // SANITIZER_ANDROID && defined(__arm__)
+
+int SuspendedThreadsList::GetRegistersAndSP(uptr index,
+                                            uptr *buffer,
+                                            uptr *sp) const {
+  pid_t tid = GetThreadID(index);
+  regs_struct regs;
+  int pterrno;
+  if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, &regs),
+                       &pterrno)) {
+    Report("Could not get registers from thread %d (errno %d).\n",
+           tid, pterrno);
+    return -1;
+  }
+
+  *sp = regs.REG_SP;
+  internal_memcpy(buffer, &regs, sizeof(regs));
+  return 0;
+}
+
+uptr SuspendedThreadsList::RegisterCount() {
+  return sizeof(regs_struct) / sizeof(uptr);
+}
 }  // namespace __sanitizer
 
-#endif  // __linux__
+#endif  // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc
new file mode 100644
index 0000000..0676c0b
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_suppressions.cc
@@ -0,0 +1,148 @@
+//===-- sanitizer_suppressions.cc -----------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Suppression parsing/matching code shared between TSan and LSan.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_suppressions.h"
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+static const char *const kTypeStrings[SuppressionTypeCount] = {
+  "none", "race", "mutex", "thread", "signal", "leak"
+};
+
+bool TemplateMatch(char *templ, const char *str) {
+  if (str == 0 || str[0] == 0)
+    return false;
+  bool start = false;
+  if (templ && templ[0] == '^') {
+    start = true;
+    templ++;
+  }
+  bool asterisk = false;
+  while (templ && templ[0]) {
+    if (templ[0] == '*') {
+      templ++;
+      start = false;
+      asterisk = true;
+      continue;
+    }
+    if (templ[0] == '$')
+      return str[0] == 0 || asterisk;
+    if (str[0] == 0)
+      return false;
+    char *tpos = (char*)internal_strchr(templ, '*');
+    char *tpos1 = (char*)internal_strchr(templ, '$');
+    if (tpos == 0 || (tpos1 && tpos1 < tpos))
+      tpos = tpos1;
+    if (tpos != 0)
+      tpos[0] = 0;
+    const char *str0 = str;
+    const char *spos = internal_strstr(str, templ);
+    str = spos + internal_strlen(templ);
+    templ = tpos;
+    if (tpos)
+      tpos[0] = tpos == tpos1 ? '$' : '*';
+    if (spos == 0)
+      return false;
+    if (start && spos != str0)
+      return false;
+    start = false;
+    asterisk = false;
+  }
+  return true;
+}
+
+bool SuppressionContext::Match(const char *str, SuppressionType type,
+                               Suppression **s) {
+  can_parse_ = false;
+  uptr i;
+  for (i = 0; i < suppressions_.size(); i++)
+    if (type == suppressions_[i].type &&
+        TemplateMatch(suppressions_[i].templ, str))
+      break;
+  if (i == suppressions_.size()) return false;
+  *s = &suppressions_[i];
+  return true;
+}
+
+static const char *StripPrefix(const char *str, const char *prefix) {
+  while (str && *str == *prefix) {
+    str++;
+    prefix++;
+  }
+  if (!*prefix)
+    return str;
+  return 0;
+}
+
+void SuppressionContext::Parse(const char *str) {
+  // Context must not mutate once Match has been called.
+  CHECK(can_parse_);
+  const char *line = str;
+  while (line) {
+    while (line[0] == ' ' || line[0] == '\t')
+      line++;
+    const char *end = internal_strchr(line, '\n');
+    if (end == 0)
+      end = line + internal_strlen(line);
+    if (line != end && line[0] != '#') {
+      const char *end2 = end;
+      while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
+        end2--;
+      int type;
+      for (type = 0; type < SuppressionTypeCount; type++) {
+        const char *next_char = StripPrefix(line, kTypeStrings[type]);
+        if (next_char && *next_char == ':') {
+          line = ++next_char;
+          break;
+        }
+      }
+      if (type == SuppressionTypeCount) {
+        Printf("%s: failed to parse suppressions\n", SanitizerToolName);
+        Die();
+      }
+      Suppression s;
+      s.type = static_cast<SuppressionType>(type);
+      s.templ = (char*)InternalAlloc(end2 - line + 1);
+      internal_memcpy(s.templ, line, end2 - line);
+      s.templ[end2 - line] = 0;
+      s.hit_count = 0;
+      s.weight = 0;
+      suppressions_.push_back(s);
+    }
+    if (end[0] == 0)
+      break;
+    line = end + 1;
+  }
+}
+
+uptr SuppressionContext::SuppressionCount() {
+  return suppressions_.size();
+}
+
+void SuppressionContext::GetMatched(
+    InternalMmapVector<Suppression *> *matched) {
+  for (uptr i = 0; i < suppressions_.size(); i++)
+    if (suppressions_[i].hit_count)
+      matched->push_back(&suppressions_[i]);
+}
+
+const char *SuppressionTypeString(SuppressionType t) {
+  CHECK(t < SuppressionTypeCount);
+  return kTypeStrings[t];
+}
+
+}  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_suppressions.h b/lib/sanitizer_common/sanitizer_suppressions.h
new file mode 100644
index 0000000..e0b562e
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_suppressions.h
@@ -0,0 +1,60 @@
+//===-- sanitizer_suppressions.h --------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Suppression parsing/matching code shared between TSan and LSan.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SUPPRESSIONS_H
+#define SANITIZER_SUPPRESSIONS_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+
+enum SuppressionType {
+  SuppressionNone,
+  SuppressionRace,
+  SuppressionMutex,
+  SuppressionThread,
+  SuppressionSignal,
+  SuppressionLeak,
+  SuppressionTypeCount
+};
+
+struct Suppression {
+  SuppressionType type;
+  char *templ;
+  unsigned hit_count;
+  uptr weight;
+};
+
+class SuppressionContext {
+ public:
+  SuppressionContext() : suppressions_(1), can_parse_(true) {}
+  void Parse(const char *str);
+  bool Match(const char* str, SuppressionType type, Suppression **s);
+  uptr SuppressionCount();
+  void GetMatched(InternalMmapVector<Suppression *> *matched);
+
+ private:
+  InternalMmapVector<Suppression> suppressions_;
+  bool can_parse_;
+
+  friend class SuppressionContextTest;
+};
+
+const char *SuppressionTypeString(SuppressionType t);
+
+// Exposed for testing.
+bool TemplateMatch(char *templ, const char *str);
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_SUPPRESSIONS_H
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h
index dd2037e..5a15a3f 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.h
+++ b/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -43,7 +43,7 @@
     internal_memset(this, 0, sizeof(AddressInfo));
   }
   // Deletes all strings and sets all fields to zero.
-  void Clear();
+  void Clear() SANITIZER_WEAK_ATTRIBUTE;
 
   void FillAddressAndModuleInfo(uptr addr, const char *mod_name,
                                 uptr mod_offset) {
@@ -66,18 +66,24 @@
 // for a given address (in all inlined functions). Returns the number
 // of descriptions actually filled.
 // This function should NOT be called from two threads simultaneously.
-uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames);
+uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames)
+    SANITIZER_WEAK_ATTRIBUTE;
 bool SymbolizeData(uptr address, DataInfo *info);
 
 bool IsSymbolizerAvailable();
+void FlushSymbolizer();  // releases internal caches (if any)
 
 // Attempts to demangle the provided C++ mangled name.
-const char *Demangle(const char *Name);
+const char *Demangle(const char *name);
+// Attempts to demangle the name via __cxa_demangle from __cxxabiv1.
+const char *DemangleCXXABI(const char *name);
 
 // Starts external symbolizer program in a subprocess. Sanitizer communicates
 // with external symbolizer via pipes.
 bool InitializeExternalSymbolizer(const char *path_to_symbolizer);
 
+const int kSymbolizerStartupTimeMillis = 10;
+
 class LoadedModule {
  public:
   LoadedModule(const char *module_name, uptr base_address);
@@ -106,8 +112,13 @@
 
 // OS-dependent function that fills array with descriptions of at most
 // "max_modules" currently loaded modules. Returns the number of
-// initialized modules.
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules);
+// initialized modules. If filter is nonzero, ignores modules for which
+// filter(full_name) is false.
+typedef bool (*string_predicate_t)(const char *);
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+                      string_predicate_t filter);
+
+void SymbolizerPrepareForSandboxing();
 
 }  // namespace __sanitizer
 
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc b/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc
index 4386294..93a26e6 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_itanium.cc
@@ -10,7 +10,9 @@
 // This file is shared between the sanitizer run-time libraries.
 // Itanium C++ ABI-specific implementation of symbolizer parts.
 //===----------------------------------------------------------------------===//
-#if defined(__APPLE__) || defined(__linux__)
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC || SANITIZER_LINUX
 
 #include "sanitizer_symbolizer.h"
 
@@ -25,18 +27,18 @@
     SANITIZER_WEAK_ATTRIBUTE;
 }
 
-const char *__sanitizer::Demangle(const char *MangledName) {
+const char *__sanitizer::DemangleCXXABI(const char *name) {
   // FIXME: __cxa_demangle aggressively insists on allocating memory.
   // There's not much we can do about that, short of providing our
   // own demangler (libc++abi's implementation could be adapted so that
   // it does not allocate). For now, we just call it anyway, and we leak
   // the returned value.
   if (__cxxabiv1::__cxa_demangle)
-    if (const char *Demangled =
-          __cxxabiv1::__cxa_demangle(MangledName, 0, 0, 0))
-      return Demangled;
+    if (const char *demangled_name =
+          __cxxabiv1::__cxa_demangle(name, 0, 0, 0))
+      return demangled_name;
 
-  return MangledName;
+  return name;
 }
 
-#endif  // __APPLE__ || __linux__
+#endif  // SANITIZER_MAC || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
similarity index 83%
rename from lib/sanitizer_common/sanitizer_symbolizer.cc
rename to lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
index 5609e91..4f0b2ab 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -1,4 +1,4 @@
-//===-- sanitizer_symbolizer.cc -------------------------------------------===//
+//===-- sanitizer_symbolizer_libcdep.cc -----------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -11,6 +11,7 @@
 // run-time libraries. See sanitizer_symbolizer.h for details.
 //===----------------------------------------------------------------------===//
 
+#include "sanitizer_allocator_internal.h"
 #include "sanitizer_common.h"
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
@@ -111,7 +112,7 @@
 
   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
     CHECK(module_name);
-    internal_snprintf(buffer_, kBufferSize, "%s%s 0x%zx\n",
+    internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
                       is_data ? "DATA " : "", module_name, module_offset);
     if (!writeToSymbolizer(buffer_, internal_strlen(buffer_)))
       return 0;
@@ -128,6 +129,9 @@
     return StartSymbolizerSubprocess(path_, &input_fd_, &output_fd_);
   }
 
+  void Flush() {
+  }
+
  private:
   bool readFromSymbolizer(char *buffer, uptr max_length) {
     if (max_length == 0)
@@ -184,11 +188,17 @@
 SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
 bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
                                 char *Buffer, int MaxLength);
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_symbolize_flush();
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+int __sanitizer_symbolize_demangle(const char *Name, char *Buffer,
+                                   int MaxLength);
 }  // extern "C"
 
 class InternalSymbolizer {
  public:
   typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int);
+
   static InternalSymbolizer *get() {
     if (__sanitizer_symbolize_code != 0 &&
         __sanitizer_symbolize_data != 0) {
@@ -197,6 +207,7 @@
     }
     return 0;
   }
+
   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
     SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data
                                                 : __sanitizer_symbolize_code;
@@ -205,10 +216,34 @@
     return 0;
   }
 
+  void Flush() {
+    if (__sanitizer_symbolize_flush)
+      __sanitizer_symbolize_flush();
+  }
+
+  const char *Demangle(const char *name) {
+    if (__sanitizer_symbolize_demangle) {
+      for (uptr res_length = 1024;
+           res_length <= InternalSizeClassMap::kMaxSize;) {
+        char *res_buff = static_cast<char*>(InternalAlloc(res_length));
+        uptr req_length =
+            __sanitizer_symbolize_demangle(name, res_buff, res_length);
+        if (req_length > res_length) {
+          res_length = req_length + 1;
+          InternalFree(res_buff);
+          continue;
+        }
+        return res_buff;
+      }
+    }
+    return name;
+  }
+
  private:
   InternalSymbolizer() { }
 
   static const int kBufferSize = 16 * 1024;
+  static const int kMaxDemangledNameSize = 1024;
   char buffer_[kBufferSize];
 };
 #else  // SANITIZER_SUPPORTS_WEAK_HOOKS
@@ -219,11 +254,15 @@
   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
     return 0;
   }
+  void Flush() { }
+  const char *Demangle(const char *name) { return name; }
 };
 
 #endif  // SANITIZER_SUPPORTS_WEAK_HOOKS
 
 class Symbolizer {
+  // This class has no constructor, as global constructors are forbidden in
+  // sanitizer_common. It should be linker initialized instead.
  public:
   uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
     if (max_frames == 0)
@@ -321,6 +360,19 @@
     return internal_symbolizer_ || external_symbolizer_;
   }
 
+  void Flush() {
+    if (internal_symbolizer_)
+      internal_symbolizer_->Flush();
+    if (external_symbolizer_)
+      external_symbolizer_->Flush();
+  }
+
+  const char *Demangle(const char *name) {
+    if (IsSymbolizerAvailable() && internal_symbolizer_ != 0)
+      return internal_symbolizer_->Demangle(name);
+    return DemangleCXXABI(name);
+  }
+
  private:
   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
     // First, try to use internal symbolizer.
@@ -355,22 +407,35 @@
   }
 
   LoadedModule *FindModuleForAddress(uptr address) {
-    if (modules_ == 0) {
+    bool modules_were_reloaded = false;
+    if (modules_ == 0 || !modules_fresh_) {
       modules_ = (LoadedModule*)(symbolizer_allocator.Allocate(
           kMaxNumberOfModuleContexts * sizeof(LoadedModule)));
       CHECK(modules_);
-      n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts);
+      n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
+                                    /* filter */ 0);
       // FIXME: Return this check when GetListOfModules is implemented on Mac.
       // CHECK_GT(n_modules_, 0);
       CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
+      modules_fresh_ = true;
+      modules_were_reloaded = true;
     }
     for (uptr i = 0; i < n_modules_; i++) {
       if (modules_[i].containsAddress(address)) {
         return &modules_[i];
       }
     }
+    // Reload the modules and look up again, if we haven't tried it yet.
+    if (!modules_were_reloaded) {
+      // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
+      // It's too aggressive to reload the list of modules each time we fail
+      // to find a module for a given address.
+      modules_fresh_ = false;
+      return FindModuleForAddress(address);
+    }
     return 0;
   }
+
   void ReportExternalSymbolizerError(const char *msg) {
     // Don't use atomics here for now, as SymbolizeCode can't be called
     // from multiple threads anyway.
@@ -385,6 +450,8 @@
   static const uptr kMaxNumberOfModuleContexts = 1 << 14;
   LoadedModule *modules_;  // Array of module descriptions is leaked.
   uptr n_modules_;
+  // If stale, need to reload the modules before looking up addresses.
+  bool modules_fresh_;
 
   ExternalSymbolizer *external_symbolizer_;  // Leaked.
   InternalSymbolizer *internal_symbolizer_;  // Leaked.
@@ -408,4 +475,12 @@
   return symbolizer.IsSymbolizerAvailable();
 }
 
+void FlushSymbolizer() {
+  symbolizer.Flush();
+}
+
+const char *Demangle(const char *name) {
+  return symbolizer.Demangle(name);
+}
+
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_linux.cc b/lib/sanitizer_common/sanitizer_symbolizer_linux.cc
index fbc1284..50f6da7 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_linux.cc
@@ -11,173 +11,53 @@
 // run-time libraries.
 // Linux-specific implementation of symbolizer parts.
 //===----------------------------------------------------------------------===//
-#ifdef __linux__
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
 #include "sanitizer_common.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_placement_new.h"
-#include "sanitizer_symbolizer.h"
-
-#include <elf.h>
-#include <errno.h>
-#include <poll.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#if !defined(__ANDROID__) && !defined(ANDROID)
-#include <link.h>
-#endif
+#include "sanitizer_linux.h"
 
 namespace __sanitizer {
 
-static const int kSymbolizerStartupTimeMillis = 10;
+#if SANITIZER_ANDROID
+void SymbolizerPrepareForSandboxing() {
+  // Do nothing on Android.
+}
+#else
+static char proc_self_exe_cache_str[kMaxPathLength];
+static uptr proc_self_exe_cache_len = 0;
 
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
-                               int *input_fd, int *output_fd) {
-  if (!FileExists(path_to_symbolizer)) {
-    Report("WARNING: invalid path to external symbolizer!\n");
-    return false;
-  }
-
-  int *infd = NULL;
-  int *outfd = NULL;
-  // The client program may close its stdin and/or stdout and/or stderr
-  // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
-  // In this case the communication between the forked processes may be
-  // broken if either the parent or the child tries to close or duplicate
-  // these descriptors. The loop below produces two pairs of file
-  // descriptors, each greater than 2 (stderr).
-  int sock_pair[5][2];
-  for (int i = 0; i < 5; i++) {
-    if (pipe(sock_pair[i]) == -1) {
-      for (int j = 0; j < i; j++) {
-        internal_close(sock_pair[j][0]);
-        internal_close(sock_pair[j][1]);
-      }
-      Report("WARNING: Can't create a socket pair to start "
-             "external symbolizer (errno: %d)\n", errno);
-      return false;
-    } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
-      if (infd == NULL) {
-        infd = sock_pair[i];
-      } else {
-        outfd = sock_pair[i];
-        for (int j = 0; j < i; j++) {
-          if (sock_pair[j] == infd) continue;
-          internal_close(sock_pair[j][0]);
-          internal_close(sock_pair[j][1]);
-        }
-        break;
-      }
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
+  uptr module_name_len = internal_readlink(
+      "/proc/self/exe", buf, buf_len);
+  int readlink_error;
+  if (internal_iserror(buf_len, &readlink_error)) {
+    if (proc_self_exe_cache_len) {
+      // If available, use the cached module name.
+      CHECK_LE(proc_self_exe_cache_len, buf_len);
+      internal_strncpy(buf, proc_self_exe_cache_str, buf_len);
+      module_name_len = internal_strlen(proc_self_exe_cache_str);
+    } else {
+      // We can't read /proc/self/exe for some reason, assume the name of the
+      // binary is unknown.
+      Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, "
+             "some stack frames may not be symbolized\n", readlink_error);
+      module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe");
     }
+    CHECK_LT(module_name_len, buf_len);
+    buf[module_name_len] = '\0';
   }
-  CHECK(infd);
-  CHECK(outfd);
-
-  int pid = fork();
-  if (pid == -1) {
-    // Fork() failed.
-    internal_close(infd[0]);
-    internal_close(infd[1]);
-    internal_close(outfd[0]);
-    internal_close(outfd[1]);
-    Report("WARNING: failed to fork external symbolizer "
-           " (errno: %d)\n", errno);
-    return false;
-  } else if (pid == 0) {
-    // Child subprocess.
-    internal_close(STDOUT_FILENO);
-    internal_close(STDIN_FILENO);
-    internal_dup2(outfd[0], STDIN_FILENO);
-    internal_dup2(infd[1], STDOUT_FILENO);
-    internal_close(outfd[0]);
-    internal_close(outfd[1]);
-    internal_close(infd[0]);
-    internal_close(infd[1]);
-    for (int fd = getdtablesize(); fd > 2; fd--)
-      internal_close(fd);
-    execl(path_to_symbolizer, path_to_symbolizer, (char*)0);
-    internal__exit(1);
-  }
-
-  // Continue execution in parent process.
-  internal_close(outfd[0]);
-  internal_close(infd[1]);
-  *input_fd = infd[0];
-  *output_fd = outfd[1];
-
-  // Check that symbolizer subprocess started successfully.
-  int pid_status;
-  SleepForMillis(kSymbolizerStartupTimeMillis);
-  int exited_pid = waitpid(pid, &pid_status, WNOHANG);
-  if (exited_pid != 0) {
-    // Either waitpid failed, or child has already exited.
-    Report("WARNING: external symbolizer didn't start up correctly!\n");
-    return false;
-  }
-
-  return true;
+  return module_name_len;
 }
 
-#if defined(__ANDROID__) || defined(ANDROID)
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
-  UNIMPLEMENTED();
-  return max_modules;
-}
-#else  // ANDROID
-typedef ElfW(Phdr) Elf_Phdr;
-
-struct DlIteratePhdrData {
-  LoadedModule *modules;
-  uptr current_n;
-  uptr max_n;
-};
-
-static const uptr kMaxPathLength = 512;
-
-static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
-  DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
-  if (data->current_n == data->max_n)
-    return 0;
-  InternalScopedBuffer<char> module_name(kMaxPathLength);
-  module_name.data()[0] = '\0';
-  if (data->current_n == 0) {
-    // First module is the binary itself.
-    uptr module_name_len = internal_readlink(
-        "/proc/self/exe", module_name.data(), module_name.size());
-    CHECK_NE(module_name_len, (uptr)-1);
-    CHECK_LT(module_name_len, module_name.size());
-    module_name[module_name_len] = '\0';
-  } else if (info->dlpi_name) {
-    internal_strncpy(module_name.data(), info->dlpi_name, module_name.size());
+void SymbolizerPrepareForSandboxing() {
+  if (!proc_self_exe_cache_len) {
+    proc_self_exe_cache_len =
+        ReadBinaryName(proc_self_exe_cache_str, kMaxPathLength);
   }
-  if (module_name.data()[0] == '\0')
-    return 0;
-  void *mem = &data->modules[data->current_n];
-  LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
-                                                   info->dlpi_addr);
-  data->current_n++;
-  for (int i = 0; i < info->dlpi_phnum; i++) {
-    const Elf_Phdr *phdr = &info->dlpi_phdr[i];
-    if (phdr->p_type == PT_LOAD) {
-      uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
-      uptr cur_end = cur_beg + phdr->p_memsz;
-      cur_module->addAddressRange(cur_beg, cur_end);
-    }
-  }
-  return 0;
 }
-
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
-  CHECK(modules);
-  DlIteratePhdrData data = {modules, 0, max_modules};
-  dl_iterate_phdr(dl_iterate_phdr_cb, &data);
-  return data.current_n;
-}
-#endif  // ANDROID
+#endif  // SANITIZER_ANDROID
 
 }  // namespace __sanitizer
 
-#endif  // __linux__
+#endif  // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc
new file mode 100644
index 0000000..f0ef23b
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_linux_libcdep.cc
@@ -0,0 +1,100 @@
+//===-- sanitizer_symbolizer_linux_libcdep.cc -----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// Linux-specific implementation of symbolizer parts.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_linux.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_symbolizer.h"
+
+// Android NDK r8e elf.h depends on stdint.h without including the latter.
+#include <stdint.h>
+
+#include <elf.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#if !SANITIZER_ANDROID
+#include <link.h>
+#endif
+
+namespace __sanitizer {
+
+#if SANITIZER_ANDROID
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+                      string_predicate_t filter) {
+  return 0;
+}
+#else  // SANITIZER_ANDROID
+typedef ElfW(Phdr) Elf_Phdr;
+
+struct DlIteratePhdrData {
+  LoadedModule *modules;
+  uptr current_n;
+  bool first;
+  uptr max_n;
+  string_predicate_t filter;
+};
+
+static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
+  DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
+  if (data->current_n == data->max_n)
+    return 0;
+  InternalScopedBuffer<char> module_name(kMaxPathLength);
+  module_name.data()[0] = '\0';
+  if (data->first) {
+    data->first = false;
+    // First module is the binary itself.
+    ReadBinaryName(module_name.data(), module_name.size());
+  } else if (info->dlpi_name) {
+    internal_strncpy(module_name.data(), info->dlpi_name, module_name.size());
+  }
+  if (module_name.data()[0] == '\0')
+    return 0;
+  if (data->filter && !data->filter(module_name.data()))
+    return 0;
+  void *mem = &data->modules[data->current_n];
+  LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
+                                                   info->dlpi_addr);
+  data->current_n++;
+  for (int i = 0; i < info->dlpi_phnum; i++) {
+    const Elf_Phdr *phdr = &info->dlpi_phdr[i];
+    if (phdr->p_type == PT_LOAD) {
+      uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
+      uptr cur_end = cur_beg + phdr->p_memsz;
+      cur_module->addAddressRange(cur_beg, cur_end);
+    }
+  }
+  return 0;
+}
+
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+                      string_predicate_t filter) {
+  CHECK(modules);
+  DlIteratePhdrData data = {modules, 0, true, max_modules, filter};
+  dl_iterate_phdr(dl_iterate_phdr_cb, &data);
+  return data.current_n;
+}
+#endif  // SANITIZER_ANDROID
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc b/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
index cd0d004..c44e3b3 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
@@ -11,22 +11,52 @@
 // run-time libraries.
 // Mac-specific implementation of symbolizer parts.
 //===----------------------------------------------------------------------===//
-#ifdef __APPLE__
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+#include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
 #include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
-bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
-                               int *input_fd, int *output_fd) {
-  UNIMPLEMENTED();
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+                      string_predicate_t filter) {
+  MemoryMappingLayout memory_mapping(false);
+  memory_mapping.Reset();
+  uptr cur_beg, cur_end, cur_offset;
+  InternalScopedBuffer<char> module_name(kMaxPathLength);
+  uptr n_modules = 0;
+  for (uptr i = 0;
+       n_modules < max_modules &&
+           memory_mapping.Next(&cur_beg, &cur_end, &cur_offset,
+                               module_name.data(), module_name.size(), 0);
+       i++) {
+    const char *cur_name = module_name.data();
+    if (cur_name[0] == '\0')
+      continue;
+    if (filter && !filter(cur_name))
+      continue;
+    LoadedModule *cur_module = 0;
+    if (n_modules > 0 &&
+        0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
+      cur_module = &modules[n_modules - 1];
+    } else {
+      void *mem = &modules[n_modules];
+      cur_module = new(mem) LoadedModule(cur_name, cur_beg);
+      n_modules++;
+    }
+    cur_module->addAddressRange(cur_beg, cur_end);
+  }
+  return n_modules;
 }
 
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
-  // FIXME: Actually implement this on Mac.
-  return 0;
+void SymbolizerPrepareForSandboxing() {
+  // Do nothing on Mac.
 }
 
 }  // namespace __sanitizer
 
-#endif  // __APPLE__
+#endif  // SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
new file mode 100644
index 0000000..b580f37
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -0,0 +1,127 @@
+//===-- sanitizer_symbolizer_posix_libcdep.cc -----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// POSIX-specific implementation of symbolizer parts.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_POSIX
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_symbolizer.h"
+
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+namespace __sanitizer {
+
+#if defined(__x86_64__)
+static const char* const kSymbolizerArch = "--default-arch=x86_64";
+#elif defined(__i386__)
+static const char* const kSymbolizerArch = "--default-arch=i386";
+#elif defined(__powerpc64__)
+static const char* const kSymbolizerArch = "--default-arch=powerpc64";
+#else
+static const char* const kSymbolizerArch = "--default-arch=unknown";
+#endif
+
+bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
+                               int *input_fd, int *output_fd) {
+  if (!FileExists(path_to_symbolizer)) {
+    Report("WARNING: invalid path to external symbolizer!\n");
+    return false;
+  }
+
+  int *infd = NULL;
+  int *outfd = NULL;
+  // The client program may close its stdin and/or stdout and/or stderr
+  // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
+  // In this case the communication between the forked processes may be
+  // broken if either the parent or the child tries to close or duplicate
+  // these descriptors. The loop below produces two pairs of file
+  // descriptors, each greater than 2 (stderr).
+  int sock_pair[5][2];
+  for (int i = 0; i < 5; i++) {
+    if (pipe(sock_pair[i]) == -1) {
+      for (int j = 0; j < i; j++) {
+        internal_close(sock_pair[j][0]);
+        internal_close(sock_pair[j][1]);
+      }
+      Report("WARNING: Can't create a socket pair to start "
+             "external symbolizer (errno: %d)\n", errno);
+      return false;
+    } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
+      if (infd == NULL) {
+        infd = sock_pair[i];
+      } else {
+        outfd = sock_pair[i];
+        for (int j = 0; j < i; j++) {
+          if (sock_pair[j] == infd) continue;
+          internal_close(sock_pair[j][0]);
+          internal_close(sock_pair[j][1]);
+        }
+        break;
+      }
+    }
+  }
+  CHECK(infd);
+  CHECK(outfd);
+
+  int pid = fork();
+  if (pid == -1) {
+    // Fork() failed.
+    internal_close(infd[0]);
+    internal_close(infd[1]);
+    internal_close(outfd[0]);
+    internal_close(outfd[1]);
+    Report("WARNING: failed to fork external symbolizer "
+           " (errno: %d)\n", errno);
+    return false;
+  } else if (pid == 0) {
+    // Child subprocess.
+    internal_close(STDOUT_FILENO);
+    internal_close(STDIN_FILENO);
+    internal_dup2(outfd[0], STDIN_FILENO);
+    internal_dup2(infd[1], STDOUT_FILENO);
+    internal_close(outfd[0]);
+    internal_close(outfd[1]);
+    internal_close(infd[0]);
+    internal_close(infd[1]);
+    for (int fd = getdtablesize(); fd > 2; fd--)
+      internal_close(fd);
+    execl(path_to_symbolizer, path_to_symbolizer, kSymbolizerArch, (char*)0);
+    internal__exit(1);
+  }
+
+  // Continue execution in parent process.
+  internal_close(outfd[0]);
+  internal_close(infd[1]);
+  *input_fd = infd[0];
+  *output_fd = outfd[1];
+
+  // Check that symbolizer subprocess started successfully.
+  int pid_status;
+  SleepForMillis(kSymbolizerStartupTimeMillis);
+  int exited_pid = waitpid(pid, &pid_status, WNOHANG);
+  if (exited_pid != 0) {
+    // Either waitpid failed, or child has already exited.
+    Report("WARNING: external symbolizer didn't start up correctly!\n");
+    return false;
+  }
+
+  return true;
+}
+
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
index f1b6a02..e2bd664 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -11,7 +11,9 @@
 // run-time libraries.
 // Windows-specific implementation of symbolizer parts.
 //===----------------------------------------------------------------------===//
-#ifdef _WIN32
+
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
 #include <windows.h>
 
 #include "sanitizer_internal_defs.h"
@@ -24,12 +26,17 @@
   UNIMPLEMENTED();
 }
 
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
+uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
+                      string_predicate_t filter) {
   UNIMPLEMENTED();
 };
 
-const char *Demangle(const char *MangledName) {
-  return MangledName;
+void SymbolizerPrepareForSandboxing() {
+  // Do nothing on Windows.
+}
+
+const char *DemangleCXXABI(const char *name) {
+  return name;
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_syscall_generic.inc b/lib/sanitizer_common/sanitizer_syscall_generic.inc
new file mode 100644
index 0000000..aac20a5
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_syscall_generic.inc
@@ -0,0 +1,24 @@
+//===-- sanitizer_syscall_generic.inc ---------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Generic implementations of internal_syscall and internal_iserror.
+//
+//===----------------------------------------------------------------------===//
+
+#define internal_syscall syscall
+
+bool internal_iserror(uptr retval, int *rverrno) {
+  if (retval == (uptr)-1) {
+    if (rverrno)
+      *rverrno = errno;
+    return true;
+  } else {
+    return false;
+  }
+}
diff --git a/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc b/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
new file mode 100644
index 0000000..e084b84
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
@@ -0,0 +1,87 @@
+//===-- sanitizer_syscall_linux_x86_64.inc ----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementations of internal_syscall and internal_iserror for Linux/x86_64.
+//
+//===----------------------------------------------------------------------===//
+
+static uptr internal_syscall(u64 nr) {
+  u64 retval;
+  asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11");
+  return retval;
+}
+
+template <typename T1>
+static uptr internal_syscall(u64 nr, T1 arg1) {
+  u64 retval;
+  asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1) :
+               "rcx", "r11");
+  return retval;
+}
+
+template <typename T1, typename T2>
+static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2) {
+  u64 retval;
+  asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
+               "S"((u64)arg2) : "rcx", "r11");
+  return retval;
+}
+
+template <typename T1, typename T2, typename T3>
+static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3) {
+  u64 retval;
+  asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
+               "S"((u64)arg2), "d"((u64)arg3) : "rcx", "r11");
+  return retval;
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
+  u64 retval;
+  asm volatile("mov %5, %%r10;"
+               "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
+               "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4) :
+               "rcx", "r11", "r10");
+  return retval;
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
+                             T5 arg5) {
+  u64 retval;
+  asm volatile("mov %5, %%r10;"
+               "mov %6, %%r8;"
+               "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
+               "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5) :
+               "rcx", "r11", "r10", "r8");
+  return retval;
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6>
+static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
+                             T5 arg5, T6 arg6) {
+  u64 retval;
+  asm volatile("mov %5, %%r10;"
+               "mov %6, %%r8;"
+               "mov %7, %%r9;"
+               "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
+               "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5),
+               "r"((u64)arg6) : "rcx", "r11", "r10", "r8", "r9");
+  return retval;
+}
+
+bool internal_iserror(uptr retval, int *rverrno) {
+  if (retval >= (uptr)-4095) {
+    if (rverrno)
+      *rverrno = -retval;
+    return true;
+  }
+  return false;
+}
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc
index 3d246fe..ff7c9de 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.cc
+++ b/lib/sanitizer_common/sanitizer_thread_registry.cc
@@ -22,11 +22,10 @@
   name[0] = '\0';
 }
 
-#ifndef SANITIZER_GO
 ThreadContextBase::~ThreadContextBase() {
+  // ThreadContextBase should never be deleted.
   CHECK(0);
 }
-#endif
 
 void ThreadContextBase::SetName(const char *new_name) {
   name[0] = '\0';
@@ -77,16 +76,16 @@
   OnCreated(arg);
 }
 
-void ThreadContextBase::Reset(void *arg) {
+void ThreadContextBase::Reset() {
   status = ThreadStatusInvalid;
   reuse_count++;
   SetName(0);
-  OnReset(arg);
+  OnReset();
 }
 
 // ThreadRegistry implementation.
 
-const u32 ThreadRegistry::kUnknownTid = -1U;
+const u32 ThreadRegistry::kUnknownTid = ~0U;
 
 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
                                u32 thread_quarantine_size)
@@ -102,6 +101,7 @@
   threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]),
                                              "ThreadRegistry");
   dead_threads_.clear();
+  invalid_threads_.clear();
 }
 
 void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
@@ -121,25 +121,18 @@
                                  void *arg) {
   BlockingMutexLock l(&mtx_);
   u32 tid = kUnknownTid;
-  ThreadContextBase *tctx = 0;
-  if (dead_threads_.size() > thread_quarantine_size_ ||
-      n_contexts_ >= max_threads_) {
-    // Reusing old thread descriptor and tid.
-    if (dead_threads_.size() == 0) {
-      Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
-             SanitizerToolName, max_threads_);
-      Die();
-    }
-    tctx = dead_threads_.front();
-    dead_threads_.pop_front();
-    CHECK_EQ(ThreadStatusDead, tctx->status);
-    tctx->Reset(arg);
+  ThreadContextBase *tctx = QuarantinePop();
+  if (tctx) {
     tid = tctx->tid;
-  } else {
+  } else if (n_contexts_ < max_threads_) {
     // Allocate new thread context and tid.
     tid = n_contexts_++;
     tctx = context_factory_(tid);
     threads_[tid] = tctx;
+  } else {
+    Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
+           SanitizerToolName, max_threads_);
+    Die();
   }
   CHECK_NE(tctx, 0);
   CHECK_NE(tid, kUnknownTid);
@@ -187,6 +180,17 @@
   return 0;
 }
 
+static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
+                                            void *arg) {
+  return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
+      tctx->status != ThreadStatusDead);
+}
+
+ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(uptr os_id) {
+  return FindThreadContextLocked(FindThreadContextByOsIdCallback,
+                                 (void *)os_id);
+}
+
 void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
   BlockingMutexLock l(&mtx_);
   CHECK_LT(tid, n_contexts_);
@@ -207,7 +211,7 @@
   }
   if (tctx->status == ThreadStatusFinished) {
     tctx->SetDead();
-    dead_threads_.push_back(tctx);
+    QuarantinePush(tctx);
   } else {
     tctx->detached = true;
   }
@@ -223,7 +227,7 @@
     return;
   }
   tctx->SetJoined(arg);
-  dead_threads_.push_back(tctx);
+  QuarantinePush(tctx);
 }
 
 void ThreadRegistry::FinishThread(u32 tid) {
@@ -239,7 +243,7 @@
   tctx->SetFinished();
   if (tctx->detached) {
     tctx->SetDead();
-    dead_threads_.push_back(tctx);
+    QuarantinePush(tctx);
   }
 }
 
@@ -253,4 +257,23 @@
   tctx->SetStarted(os_id, arg);
 }
 
+void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
+  dead_threads_.push_back(tctx);
+  if (dead_threads_.size() <= thread_quarantine_size_)
+    return;
+  tctx = dead_threads_.front();
+  dead_threads_.pop_front();
+  CHECK_EQ(tctx->status, ThreadStatusDead);
+  tctx->Reset();
+  invalid_threads_.push_back(tctx);
+}
+
+ThreadContextBase *ThreadRegistry::QuarantinePop() {
+  if (invalid_threads_.size() == 0)
+    return 0;
+  ThreadContextBase *tctx = invalid_threads_.front();
+  invalid_threads_.pop_front();
+  return tctx;
+}
+
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.h b/lib/sanitizer_common/sanitizer_thread_registry.h
index e2ee8f8..6072e7c 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -34,10 +34,7 @@
 class ThreadContextBase {
  public:
   explicit ThreadContextBase(u32 tid);
-#ifndef SANITIZER_GO  // Go does not have libstdc++
-  virtual
-#endif
-  ~ThreadContextBase();
+  ~ThreadContextBase();  // Should never be called.
 
   const u32 tid;  // Thread ID. Main thread should have tid = 0.
   u64 unique_id;  // Unique thread ID.
@@ -60,7 +57,7 @@
   void SetStarted(uptr _os_id, void *arg);
   void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
                   u32 _parent_tid, void *arg);
-  void Reset(void *arg);
+  void Reset();
 
   // The following methods may be overriden by subclasses.
   // Some of them take opaque arg that may be optionally be used
@@ -70,7 +67,7 @@
   virtual void OnFinished() {}
   virtual void OnStarted(void *arg) {}
   virtual void OnCreated(void *arg) {}
-  virtual void OnReset(void *arg) {}
+  virtual void OnReset() {}
 };
 
 typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
@@ -105,10 +102,11 @@
   // Finds a thread using the provided callback. Returns kUnknownTid if no
   // thread is found.
   u32 FindThread(FindThreadCallback cb, void *arg);
-  // Should be guarded by ThreadRegistryLock. Returns 0 if no thread
+  // Should be guarded by ThreadRegistryLock. Return 0 if no thread
   // is found.
   ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb,
                                              void *arg);
+  ThreadContextBase *FindThreadContextByOsIDLocked(uptr os_id);
 
   void SetThreadName(u32 tid, const char *name);
   void DetachThread(u32 tid);
@@ -133,6 +131,10 @@
 
   ThreadContextBase **threads_;  // Array of thread contexts is leaked.
   IntrusiveList<ThreadContextBase> dead_threads_;
+  IntrusiveList<ThreadContextBase> invalid_threads_;
+
+  void QuarantinePush(ThreadContextBase *tctx);
+  ThreadContextBase *QuarantinePop();
 };
 
 typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock;
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index 77afa47..0a43aca 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -11,7 +11,10 @@
 // run-time libraries and implements windows-specific functions from
 // sanitizer_libc.h.
 //===----------------------------------------------------------------------===//
-#ifdef _WIN32
+
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+
 #define WIN32_LEAN_AND_MEAN
 #define NOGDI
 #include <stdlib.h>
@@ -20,11 +23,14 @@
 
 #include "sanitizer_common.h"
 #include "sanitizer_libc.h"
-#include "sanitizer_placement_new.h"
 #include "sanitizer_mutex.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_stacktrace.h"
 
 namespace __sanitizer {
 
+#include "sanitizer_syscall_generic.inc"
+
 // --------------------- sanitizer_common.h
 uptr GetPageSize() {
   return 1U << 14;  // FIXME: is this configurable?
@@ -34,18 +40,30 @@
   return 1U << 16;  // FIXME: is this configurable?
 }
 
+uptr GetMaxVirtualAddress() {
+  SYSTEM_INFO si;
+  GetSystemInfo(&si);
+  return (uptr)si.lpMaximumApplicationAddress;
+}
+
 bool FileExists(const char *filename) {
   UNIMPLEMENTED();
 }
 
-int GetPid() {
+uptr internal_getpid() {
   return GetProcessId(GetCurrentProcess());
 }
 
-uptr GetThreadSelf() {
+// In contrast to POSIX, on Windows GetCurrentThreadId()
+// returns a system-unique identifier.
+uptr GetTid() {
   return GetCurrentThreadId();
 }
 
+uptr GetThreadSelf() {
+  return GetTid();
+}
+
 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                 uptr *stack_bottom) {
   CHECK(stack_top);
@@ -112,7 +130,7 @@
 }
 
 static const int kMaxEnvNameLength = 128;
-static const int kMaxEnvValueLength = 32767;
+static const DWORD kMaxEnvValueLength = 32767;
 
 namespace {
 
@@ -186,6 +204,10 @@
   Sleep(millis);
 }
 
+u64 NanoTime() {
+  return 0;
+}
+
 void Abort() {
   abort();
   _exit(-1);  // abort is not NORETURN on Windows.
@@ -198,16 +220,16 @@
 #endif
 
 // ------------------ sanitizer_libc.h
-void *internal_mmap(void *addr, uptr length, int prot, int flags,
-                    int fd, u64 offset) {
+uptr internal_mmap(void *addr, uptr length, int prot, int flags,
+                   int fd, u64 offset) {
   UNIMPLEMENTED();
 }
 
-int internal_munmap(void *addr, uptr length) {
+uptr internal_munmap(void *addr, uptr length) {
   UNIMPLEMENTED();
 }
 
-int internal_close(fd_t fd) {
+uptr internal_close(fd_t fd) {
   UNIMPLEMENTED();
 }
 
@@ -215,15 +237,15 @@
   return _isatty(fd);
 }
 
-fd_t internal_open(const char *filename, int flags) {
+uptr internal_open(const char *filename, int flags) {
   UNIMPLEMENTED();
 }
 
-fd_t internal_open(const char *filename, int flags, u32 mode) {
+uptr internal_open(const char *filename, int flags, u32 mode) {
   UNIMPLEMENTED();
 }
 
-fd_t OpenFile(const char *filename, bool write) {
+uptr OpenFile(const char *filename, bool write) {
   UNIMPLEMENTED();
 }
 
@@ -243,15 +265,15 @@
   return ret;
 }
 
-int internal_stat(const char *path, void *buf) {
+uptr internal_stat(const char *path, void *buf) {
   UNIMPLEMENTED();
 }
 
-int internal_lstat(const char *path, void *buf) {
+uptr internal_lstat(const char *path, void *buf) {
   UNIMPLEMENTED();
 }
 
-int internal_fstat(fd_t fd, void *buf) {
+uptr internal_fstat(fd_t fd, void *buf) {
   UNIMPLEMENTED();
 }
 
@@ -259,7 +281,7 @@
   UNIMPLEMENTED();
 }
 
-int internal_dup2(int oldfd, int newfd) {
+uptr internal_dup2(int oldfd, int newfd) {
   UNIMPLEMENTED();
 }
 
@@ -267,7 +289,7 @@
   UNIMPLEMENTED();
 }
 
-int internal_sched_yield() {
+uptr internal_sched_yield() {
   Sleep(0);
   return 0;
 }
@@ -327,6 +349,50 @@
 void InitTlsSize() {
 }
 
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+                          uptr *tls_addr, uptr *tls_size) {
+#ifdef SANITIZER_GO
+  *stk_addr = 0;
+  *stk_size = 0;
+  *tls_addr = 0;
+  *tls_size = 0;
+#else
+  uptr stack_top, stack_bottom;
+  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
+  *stk_addr = stack_bottom;
+  *stk_size = stack_top - stack_bottom;
+  *tls_addr = 0;
+  *tls_size = 0;
+#endif
+}
+
+void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+                   uptr stack_top, uptr stack_bottom, bool fast) {
+  (void)fast;
+  (void)stack_top;
+  (void)stack_bottom;
+  stack->max_size = max_s;
+  void *tmp[kStackTraceMax];
+
+  // FIXME: CaptureStackBackTrace might be too slow for us.
+  // FIXME: Compare with StackWalk64.
+  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
+  uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
+  uptr offset = 0;
+  // Skip the RTL frames by searching for the PC in the stacktrace.
+  // FIXME: this doesn't work well for the malloc/free stacks yet.
+  for (uptr i = 0; i < cs_ret; i++) {
+    if (pc != (uptr)tmp[i])
+      continue;
+    offset = i;
+    break;
+  }
+
+  stack->size = cs_ret - offset;
+  for (uptr i = 0; i < stack->size; i++)
+    stack->trace[i] = (uptr)tmp[i + offset];
+}
+
 }  // namespace __sanitizer
 
 #endif  // _WIN32
diff --git a/lib/sanitizer_common/scripts/check_lint.sh b/lib/sanitizer_common/scripts/check_lint.sh
index 8596629..b24684e 100755
--- a/lib/sanitizer_common/scripts/check_lint.sh
+++ b/lib/sanitizer_common/scripts/check_lint.sh
@@ -23,28 +23,31 @@
 # TODO: remove some of these filters
 COMMON_LINT_FILTER=-build/include,-build/header_guard,-legal/copyright,-whitespace/comments,-readability/casting,\
 -build/namespaces
-ASAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-readability/check,-runtime/int
+ASAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
 ASAN_TEST_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/sizeof,-runtime/int,-runtime/printf
 ASAN_LIT_TEST_LINT_FILTER=${ASAN_TEST_LINT_FILTER},-whitespace/line_length
 TSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
 TSAN_TEST_LINT_FILTER=${TSAN_RTL_LINT_FILTER},-runtime/threadsafe_fn,-runtime/int
 TSAN_LIT_TEST_LINT_FILTER=${TSAN_TEST_LINT_FILTER},-whitespace/line_length
 MSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
+LSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
+LSAN_LIT_TEST_LINT_FILTER=${LSAN_RTL_LINT_FILTER},-whitespace/line_length
 COMMON_RTL_INC_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/sizeof,-runtime/printf
+SANITIZER_INCLUDES_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
 
 cd ${LLVM_CHECKOUT}
 
 # LLVM Instrumentation
 LLVM_INSTRUMENTATION=lib/Transforms/Instrumentation
 LLVM_LINT_FILTER=-,+whitespace
-${CPPLINT} --filter=${LLVM_LINT_FILTER} ${LLVM_INSTRUMENTATION}/*Sanitizer.cpp \
-                                        ${LLVM_INSTRUMENTATION}/BlackList.*
+${CPPLINT} --filter=${LLVM_LINT_FILTER} lib/Transforms/Instrumentation/*Sanitizer.cpp \
+                                        lib/Transforms/Utils/SpecialCaseList.cpp
 
 COMPILER_RT=projects/compiler-rt
 
 # Headers
 SANITIZER_INCLUDES=${COMPILER_RT}/include/sanitizer
-${CPPLINT} --filter=${TSAN_RTL_LINT_FILTER} ${SANITIZER_INCLUDES}/*.h
+${CPPLINT} --filter=${SANITIZER_INCLUDES_LINT_FILTER} ${SANITIZER_INCLUDES}/*.h
 
 # Sanitizer_common
 COMMON_RTL=${COMPILER_RT}/lib/sanitizer_common
@@ -59,8 +62,7 @@
 ASAN_RTL=${COMPILER_RT}/lib/asan
 ${CPPLINT} --filter=${ASAN_RTL_LINT_FILTER} ${ASAN_RTL}/*.{cc,h}
 ${CPPLINT} --filter=${ASAN_TEST_LINT_FILTER} ${ASAN_RTL}/tests/*.{cc,h}
-${CPPLINT} --filter=${ASAN_LIT_TEST_LINT_FILTER} ${ASAN_RTL}/lit_tests/*.cc \
-                                             ${ASAN_RTL}/lit_tests/*/*.cc \
+${CPPLINT} --filter=${ASAN_LIT_TEST_LINT_FILTER} ${ASAN_RTL}/lit_tests/*/*.cc \
 
 # TSan
 TSAN_RTL=${COMPILER_RT}/lib/tsan
@@ -73,6 +75,12 @@
 MSAN_RTL=${COMPILER_RT}/lib/msan
 ${CPPLINT} --filter=${MSAN_RTL_LINT_FILTER} ${MSAN_RTL}/*.{cc,h}
 
+# LSan
+LSAN_RTL=${COMPILER_RT}/lib/lsan
+${CPPLINT} --filter=${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/*.{cc,h}
+${CPPLINT} --filter=${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/tests/*.{cc,h}
+${CPPLINT} --filter=${LSAN_LIT_TEST_LINT_FILTER} ${LSAN_RTL}/lit_tests/*/*.cc
+
 set +e
 
 # Misc files
diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt
index 346e010..d7ccc78 100644
--- a/lib/sanitizer_common/tests/CMakeLists.txt
+++ b/lib/sanitizer_common/tests/CMakeLists.txt
@@ -2,17 +2,21 @@
 
 set(SANITIZER_UNITTESTS
   sanitizer_allocator_test.cc
+  sanitizer_atomic_test.cc
   sanitizer_common_test.cc
   sanitizer_flags_test.cc
+  sanitizer_ioctl_test.cc
   sanitizer_libc_test.cc
   sanitizer_linux_test.cc
   sanitizer_list_test.cc
   sanitizer_mutex_test.cc
+  sanitizer_nolibc_test.cc
   sanitizer_printf_test.cc
   sanitizer_scanf_interceptor_test.cc
   sanitizer_stackdepot_test.cc
   sanitizer_stacktrace_test.cc
   sanitizer_stoptheworld_test.cc
+  sanitizer_suppressions_test.cc
   sanitizer_test_main.cc
   sanitizer_thread_registry_test.cc
   )
@@ -85,6 +89,24 @@
                        DEPS ${SANITIZER_TEST_OBJECTS} ${SANITIZER_COMMON_LIB}
                        LINK_FLAGS ${SANITIZER_TEST_LINK_FLAGS_COMMON}
                                   -lpthread ${TARGET_FLAGS})
+
+  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND "${arch}" STREQUAL "x86_64")
+    # Test that the libc-independent part of sanitizer_common is indeed
+    # independent of libc, by linking this binary without libc (here) and
+    # executing it (unit test in sanitizer_nolibc_test.cc).
+    clang_compile(sanitizer_nolibc_test_main.${arch}.o
+                  sanitizer_nolibc_test_main.cc
+                  CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS}
+                  DEPS ${SANITIZER_RUNTIME_LIBRARIES} ${SANITIZER_TEST_HEADERS})
+    add_compiler_rt_test(SanitizerUnitTests "Sanitizer-${arch}-Test-Nolibc"
+                         OBJECTS sanitizer_nolibc_test_main.${arch}.o
+                                 -Wl,-whole-archive
+                                 libRTSanitizerCommon.test.nolibc.${arch}.a
+                                 -Wl,-no-whole-archive
+                         DEPS sanitizer_nolibc_test_main.${arch}.o
+                              RTSanitizerCommon.test.nolibc.${arch}
+                         LINK_FLAGS -nostdlib ${TARGET_FLAGS})
+  endif()
 endmacro()
 
 if(COMPILER_RT_CAN_EXECUTE_TESTS)
@@ -96,11 +118,15 @@
   else()
     if(CAN_TARGET_x86_64)
       add_sanitizer_common_lib("RTSanitizerCommon.test.x86_64"
+                               $<TARGET_OBJECTS:RTSanitizerCommon.x86_64>
+                               $<TARGET_OBJECTS:RTSanitizerCommonLibc.x86_64>)
+      add_sanitizer_common_lib("RTSanitizerCommon.test.nolibc.x86_64"
                                $<TARGET_OBJECTS:RTSanitizerCommon.x86_64>)
     endif()
     if(CAN_TARGET_i386)
       add_sanitizer_common_lib("RTSanitizerCommon.test.i386"
-                               $<TARGET_OBJECTS:RTSanitizerCommon.i386>)
+                               $<TARGET_OBJECTS:RTSanitizerCommon.i386>
+                               $<TARGET_OBJECTS:RTSanitizerCommonLibc.i386>)
     endif()
   endif()
   if(CAN_TARGET_x86_64)
diff --git a/lib/sanitizer_common/tests/lit.cfg b/lib/sanitizer_common/tests/lit.cfg
index d774753..303d56c 100644
--- a/lib/sanitizer_common/tests/lit.cfg
+++ b/lib/sanitizer_common/tests/lit.cfg
@@ -11,9 +11,8 @@
   return attr_value
 
 # Setup attributes common for all compiler-rt projects.
-llvm_src_root = get_required_attr(config, 'llvm_src_root')
-compiler_rt_lit_unit_cfg = os.path.join(llvm_src_root, "projects",
-                                        "compiler-rt", "lib",
+compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root')
+compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib",
                                         "lit.common.unit.cfg")
 lit.load_config(config, compiler_rt_lit_unit_cfg)
 
diff --git a/lib/sanitizer_common/tests/lit.site.cfg.in b/lib/sanitizer_common/tests/lit.site.cfg.in
index ad0ff3c..50485aa 100644
--- a/lib/sanitizer_common/tests/lit.site.cfg.in
+++ b/lib/sanitizer_common/tests/lit.site.cfg.in
@@ -3,6 +3,7 @@
 
 config.llvm_obj_root = "@LLVM_BINARY_DIR@"
 config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
 config.llvm_build_mode = "@LLVM_BUILD_MODE@"
 
 try:
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
index a8747a5..5574206 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
@@ -12,6 +12,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
 #include "sanitizer_common/sanitizer_common.h"
 
 #include "sanitizer_test_utils.h"
@@ -41,8 +42,16 @@
 static const u64 kAddressSpaceSize = 1ULL << 32;
 #endif
 
+static const uptr kRegionSizeLog = FIRST_32_SECOND_64(20, 24);
+static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
+
 typedef SizeClassAllocator32<
-  0, kAddressSpaceSize, 16, CompactSizeClassMap> Allocator32Compact;
+  0, kAddressSpaceSize,
+  /*kMetadataSize*/16,
+  CompactSizeClassMap,
+  kRegionSizeLog,
+  FlatByteMap<kFlatByteMapSize> >
+  Allocator32Compact;
 
 template <class SizeClassMap>
 void TestSizeClassMap() {
@@ -59,6 +68,10 @@
   TestSizeClassMap<CompactSizeClassMap>();
 }
 
+TEST(SanitizerCommon, InternalSizeClassMap) {
+  TestSizeClassMap<InternalSizeClassMap>();
+}
+
 template <class Allocator>
 void TestSizeClassAllocator() {
   Allocator *a = new Allocator;
@@ -147,24 +160,26 @@
   SizeClassAllocatorLocalCache<Allocator> cache;
   memset(&cache, 0, sizeof(cache));
   cache.Init(0);
-  static volatile void *sink;
 
-  const uptr kNumAllocs = 10000;
+  const uptr kNumAllocs = 1 << 13;
   void *allocated[kNumAllocs];
+  void *meta[kNumAllocs];
   for (uptr i = 0; i < kNumAllocs; i++) {
     void *x = cache.Allocate(a, 1 + i % 50);
     allocated[i] = x;
+    meta[i] = a->GetMetaData(x);
   }
   // Get Metadata kNumAllocs^2 times.
   for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
-    sink = a->GetMetaData(allocated[i % kNumAllocs]);
+    uptr idx = i % kNumAllocs;
+    void *m = a->GetMetaData(allocated[idx]);
+    EXPECT_EQ(m, meta[idx]);
   }
   for (uptr i = 0; i < kNumAllocs; i++) {
     cache.Deallocate(a, 1 + i % 50, allocated[i]);
   }
 
   a->TestOnlyUnmap();
-  (void)sink;
   delete a;
 }
 
@@ -176,11 +191,47 @@
 TEST(SanitizerCommon, SizeClassAllocator64CompactMetadataStress) {
   SizeClassAllocatorMetadataStress<Allocator64Compact>();
 }
-#endif
+#endif  // SANITIZER_WORDSIZE == 64
 TEST(SanitizerCommon, SizeClassAllocator32CompactMetadataStress) {
   SizeClassAllocatorMetadataStress<Allocator32Compact>();
 }
 
+template <class Allocator>
+void SizeClassAllocatorGetBlockBeginStress() {
+  Allocator *a = new Allocator;
+  a->Init();
+  SizeClassAllocatorLocalCache<Allocator> cache;
+  memset(&cache, 0, sizeof(cache));
+  cache.Init(0);
+
+  uptr max_size_class = Allocator::kNumClasses - 1;
+  uptr size = Allocator::SizeClassMapT::Size(max_size_class);
+  u64 G8 = 1ULL << 33;
+  // Make sure we correctly compute GetBlockBegin() w/o overflow.
+  for (size_t i = 0; i <= G8 / size; i++) {
+    void *x = cache.Allocate(a, max_size_class);
+    void *beg = a->GetBlockBegin(x);
+    // if ((i & (i - 1)) == 0)
+    //   fprintf(stderr, "[%zd] %p %p\n", i, x, beg);
+    EXPECT_EQ(x, beg);
+  }
+
+  a->TestOnlyUnmap();
+  delete a;
+}
+
+#if SANITIZER_WORDSIZE == 64
+TEST(SanitizerCommon, SizeClassAllocator64GetBlockBegin) {
+  SizeClassAllocatorGetBlockBeginStress<Allocator64>();
+}
+TEST(SanitizerCommon, SizeClassAllocator64CompactGetBlockBegin) {
+  SizeClassAllocatorGetBlockBeginStress<Allocator64Compact>();
+}
+TEST(SanitizerCommon, SizeClassAllocator32CompactGetBlockBegin) {
+  SizeClassAllocatorGetBlockBeginStress<Allocator32Compact>();
+}
+#endif  // SANITIZER_WORDSIZE == 64
+
 struct TestMapUnmapCallback {
   static int map_count, unmap_count;
   void OnMap(uptr p, uptr size) const { map_count++; }
@@ -216,20 +267,25 @@
   TestMapUnmapCallback::map_count = 0;
   TestMapUnmapCallback::unmap_count = 0;
   typedef SizeClassAllocator32<
-      0, kAddressSpaceSize, 16, CompactSizeClassMap,
-      TestMapUnmapCallback> Allocator32WithCallBack;
+      0, kAddressSpaceSize,
+      /*kMetadataSize*/16,
+      CompactSizeClassMap,
+      kRegionSizeLog,
+      FlatByteMap<kFlatByteMapSize>,
+      TestMapUnmapCallback>
+    Allocator32WithCallBack;
   Allocator32WithCallBack *a = new Allocator32WithCallBack;
   a->Init();
-  EXPECT_EQ(TestMapUnmapCallback::map_count, 1);  // Allocator state.
+  EXPECT_EQ(TestMapUnmapCallback::map_count, 0);
   SizeClassAllocatorLocalCache<Allocator32WithCallBack>  cache;
   memset(&cache, 0, sizeof(cache));
   cache.Init(0);
   AllocatorStats stats;
   stats.Init();
   a->AllocateBatch(&stats, &cache, 32);
-  EXPECT_EQ(TestMapUnmapCallback::map_count, 2);  // alloc.
+  EXPECT_EQ(TestMapUnmapCallback::map_count, 1);
   a->TestOnlyUnmap();
-  EXPECT_EQ(TestMapUnmapCallback::unmap_count, 2);  // The whole thing + alloc.
+  EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1);
   delete a;
   // fprintf(stderr, "Map: %d Unmap: %d\n",
   //         TestMapUnmapCallback::map_count,
@@ -337,6 +393,14 @@
       a.Deallocate(&stats, allocated[i]);
     }
   }
+
+  // Regression test for boundary condition in GetBlockBegin().
+  uptr page_size = GetPageSizeCached();
+  char *p = (char *)a.Allocate(&stats, page_size, 1);
+  CHECK_EQ(p, a.GetBlockBegin(p));
+  CHECK_EQ(p, (char *)a.GetBlockBegin(p + page_size - 1));
+  CHECK_NE(p, (char *)a.GetBlockBegin(p + page_size));
+  a.Deallocate(&stats, p);
 }
 
 template
@@ -552,6 +616,11 @@
   }
 }
 
+TEST(Allocator, InternalAllocFailure) {
+  EXPECT_DEATH(Ident(InternalAlloc(10 << 20)),
+               "Unexpected mmap in InternalAllocator!");
+}
+
 TEST(Allocator, ScopedBuffer) {
   const int kSize = 512;
   {
@@ -566,16 +635,9 @@
   }
 }
 
-class IterationTestCallback {
- public:
-  explicit IterationTestCallback(std::set<void *> *chunks)
-    : chunks_(chunks) {}
-  void operator()(void *chunk) const {
-    chunks_->insert(chunk);
-  }
- private:
-  std::set<void *> *chunks_;
-};
+void IterationTestCallback(uptr chunk, void *arg) {
+  reinterpret_cast<std::set<uptr> *>(arg)->insert(chunk);
+}
 
 template <class Allocator>
 void TestSizeClassAllocatorIteration() {
@@ -604,15 +666,15 @@
     }
   }
 
-  std::set<void *> reported_chunks;
-  IterationTestCallback callback(&reported_chunks);
+  std::set<uptr> reported_chunks;
   a->ForceLock();
-  a->ForEachChunk(callback);
+  a->ForEachChunk(IterationTestCallback, &reported_chunks);
   a->ForceUnlock();
 
   for (uptr i = 0; i < allocated.size(); i++) {
     // Don't use EXPECT_NE. Reporting the first mismatch is enough.
-    ASSERT_NE(reported_chunks.find(allocated[i]), reported_chunks.end());
+    ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])),
+              reported_chunks.end());
   }
 
   a->TestOnlyUnmap();
@@ -629,7 +691,6 @@
   TestSizeClassAllocatorIteration<Allocator32Compact>();
 }
 
-
 TEST(SanitizerCommon, LargeMmapAllocatorIteration) {
   LargeMmapAllocator<> a;
   a.Init();
@@ -640,20 +701,86 @@
   char *allocated[kNumAllocs];
   static const uptr size = 40;
   // Allocate some.
-  for (uptr i = 0; i < kNumAllocs; i++) {
+  for (uptr i = 0; i < kNumAllocs; i++)
     allocated[i] = (char *)a.Allocate(&stats, size, 1);
-  }
 
-  std::set<void *> reported_chunks;
-  IterationTestCallback callback(&reported_chunks);
+  std::set<uptr> reported_chunks;
   a.ForceLock();
-  a.ForEachChunk(callback);
+  a.ForEachChunk(IterationTestCallback, &reported_chunks);
   a.ForceUnlock();
 
   for (uptr i = 0; i < kNumAllocs; i++) {
     // Don't use EXPECT_NE. Reporting the first mismatch is enough.
-    ASSERT_NE(reported_chunks.find(allocated[i]), reported_chunks.end());
+    ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])),
+              reported_chunks.end());
   }
+  for (uptr i = 0; i < kNumAllocs; i++)
+    a.Deallocate(&stats, allocated[i]);
 }
 
+TEST(SanitizerCommon, LargeMmapAllocatorBlockBegin) {
+  LargeMmapAllocator<> a;
+  a.Init();
+  AllocatorStats stats;
+  stats.Init();
+
+  static const uptr kNumAllocs = 1024;
+  static const uptr kNumExpectedFalseLookups = 10000000;
+  char *allocated[kNumAllocs];
+  static const uptr size = 4096;
+  // Allocate some.
+  for (uptr i = 0; i < kNumAllocs; i++) {
+    allocated[i] = (char *)a.Allocate(&stats, size, 1);
+  }
+
+  for (uptr i = 0; i < kNumAllocs  * kNumAllocs; i++) {
+    // if ((i & (i - 1)) == 0) fprintf(stderr, "[%zd]\n", i);
+    char *p1 = allocated[i % kNumAllocs];
+    EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1));
+    EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size / 2));
+    EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size - 1));
+    EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 - 100));
+  }
+
+  for (uptr i = 0; i < kNumExpectedFalseLookups; i++) {
+    void *p = reinterpret_cast<void *>(i % 1024);
+    EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p));
+    p = reinterpret_cast<void *>(~0L - (i % 1024));
+    EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p));
+  }
+
+  for (uptr i = 0; i < kNumAllocs; i++)
+    a.Deallocate(&stats, allocated[i]);
+}
+
+
+#if SANITIZER_WORDSIZE == 64
+// Regression test for out-of-memory condition in PopulateFreeList().
+TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) {
+  // In a world where regions are small and chunks are huge...
+  typedef SizeClassMap<63, 128, 16> SpecialSizeClassMap;
+  typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0,
+                               SpecialSizeClassMap> SpecialAllocator64;
+  const uptr kRegionSize =
+      kAllocatorSize / SpecialSizeClassMap::kNumClassesRounded;
+  SpecialAllocator64 *a = new SpecialAllocator64;
+  a->Init();
+  SizeClassAllocatorLocalCache<SpecialAllocator64> cache;
+  memset(&cache, 0, sizeof(cache));
+  cache.Init(0);
+
+  // ...one man is on a mission to overflow a region with a series of
+  // successive allocations.
+  const uptr kClassID = 107;
+  const uptr kAllocationSize = DefaultSizeClassMap::Size(kClassID);
+  ASSERT_LT(2 * kAllocationSize, kRegionSize);
+  ASSERT_GT(3 * kAllocationSize, kRegionSize);
+  cache.Allocate(a, kClassID);
+  EXPECT_DEATH(cache.Allocate(a, kClassID) && cache.Allocate(a, kClassID),
+               "The process has exhausted");
+  a->TestOnlyUnmap();
+  delete a;
+}
+#endif
+
 #endif  // #if TSAN_DEBUG==0
diff --git a/lib/sanitizer_common/tests/sanitizer_atomic_test.cc b/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
new file mode 100644
index 0000000..a4a97c4
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
@@ -0,0 +1,55 @@
+//===-- sanitizer_atomic_test.cc ------------------------------------------===//
+//
+//                     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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+// Clang crashes while compiling this test for Android:
+// http://llvm.org/bugs/show_bug.cgi?id=15587
+#if !SANITIZER_ANDROID
+template<typename T>
+void CheckAtomicCompareExchange() {
+  typedef typename T::Type Type;
+  {
+    Type old_val = 42;
+    Type new_val = 24;
+    Type var = old_val;
+    EXPECT_TRUE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
+                                               memory_order_relaxed));
+    EXPECT_FALSE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
+                                                memory_order_relaxed));
+    EXPECT_EQ(new_val, old_val);
+  }
+  {
+    Type old_val = 42;
+    Type new_val = 24;
+    Type var = old_val;
+    EXPECT_TRUE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
+                                             memory_order_relaxed));
+    EXPECT_FALSE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
+                                              memory_order_relaxed));
+    EXPECT_EQ(new_val, old_val);
+  }
+}
+
+TEST(SanitizerCommon, AtomicCompareExchangeTest) {
+  CheckAtomicCompareExchange<atomic_uint8_t>();
+  CheckAtomicCompareExchange<atomic_uint16_t>();
+  CheckAtomicCompareExchange<atomic_uint32_t>();
+  CheckAtomicCompareExchange<atomic_uint64_t>();
+  CheckAtomicCompareExchange<atomic_uintptr_t>();
+}
+#endif  //!SANITIZER_ANDROID
+
+}  // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc
index 0a777bd..ee913dc 100644
--- a/lib/sanitizer_common/tests/sanitizer_common_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_platform.h"
 #include "gtest/gtest.h"
 
 namespace __sanitizer {
@@ -79,7 +80,7 @@
   }
 }
 
-#ifdef __linux__
+#if SANITIZER_LINUX
 TEST(SanitizerCommon, SanitizerSetThreadName) {
   const char *names[] = {
     "0123456789012",
@@ -96,8 +97,8 @@
 }
 #endif
 
-TEST(SanitizerCommon, InternalVector) {
-  InternalVector<uptr> vector(1);
+TEST(SanitizerCommon, InternalMmapVector) {
+  InternalMmapVector<uptr> vector(1);
   for (uptr i = 0; i < 100; i++) {
     EXPECT_EQ(i, vector.size());
     vector.push_back(i);
@@ -112,4 +113,49 @@
   }
 }
 
+void TestThreadInfo(bool main) {
+  uptr stk_addr = 0;
+  uptr stk_size = 0;
+  uptr tls_addr = 0;
+  uptr tls_size = 0;
+  GetThreadStackAndTls(main, &stk_addr, &stk_size, &tls_addr, &tls_size);
+
+  int stack_var;
+  EXPECT_NE(stk_addr, (uptr)0);
+  EXPECT_NE(stk_size, (uptr)0);
+  EXPECT_GT((uptr)&stack_var, stk_addr);
+  EXPECT_LT((uptr)&stack_var, stk_addr + stk_size);
+
+#if SANITIZER_LINUX && defined(__x86_64__)
+  static __thread int thread_var;
+  EXPECT_NE(tls_addr, (uptr)0);
+  EXPECT_NE(tls_size, (uptr)0);
+  EXPECT_GT((uptr)&thread_var, tls_addr);
+  EXPECT_LT((uptr)&thread_var, tls_addr + tls_size);
+
+  // Ensure that tls and stack do not intersect.
+  uptr tls_end = tls_addr + tls_size;
+  EXPECT_TRUE(tls_addr < stk_addr || tls_addr >= stk_addr + stk_size);
+  EXPECT_TRUE(tls_end  < stk_addr || tls_end  >=  stk_addr + stk_size);
+  EXPECT_TRUE((tls_addr < stk_addr) == (tls_end  < stk_addr));
+#endif
+}
+
+static void *WorkerThread(void *arg) {
+  TestThreadInfo(false);
+  return 0;
+}
+
+TEST(SanitizerCommon, ThreadStackTlsMain) {
+  InitTlsSize();
+  TestThreadInfo(true);
+}
+
+TEST(SanitizerCommon, ThreadStackTlsWorker) {
+  InitTlsSize();
+  pthread_t t;
+  pthread_create(&t, 0, WorkerThread, 0);
+  pthread_join(t, 0);
+}
+
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
index 8c456c6..cd3cac1 100644
--- a/lib/sanitizer_common/tests/sanitizer_flags_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
@@ -63,6 +63,7 @@
   TestStrFlag("", "--flag_name='abc zxc'", "abc zxc");
   TestStrFlag("", "--flag_name='abc zxcc'", "abc zxcc");
   TestStrFlag("", "--flag_name=\"abc qwe\" asd", "abc qwe");
+  TestStrFlag("", "other_flag_name=zzz", "");
 }
 
 static void TestTwoFlags(const char *env, bool expected_flag1,
diff --git a/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc b/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
new file mode 100644
index 0000000..154d986
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
@@ -0,0 +1,77 @@
+//===-- sanitizer_ioctl_test.cc -------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for ioctl interceptor implementation in sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include <linux/input.h>
+#include <vector>
+
+#include "interception/interception.h"
+#include "sanitizer_test_utils.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+
+
+using namespace __sanitizer;
+
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, sz) \
+  do {                                              \
+    (void) ctx;                                     \
+    (void) ptr;                                     \
+    (void) sz;                                      \
+  } while (0)
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sz) \
+  do {                                               \
+    (void) ctx;                                      \
+    (void) ptr;                                      \
+    (void) sz;                                       \
+  } while (0)
+
+#include "sanitizer_common/sanitizer_common_interceptors_ioctl.inc"
+
+static struct IoctlInit {
+  IoctlInit() {
+    ioctl_init();
+    // Avoid unused function warnings.
+    (void)&ioctl_common_pre;
+    (void)&ioctl_common_post;
+  }
+} ioctl_static_initializer;
+
+TEST(SanitizerIoctl, Fixup) {
+  EXPECT_EQ((unsigned)FIONBIO, ioctl_request_fixup(FIONBIO));
+
+  EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(0, 16)));
+  EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 16)));
+  EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 17)));
+  EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(31, 16)));
+  EXPECT_NE(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(32, 16)));
+
+  EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(0)));
+  EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(5)));
+  EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(63)));
+  EXPECT_NE(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(64)));
+
+  EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(0)));
+  EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(5)));
+  EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(63)));
+  EXPECT_NE(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(64)));
+
+  const ioctl_desc *desc = ioctl_lookup(EVIOCGKEY(16));
+  EXPECT_NE((void *)0, desc);
+  EXPECT_EQ(EVIOCGKEY(0), desc->req);
+}
+
+#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
index b677130..39c29d3 100644
--- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
@@ -11,9 +11,10 @@
 
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_platform.h"
 #include "gtest/gtest.h"
 
-#if defined(__linux__) || defined(__APPLE__)
+#if SANITIZER_LINUX || SANITIZER_MAC
 # define SANITIZER_TEST_HAS_STAT_H 1
 # include <sys/stat.h>
 #else
@@ -49,6 +50,11 @@
   delete [] x;
 }
 
+struct stat_and_more {
+  struct stat st;
+  unsigned char z;
+};
+
 TEST(SanitizerCommon, FileOps) {
   const char *str1 = "qwerty";
   uptr len1 = internal_strlen(str1);
@@ -57,7 +63,7 @@
 
   u32 uid = GetUid();
   char temp_filename[128];
-#ifdef __ANDROID__
+#if SANITIZER_ANDROID
   // I don't know a way to query temp directory location on Android without
   // going through Java interfaces. The code below is not ideal, but should
   // work. May require "adb root", but it is needed for almost any use of ASan
@@ -69,23 +75,34 @@
   internal_snprintf(temp_filename, sizeof(temp_filename),
                     "/tmp/sanitizer_common.tmp.%d", uid);
 #endif
-  fd_t fd = OpenFile(temp_filename, true);
-  EXPECT_NE(fd, kInvalidFd);
+  uptr openrv = OpenFile(temp_filename, true);
+  EXPECT_FALSE(internal_iserror(openrv));
+  fd_t fd = openrv;
   EXPECT_EQ(len1, internal_write(fd, str1, len1));
   EXPECT_EQ(len2, internal_write(fd, str2, len2));
   internal_close(fd);
 
-  fd = OpenFile(temp_filename, false);
-  EXPECT_NE(fd, kInvalidFd);
+  openrv = OpenFile(temp_filename, false);
+  EXPECT_FALSE(internal_iserror(openrv));
+  fd = openrv;
   uptr fsize = internal_filesize(fd);
   EXPECT_EQ(len1 + len2, fsize);
 
 #if SANITIZER_TEST_HAS_STAT_H
   struct stat st1, st2, st3;
-  EXPECT_EQ(0, internal_stat(temp_filename, &st1));
-  EXPECT_EQ(0, internal_lstat(temp_filename, &st2));
-  EXPECT_EQ(0, internal_fstat(fd, &st3));
+  EXPECT_EQ(0u, internal_stat(temp_filename, &st1));
+  EXPECT_EQ(0u, internal_lstat(temp_filename, &st2));
+  EXPECT_EQ(0u, internal_fstat(fd, &st3));
   EXPECT_EQ(fsize, (uptr)st3.st_size);
+
+  // Verify that internal_fstat does not write beyond the end of the supplied
+  // buffer.
+  struct stat_and_more sam;
+  memset(&sam, 0xAB, sizeof(sam));
+  EXPECT_EQ(0u, internal_fstat(fd, &sam.st));
+  EXPECT_EQ(0xAB, sam.z);
+  EXPECT_NE(0xAB, sam.st.st_size);
+  EXPECT_NE(0, sam.st.st_size);
 #endif
 
   char buf[64] = {};
@@ -97,3 +114,4 @@
   EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
   internal_close(fd);
 }
+
diff --git a/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/lib/sanitizer_common/tests/sanitizer_linux_test.cc
index 035c11f..592d9c3 100644
--- a/lib/sanitizer_common/tests/sanitizer_linux_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_linux_test.cc
@@ -11,15 +11,17 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifdef __linux__
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "sanitizer_common/sanitizer_linux.h"
-#include "gtest/gtest.h"
 
 #include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
 
 #include <pthread.h>
 #include <sched.h>
+#include <stdlib.h>
 
 #include <algorithm>
 #include <vector>
@@ -185,6 +187,74 @@
   ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));
 }
 
+TEST(SanitizerCommon, SetEnvTest) {
+  const char kEnvName[] = "ENV_FOO";
+  SetEnv(kEnvName, "value");
+  EXPECT_STREQ("value", getenv(kEnvName));
+  unsetenv(kEnvName);
+  EXPECT_EQ(0, getenv(kEnvName));
+}
+
+#if defined(__x86_64__) || defined(__i386__)
+void *thread_self_offset_test_func(void *arg) {
+  bool result =
+      *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
+  return (void *)result;
+}
+
+TEST(SanitizerLinux, ThreadSelfOffset) {
+  EXPECT_TRUE((bool)thread_self_offset_test_func(0));
+  pthread_t tid;
+  void *result;
+  ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0));
+  ASSERT_EQ(0, pthread_join(tid, &result));
+  EXPECT_TRUE((bool)result);
+}
+
+// libpthread puts the thread descriptor at the end of stack space.
+void *thread_descriptor_size_test_func(void *arg) {
+  uptr descr_addr = ThreadSelf();
+  pthread_attr_t attr;
+  pthread_getattr_np(pthread_self(), &attr);
+  void *stackaddr;
+  size_t stacksize;
+  pthread_attr_getstack(&attr, &stackaddr, &stacksize);
+  return (void *)((uptr)stackaddr + stacksize - descr_addr);
+}
+
+TEST(SanitizerLinux, ThreadDescriptorSize) {
+  pthread_t tid;
+  void *result;
+  ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
+  ASSERT_EQ(0, pthread_join(tid, &result));
+  EXPECT_EQ((uptr)result, ThreadDescriptorSize());
+}
+#endif
+
+TEST(SanitizerCommon, LibraryNameIs) {
+  EXPECT_FALSE(LibraryNameIs("", ""));
+
+  char full_name[256];
+  const char *paths[] = { "", "/", "/path/to/" };
+  const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" };
+  const char *base_names[] = { "lib", "lib.0", "lib-i386" };
+  const char *wrong_names[] = { "", "lib.9", "lib-x86_64" };
+  for (uptr i = 0; i < ARRAY_SIZE(paths); i++)
+    for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) {
+      for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) {
+        internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so",
+                          paths[i], base_names[k], suffixes[j]);
+        EXPECT_TRUE(LibraryNameIs(full_name, base_names[k]))
+            << "Full name " << full_name
+            << " doesn't match base name " << base_names[k];
+        for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++)
+          EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m]))
+            << "Full name " << full_name
+            << " matches base name " << wrong_names[m];
+      }
+    }
+}
+
 }  // namespace __sanitizer
 
-#endif  // __linux__
+#endif  // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc b/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc
new file mode 100644
index 0000000..d0d5a5e
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_nolibc_test.cc
@@ -0,0 +1,31 @@
+//===-- sanitizer_nolibc_test.cc ------------------------------------------===//
+//
+//                     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 ThreadSanitizer/AddressSanitizer runtime.
+// Tests for libc independence of sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+#include "gtest/gtest.h"
+
+#include <stdlib.h>
+
+extern const char *argv0;
+
+#if SANITIZER_LINUX && defined(__x86_64__)
+TEST(SanitizerCommon, NolibcMain) {
+  std::string NolibcTestPath = argv0;
+  NolibcTestPath += "-Nolibc";
+  int status = system(NolibcTestPath.c_str());
+  EXPECT_EQ(true, WIFEXITED(status));
+  EXPECT_EQ(0, WEXITSTATUS(status));
+}
+#endif
diff --git a/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc b/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc
new file mode 100644
index 0000000..72df621
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_nolibc_test_main.cc
@@ -0,0 +1,19 @@
+//===-- sanitizer_nolibc_test_main.cc -------------------------------------===//
+//
+//                     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 ThreadSanitizer/AddressSanitizer runtime.
+// Tests for libc independence of sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_libc.h"
+
+extern "C" void _start() {
+  internal__exit(0);
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_printf_test.cc b/lib/sanitizer_common/tests/sanitizer_printf_test.cc
index b1889cd..2c478cc 100644
--- a/lib/sanitizer_common/tests/sanitizer_printf_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_printf_test.cc
@@ -104,22 +104,36 @@
 }
 
 template<typename T>
-static void TestMinMax(const char *fmt, T min, T max) {
+static void TestAgainstLibc(const char *fmt, T arg1, T arg2) {
   char buf[1024];
-  uptr len = internal_snprintf(buf, sizeof(buf), fmt, min, max);
+  uptr len = internal_snprintf(buf, sizeof(buf), fmt, arg1, arg2);
   char buf2[1024];
-  snprintf(buf2, sizeof(buf2), fmt, min, max);
+  snprintf(buf2, sizeof(buf2), fmt, arg1, arg2);
   EXPECT_EQ(len, strlen(buf));
   EXPECT_STREQ(buf2, buf);
 }
 
 TEST(Printf, MinMax) {
-  TestMinMax<int>("%d-%d", INT_MIN, INT_MAX);  // NOLINT
-  TestMinMax<long>("%zd-%zd", LONG_MIN, LONG_MAX);  // NOLINT
-  TestMinMax<unsigned>("%u-%u", 0, UINT_MAX);  // NOLINT
-  TestMinMax<unsigned long>("%zu-%zu", 0, ULONG_MAX);  // NOLINT
-  TestMinMax<unsigned>("%x-%x", 0, UINT_MAX);  // NOLINT
-  TestMinMax<unsigned long>("%zx-%zx", 0, ULONG_MAX);  // NOLINT
+  TestAgainstLibc<int>("%d-%d", INT_MIN, INT_MAX);  // NOLINT
+  TestAgainstLibc<long>("%zd-%zd", LONG_MIN, LONG_MAX);  // NOLINT
+  TestAgainstLibc<unsigned>("%u-%u", 0, UINT_MAX);  // NOLINT
+  TestAgainstLibc<unsigned long>("%zu-%zu", 0, ULONG_MAX);  // NOLINT
+  TestAgainstLibc<unsigned>("%x-%x", 0, UINT_MAX);  // NOLINT
+  TestAgainstLibc<unsigned long>("%zx-%zx", 0, ULONG_MAX);  // NOLINT
+  Report("%zd\n", LONG_MIN);
+}
+
+TEST(Printf, Padding) {
+  TestAgainstLibc<int>("%3d - %3d", 1, 0);
+  TestAgainstLibc<int>("%3d - %3d", -1, 123);
+  TestAgainstLibc<int>("%3d - %3d", -1, -123);
+  TestAgainstLibc<int>("%3d - %3d", 12, 1234);
+  TestAgainstLibc<int>("%3d - %3d", -12, -1234);
+  TestAgainstLibc<int>("%03d - %03d", 1, 0);
+  TestAgainstLibc<int>("%03d - %03d", -1, 123);
+  TestAgainstLibc<int>("%03d - %03d", -1, -123);
+  TestAgainstLibc<int>("%03d - %03d", 12, 1234);
+  TestAgainstLibc<int>("%03d - %03d", -12, -1234);
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
index 2025255..3d352cb 100644
--- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
@@ -28,12 +28,16 @@
   StackTrace trace;
 };
 
+static uptr PC(uptr idx) {
+  return (1<<20) + idx;
+}
+
 void FastUnwindTest::SetUp() {
   // Fill an array of pointers with fake fp+retaddr pairs.  Frame pointers have
   // even indices.
   for (uptr i = 0; i+1 < ARRAY_SIZE(fake_stack); i += 2) {
     fake_stack[i] = (uptr)&fake_stack[i+2];  // fp
-    fake_stack[i+1] = i+1; // retaddr
+    fake_stack[i+1] = PC(i + 1); // retaddr
   }
   // Mark the last fp as zero to terminate the stack trace.
   fake_stack[RoundDownTo(ARRAY_SIZE(fake_stack) - 1, 2)] = 0;
@@ -42,7 +46,7 @@
   fake_top = (uptr)&fake_stack[ARRAY_SIZE(fake_stack) + 2];
   // Bottom is one slot before the start because FastUnwindStack uses >.
   fake_bottom = (uptr)&fake_stack[-1];
-  start_pc = 0;
+  start_pc = PC(0);
 
   // This is common setup done by __asan::GetStackTrace().
   trace.size = 0;
@@ -57,7 +61,7 @@
   EXPECT_EQ(6U, trace.size);
   EXPECT_EQ(start_pc, trace.trace[0]);
   for (uptr i = 1; i <= 5; i++) {
-    EXPECT_EQ(i*2 - 1, trace.trace[i]);
+    EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
   }
 }
 
@@ -71,8 +75,22 @@
   EXPECT_EQ(4U, trace.size);
   EXPECT_EQ(start_pc, trace.trace[0]);
   for (uptr i = 1; i <= 3; i++) {
-    EXPECT_EQ(i*2 - 1, trace.trace[i]);
+    EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
   }
 }
 
+TEST_F(FastUnwindTest, MisalignedFramePointer) {
+  // Make one fp misaligned.
+  fake_stack[4] += 3;
+  trace.FastUnwindStack(start_pc, (uptr)&fake_stack[0],
+                        fake_top, fake_bottom);
+  // Should get all on-stack retaddrs up to the 4th slot and start_pc.
+  EXPECT_EQ(4U, trace.size);
+  EXPECT_EQ(start_pc, trace.trace[0]);
+  for (uptr i = 1; i < 4U; i++) {
+    EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
+  }
+}
+
+
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc b/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
index 29cbc9a..a5f8516 100644
--- a/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
@@ -11,7 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifdef __linux__
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "sanitizer_common/sanitizer_stoptheworld.h"
 #include "gtest/gtest.h"
@@ -190,4 +191,4 @@
 
 }  // namespace __sanitizer
 
-#endif  // __linux__
+#endif  // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc b/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc
index 74749d4..d8be2af 100644
--- a/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stoptheworld_testlib.cc
@@ -16,7 +16,8 @@
 LD_PRELOAD=`pwd`/teststoptheworld.so /your/app
 */
 
-#ifdef __linux__
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include <dlfcn.h>
 #include <stddef.h>
@@ -49,4 +50,4 @@
 }
 }  // namespace
 
-#endif  // __linux__
+#endif  // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
new file mode 100644
index 0000000..f44911e
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
@@ -0,0 +1,150 @@
+//===-- sanitizer_suppressions_test.cc ------------------------------------===//
+//
+//                     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 ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "gtest/gtest.h"
+
+#include <string.h>
+
+namespace __sanitizer {
+
+static bool MyMatch(const char *templ, const char *func) {
+  char tmp[1024];
+  strcpy(tmp, templ);  // NOLINT
+  return TemplateMatch(tmp, func);
+}
+
+TEST(Suppressions, Match) {
+  EXPECT_TRUE(MyMatch("foobar$", "foobar"));
+
+  EXPECT_TRUE(MyMatch("foobar", "foobar"));
+  EXPECT_TRUE(MyMatch("*foobar*", "foobar"));
+  EXPECT_TRUE(MyMatch("foobar", "prefix_foobar_postfix"));
+  EXPECT_TRUE(MyMatch("*foobar*", "prefix_foobar_postfix"));
+  EXPECT_TRUE(MyMatch("foo*bar", "foo_middle_bar"));
+  EXPECT_TRUE(MyMatch("foo*bar", "foobar"));
+  EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_bar_another_baz"));
+  EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_barbaz"));
+  EXPECT_TRUE(MyMatch("^foobar", "foobar"));
+  EXPECT_TRUE(MyMatch("^foobar", "foobar_postfix"));
+  EXPECT_TRUE(MyMatch("^*foobar", "foobar"));
+  EXPECT_TRUE(MyMatch("^*foobar", "prefix_foobar"));
+  EXPECT_TRUE(MyMatch("foobar$", "foobar"));
+  EXPECT_TRUE(MyMatch("foobar$", "prefix_foobar"));
+  EXPECT_TRUE(MyMatch("*foobar*$", "foobar"));
+  EXPECT_TRUE(MyMatch("*foobar*$", "foobar_postfix"));
+  EXPECT_TRUE(MyMatch("^foobar$", "foobar"));
+
+  EXPECT_FALSE(MyMatch("foo", "baz"));
+  EXPECT_FALSE(MyMatch("foobarbaz", "foobar"));
+  EXPECT_FALSE(MyMatch("foobarbaz", "barbaz"));
+  EXPECT_FALSE(MyMatch("foo*bar", "foobaz"));
+  EXPECT_FALSE(MyMatch("foo*bar", "foo_baz"));
+  EXPECT_FALSE(MyMatch("^foobar", "prefix_foobar"));
+  EXPECT_FALSE(MyMatch("foobar$", "foobar_postfix"));
+  EXPECT_FALSE(MyMatch("^foobar$", "prefix_foobar"));
+  EXPECT_FALSE(MyMatch("^foobar$", "foobar_postfix"));
+  EXPECT_FALSE(MyMatch("foo^bar", "foobar"));
+  EXPECT_FALSE(MyMatch("foo$bar", "foobar"));
+  EXPECT_FALSE(MyMatch("foo$^bar", "foobar"));
+}
+
+TEST(Suppressions, TypeStrings) {
+  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionNone), "none"));
+  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionRace), "race"));
+  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionMutex), "mutex"));
+  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionThread), "thread"));
+  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal"));
+  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak"));
+  // Ensure this test is up-to-date when suppression types are added.
+  CHECK_EQ(SuppressionTypeCount, 6);
+}
+
+class SuppressionContextTest : public ::testing::Test {
+ public:
+  virtual void SetUp() { ctx_ = new(placeholder_) SuppressionContext; }
+  virtual void TearDown() { ctx_->~SuppressionContext(); }
+
+ protected:
+  InternalMmapVector<Suppression> *Suppressions() {
+    return &ctx_->suppressions_;
+  }
+  SuppressionContext *ctx_;
+  ALIGNED(64) char placeholder_[sizeof(SuppressionContext)];
+};
+
+TEST_F(SuppressionContextTest, Parse) {
+  ctx_->Parse(
+    "race:foo\n"
+    " 	race:bar\n"  // NOLINT
+    "race:baz	 \n"  // NOLINT
+    "# a comment\n"
+    "race:quz\n"
+  );  // NOLINT
+  EXPECT_EQ((unsigned)4, ctx_->SuppressionCount());
+  EXPECT_EQ((*Suppressions())[3].type, SuppressionRace);
+  EXPECT_EQ(0, strcmp((*Suppressions())[3].templ, "quz"));
+  EXPECT_EQ((*Suppressions())[2].type, SuppressionRace);
+  EXPECT_EQ(0, strcmp((*Suppressions())[2].templ, "baz"));
+  EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
+  EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
+  EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
+  EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+}
+
+TEST_F(SuppressionContextTest, Parse2) {
+  ctx_->Parse(
+    "  	# first line comment\n"  // NOLINT
+    " 	race:bar 	\n"  // NOLINT
+    "race:baz* *baz\n"
+    "# a comment\n"
+    "# last line comment\n"
+  );  // NOLINT
+  EXPECT_EQ((unsigned)2, ctx_->SuppressionCount());
+  EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
+  EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "baz* *baz"));
+  EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
+  EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "bar"));
+}
+
+TEST_F(SuppressionContextTest, Parse3) {
+  ctx_->Parse(
+    "# last suppression w/o line-feed\n"
+    "race:foo\n"
+    "race:bar"
+  );  // NOLINT
+  EXPECT_EQ((unsigned)2, ctx_->SuppressionCount());
+  EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
+  EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
+  EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
+  EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+}
+
+TEST_F(SuppressionContextTest, ParseType) {
+  ctx_->Parse(
+    "race:foo\n"
+    "thread:bar\n"
+    "mutex:baz\n"
+    "signal:quz\n"
+  );  // NOLINT
+  EXPECT_EQ((unsigned)4, ctx_->SuppressionCount());
+  EXPECT_EQ((*Suppressions())[3].type, SuppressionSignal);
+  EXPECT_EQ(0, strcmp((*Suppressions())[3].templ, "quz"));
+  EXPECT_EQ((*Suppressions())[2].type, SuppressionMutex);
+  EXPECT_EQ(0, strcmp((*Suppressions())[2].templ, "baz"));
+  EXPECT_EQ((*Suppressions())[1].type, SuppressionThread);
+  EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
+  EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
+  EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+}
+
+}  // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_test_main.cc b/lib/sanitizer_common/tests/sanitizer_test_main.cc
index 12d1d15..b7fd3da 100644
--- a/lib/sanitizer_common/tests/sanitizer_test_main.cc
+++ b/lib/sanitizer_common/tests/sanitizer_test_main.cc
@@ -12,7 +12,10 @@
 //===----------------------------------------------------------------------===//
 #include "gtest/gtest.h"
 
+const char *argv0;
+
 int main(int argc, char **argv) {
+  argv0 = argv[0];
   testing::GTEST_FLAG(death_test_style) = "threadsafe";
   testing::InitGoogleTest(&argc, argv);
   return RUN_ALL_TESTS();
diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt
index ef4b610..2828895 100644
--- a/lib/tsan/CMakeLists.txt
+++ b/lib/tsan/CMakeLists.txt
@@ -2,8 +2,11 @@
 
 include_directories(..)
 
+# SANITIZER_COMMON_CFLAGS contains -fPIC, but it's performance-critical for
+# TSan runtime to be built with -fPIE to reduce the number of register spills.
 set(TSAN_CFLAGS
   ${SANITIZER_COMMON_CFLAGS}
+  -fPIE
   -fno-rtti)
 # FIXME: Add support for compile flags:
 #   -Wframe-larger-than=512,
diff --git a/lib/tsan/Makefile.old b/lib/tsan/Makefile.old
index 6329bbb..64dff83 100644
--- a/lib/tsan/Makefile.old
+++ b/lib/tsan/Makefile.old
@@ -3,6 +3,7 @@
 CXXFLAGS = -fPIE -fno-rtti -g -Wall -Werror \
 					 -DGTEST_HAS_RTTI=0 -DTSAN_DEBUG=$(DEBUG) -DSANITIZER_DEBUG=$(DEBUG)
 CLANG=clang
+FILECHECK=FileCheck
 # Silence warnings that Clang produces for gtest code.
 # Use -Wno-attributes so that gcc doesn't complain about unknown warning types.
 CXXFLAGS += -Wno-attributes
@@ -20,8 +21,11 @@
 GTEST_LIB_NAME=gtest-all.o
 GTEST_LIB=$(GTEST_BUILD_DIR)/$(GTEST_LIB_NAME)
 
-SANITIZER_COMMON_TESTS_SRC=$(wildcard ../sanitizer_common/tests/*_test.cc)
-SANITIZER_COMMON_TESTS_OBJ=$(patsubst %.cc,%.o,$(SANITIZER_COMMON_TESTS_SRC))
+SANITIZER_TESTS_PATH=../sanitizer_common/tests
+SANITIZER_COMMON_TESTS_SRC=$(wildcard $(SANITIZER_TESTS_PATH)/*_test.cc)
+SANITIZER_COMMON_EXCLUDED_TESTS=$(SANITIZER_TESTS_PATH)/sanitizer_nolibc_test.cc
+SANITIZER_COMMON_GOOD_TESTS=$(filter-out $(SANITIZER_COMMON_EXCLUDED_TESTS), $(SANITIZER_COMMON_TESTS_SRC))
+SANITIZER_COMMON_TESTS_OBJ=$(patsubst %.cc,%.o,$(SANITIZER_COMMON_GOOD_TESTS))
 RTL_TEST_SRC=$(wildcard tests/rtl/*.cc)
 RTL_TEST_OBJ=$(patsubst %.cc,%.o,$(RTL_TEST_SRC))
 UNIT_TEST_SRC=$(wildcard tests/unit/*_test.cc)
@@ -56,10 +60,12 @@
 
 run: all
 	(ulimit -s 8192; ./tsan_test)
-	CC=$(CLANG) CXX=$(CLANG)++ ./lit_tests/test_output.sh
+	CC=$(CLANG) CXX=$(CLANG)++ FILECHECK=$(FILECHECK) ./lit_tests/test_output.sh
 
 presubmit:
 	../sanitizer_common/scripts/check_lint.sh
+	#./gen_dynamic_list.sh > rtl/tsan.syms.new
+	#diff rtl/tsan.syms rtl/tsan.syms.new
 	# Debug build with clang.
 	$(MAKE) -f Makefile.old clean
 	$(MAKE) -f Makefile.old run DEBUG=1 -j 16 CC=$(CLANG) CXX=$(CLANG)++
diff --git a/lib/tsan/analyze_libtsan.sh b/lib/tsan/analyze_libtsan.sh
index e080561..705e4c5 100755
--- a/lib/tsan/analyze_libtsan.sh
+++ b/lib/tsan/analyze_libtsan.sh
@@ -4,7 +4,7 @@
 set -u
 
 get_asm() {
-  grep tsan_$1.: -A 10000 libtsan.objdump | \
+  grep __tsan_$1.: -A 10000 libtsan.objdump | \
     awk "/[^:]$/ {print;} />:/ {c++; if (c == 2) {exit}}"
 }
 
@@ -27,7 +27,7 @@
   file=asm_$f.s
   get_asm $f > $file
   tot=$(wc -l < $file)
-  size=$(grep $f$ libtsan.nm | awk --non-decimal-data '{print ("0x"$2)+0}')
+  size=$(grep __tsan_$f$ libtsan.nm | awk --non-decimal-data '{print ("0x"$2)+0}')
   rsp=$(grep '(%rsp)' $file | wc -l)
   push=$(grep 'push' $file | wc -l)
   pop=$(grep 'pop' $file | wc -l)
diff --git a/lib/tsan/check_cmake.sh b/lib/tsan/check_cmake.sh
index 2d84b76..52c97c3 100755
--- a/lib/tsan/check_cmake.sh
+++ b/lib/tsan/check_cmake.sh
@@ -7,5 +7,6 @@
 cd $ROOT/build
 CC=clang CXX=clang++ cmake -DLLVM_ENABLE_WERROR=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON $ROOT/../../../..
 make -j64
-make check-sanitizer check-tsan check-asan -j64
-
+make check-sanitizer -j64
+make check-tsan -j64
+make check-asan -j64
diff --git a/lib/tsan/gen_dynamic_list.sh b/lib/tsan/gen_dynamic_list.sh
new file mode 100755
index 0000000..4868b42
--- /dev/null
+++ b/lib/tsan/gen_dynamic_list.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+set -e
+
+# Collect interceptor names from a source file.
+function collect() {
+  while read line ; do
+    if [[ $line =~ ^(.*)((TSAN_INTERCEPT|INTERCEPT_FUNCTION)\()([a-z,A-Z,0-9,_]+)(.*)$ ]] ; then
+      results+=" ${BASH_REMATCH[4]}"
+      results+=" __interceptor_${BASH_REMATCH[4]}"
+    fi
+  done < "$1"
+}
+
+# Interface functions.
+results+=" __tsan_init"
+results+=" __tsan_read*"
+results+=" __tsan_write*"
+results+=" __tsan_vptr*"
+results+=" __tsan_func*"
+results+=" __tsan_atomic*"
+results+=" __tsan_java*"
+results+=" __tsan_unaligned*"
+results+=" __tsan_release"
+results+=" __tsan_acquire"
+results+=" __sanitizer_unaligned*"
+results+=" __sanitizer_syscall*"
+results+=" _Znwm"
+results+=" _Znam"
+results+=" _ZnwmRKSt9nothrow_t"
+results+=" _ZnamRKSt9nothrow_t"
+results+=" _ZdlPv"
+results+=" _ZdlPvRKSt9nothrow_t"
+results+=" _ZdaPv"
+results+=" _ZdaPvRKSt9nothrow_t"
+results+=" Annotate*"
+results+=" WTFAnnotate*"
+results+=" RunningOnValgrind"
+
+collect rtl/tsan_interceptors.cc
+collect ../sanitizer_common/sanitizer_common_interceptors.inc
+
+results=`for i in $results; do echo $i; done | sort -f`
+echo "# AUTO GENERATED by compiler-rt/lib/tsan/gen_dynamic_list.sh; EDITING IS FUTILE."
+echo "{"
+NM=`nm rtl/libtsan.a`
+for i in $results; do
+  # Remove symbols that are not present in the library.
+  if [[ $NM =~ " $i" ]]; then
+    echo "  $i;"
+  else if [[ $i == *"*" ]]; then
+    echo "  $i;"
+  fi
+  fi
+done
+echo "};"
+
diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh
index aba03f9..bffa276 100755
--- a/lib/tsan/go/buildgo.sh
+++ b/lib/tsan/go/buildgo.sh
@@ -20,6 +20,7 @@
 	../../sanitizer_common/sanitizer_flags.cc
 	../../sanitizer_common/sanitizer_libc.cc
 	../../sanitizer_common/sanitizer_printf.cc
+	../../sanitizer_common/sanitizer_suppressions.cc
 	../../sanitizer_common/sanitizer_thread_registry.cc
 "
 
@@ -30,7 +31,9 @@
 	SRCS+="
 		../rtl/tsan_platform_linux.cc
 		../../sanitizer_common/sanitizer_posix.cc
+		../../sanitizer_common/sanitizer_posix_libcdep.cc
 		../../sanitizer_common/sanitizer_linux.cc
+		../../sanitizer_common/sanitizer_linux_libcdep.cc
 	"
 elif [ "`uname -a | grep Darwin`" != "" ]; then
 	SUFFIX="darwin_amd64"
@@ -40,6 +43,7 @@
 		../rtl/tsan_platform_mac.cc
 		../../sanitizer_common/sanitizer_posix.cc
 		../../sanitizer_common/sanitizer_mac.cc
+		../../sanitizer_common/sanitizer_posix_libcdep.cc
 	"
 elif [ "`uname -a | grep MINGW`" != "" ]; then
 	SUFFIX="windows_amd64"
@@ -61,7 +65,7 @@
 	cat $F >> gotsan.cc
 done
 
-FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -m64 -Wall -Werror -fno-exceptions -fno-rtti -DTSAN_GO -DSANITIZER_GO -DTSAN_SHADOW_COUNT=4 $OSCFLAGS"
+FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -m64 -Wall -Werror -Wno-maybe-uninitialized -fno-exceptions -fno-rtti -DTSAN_GO -DSANITIZER_GO -DTSAN_SHADOW_COUNT=4 $OSCFLAGS"
 if [ "$DEBUG" == "" ]; then
 	FLAGS+=" -DTSAN_DEBUG=0 -O3 -fomit-frame-pointer"
 else
diff --git a/lib/tsan/go/tsan_go.cc b/lib/tsan/go/tsan_go.cc
index b2aa622..7c89402 100644
--- a/lib/tsan/go/tsan_go.cc
+++ b/lib/tsan/go/tsan_go.cc
@@ -116,12 +116,14 @@
 
 void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr step,
                        void *pc) {
-  MemoryAccessRangeStep(thr, (uptr)pc, (uptr)addr, size, step, false);
+  (void)step;
+  MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
 }
 
 void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr step,
                         void *pc) {
-  MemoryAccessRangeStep(thr, (uptr)pc, (uptr)addr, size, step, true);
+  (void)step;
+  MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
 }
 
 void __tsan_func_enter(ThreadState *thr, void *pc) {
@@ -184,7 +186,7 @@
   AcquireGlobal(thr, 0);
 }
 
-#ifdef _WIN32
+#if SANITIZER_WINDOWS
 // MinGW gcc emits calls to the function.
 void ___chkstk_ms(void) {
 // The implementation must be along the lines of:
@@ -220,3 +222,11 @@
 
 }  // extern "C"
 }  // namespace __tsan
+
+namespace __sanitizer {
+
+void SymbolizerPrepareForSandboxing() {
+  // Nothing to do here for Go.
+}
+
+}  // namespace __sanitizer
diff --git a/lib/tsan/lit_tests/CMakeLists.txt b/lib/tsan/lit_tests/CMakeLists.txt
index ff2508d..53e5015 100644
--- a/lib/tsan/lit_tests/CMakeLists.txt
+++ b/lib/tsan/lit_tests/CMakeLists.txt
@@ -11,9 +11,8 @@
 if(COMPILER_RT_CAN_EXECUTE_TESTS)
   # Run TSan output tests only if we're sure we can produce working binaries.
   set(TSAN_TEST_DEPS
-    clang clang-headers FileCheck count not llvm-symbolizer
-    ${TSAN_RUNTIME_LIBRARIES}
-    )
+    ${SANITIZER_COMMON_LIT_TEST_DEPS}
+    ${TSAN_RUNTIME_LIBRARIES})
   set(TSAN_TEST_PARAMS
     tsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
     )
diff --git a/lib/asan/lit_tests/SharedLibs/lit.local.cfg b/lib/tsan/lit_tests/SharedLibs/lit.local.cfg
similarity index 100%
copy from lib/asan/lit_tests/SharedLibs/lit.local.cfg
copy to lib/tsan/lit_tests/SharedLibs/lit.local.cfg
diff --git a/lib/tsan/lit_tests/SharedLibs/load_shared_lib-so.cc b/lib/tsan/lit_tests/SharedLibs/load_shared_lib-so.cc
new file mode 100644
index 0000000..d05aa6a
--- /dev/null
+++ b/lib/tsan/lit_tests/SharedLibs/load_shared_lib-so.cc
@@ -0,0 +1,22 @@
+//===----------- load_shared_lib-so.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 ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stddef.h>
+
+int GLOB_SHARED = 0;
+
+extern "C"
+void *write_from_so(void *unused) {
+  GLOB_SHARED++;
+  return NULL;
+}
diff --git a/lib/tsan/lit_tests/Unit/lit.cfg b/lib/tsan/lit_tests/Unit/lit.cfg
index 6688697..1b8d175 100644
--- a/lib/tsan/lit_tests/Unit/lit.cfg
+++ b/lib/tsan/lit_tests/Unit/lit.cfg
@@ -10,13 +10,6 @@
               "to lit.site.cfg " % attr_name)
   return attr_value
 
-# Setup attributes common for all compiler-rt projects.
-llvm_src_root = get_required_attr(config, 'llvm_src_root')
-compiler_rt_lit_unit_cfg = os.path.join(llvm_src_root, "projects",
-                                        "compiler-rt", "lib",
-                                        "lit.common.unit.cfg")
-lit.load_config(config, compiler_rt_lit_unit_cfg)
-
 # Setup config name.
 config.name = 'ThreadSanitizer-Unit'
 
diff --git a/lib/tsan/lit_tests/Unit/lit.site.cfg.in b/lib/tsan/lit_tests/Unit/lit.site.cfg.in
index 420cdca..964da91 100644
--- a/lib/tsan/lit_tests/Unit/lit.site.cfg.in
+++ b/lib/tsan/lit_tests/Unit/lit.site.cfg.in
@@ -1,19 +1,8 @@
 ## Autogenerated by LLVM/Clang configuration.
 # Do not edit!
 
-config.llvm_obj_root = "@LLVM_BINARY_DIR@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.llvm_build_mode = "@LLVM_BUILD_MODE@"
+# Load common config for all compiler-rt unit tests.
+lit.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
 
-# LLVM tools dir can be passed in lit parameters, so try to
-# apply substitution.
-try:
-  config.llvm_tools_dir = config.llvm_tools_dir % lit.params
-  config.llvm_build_mode = config.llvm_build_mode % lit.params
-except KeyError,e:
-  key, = e.args
-  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Let the main config do the real work.
+# Load tool-specific config that would do the real work.
 lit.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/Unit/lit.cfg")
diff --git a/lib/tsan/lit_tests/aligned_vs_unaligned_race.cc b/lib/tsan/lit_tests/aligned_vs_unaligned_race.cc
new file mode 100644
index 0000000..f4533d0
--- /dev/null
+++ b/lib/tsan/lit_tests/aligned_vs_unaligned_race.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// Race between an aligned access and an unaligned access, which
+// touches the same memory region.
+// This is a real race which is not detected by tsan.
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=17
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+
+uint64_t Global[2];
+
+void *Thread1(void *x) {
+  Global[1]++;
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  char *p1 = reinterpret_cast<char *>(&Global[0]);
+  uint64_t *p4 = reinterpret_cast<uint64_t *>(p1 + 1);
+  (*p4)++;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  printf("Pass\n");
+  // CHECK-NOT: ThreadSanitizer: data race
+  // CHECK: Pass
+  return 0;
+}
diff --git a/lib/tsan/lit_tests/atomic_free.cc b/lib/tsan/lit_tests/atomic_free.cc
index ba9bd5a..87d5593 100644
--- a/lib/tsan/lit_tests/atomic_free.cc
+++ b/lib/tsan/lit_tests/atomic_free.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <unistd.h>
 
diff --git a/lib/tsan/lit_tests/atomic_free2.cc b/lib/tsan/lit_tests/atomic_free2.cc
index 5517bf7..961ff38 100644
--- a/lib/tsan/lit_tests/atomic_free2.cc
+++ b/lib/tsan/lit_tests/atomic_free2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <unistd.h>
 
diff --git a/lib/tsan/lit_tests/atomic_race.cc b/lib/tsan/lit_tests/atomic_race.cc
index 360b812..0dfe4d9 100644
--- a/lib/tsan/lit_tests/atomic_race.cc
+++ b/lib/tsan/lit_tests/atomic_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <unistd.h>
 #include <stdio.h>
diff --git a/lib/tsan/lit_tests/atomic_stack.cc b/lib/tsan/lit_tests/atomic_stack.cc
index 50f6a8a..841f74b 100644
--- a/lib/tsan/lit_tests/atomic_stack.cc
+++ b/lib/tsan/lit_tests/atomic_stack.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <unistd.h>
 
diff --git a/lib/tsan/lit_tests/benign_race.cc b/lib/tsan/lit_tests/benign_race.cc
new file mode 100644
index 0000000..a4d4d23
--- /dev/null
+++ b/lib/tsan/lit_tests/benign_race.cc
@@ -0,0 +1,39 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+int WTFGlobal;
+
+extern "C" {
+void AnnotateBenignRaceSized(const char *f, int l,
+                             void *mem, unsigned int size, const char *desc);
+void WTFAnnotateBenignRaceSized(const char *f, int l,
+                                void *mem, unsigned int size,
+                                const char *desc);
+}
+
+
+void *Thread(void *x) {
+  Global = 42;
+  WTFGlobal = 142;
+  return 0;
+}
+
+int main() {
+  AnnotateBenignRaceSized(__FILE__, __LINE__,
+                          &Global, sizeof(Global), "Race on Global");
+  WTFAnnotateBenignRaceSized(__FILE__, __LINE__,
+                             &WTFGlobal, sizeof(WTFGlobal),
+                             "Race on WTFGlobal");
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  sleep(1);
+  Global = 43;
+  WTFGlobal = 143;
+  pthread_join(t, 0);
+  printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/fd_close_norace2.cc b/lib/tsan/lit_tests/fd_close_norace2.cc
new file mode 100644
index 0000000..b42b334
--- /dev/null
+++ b/lib/tsan/lit_tests/fd_close_norace2.cc
@@ -0,0 +1,30 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int pipes[2];
+
+void *Thread(void *x) {
+  // wait for shutown signal
+  while (read(pipes[0], &x, 1) != 1) {
+  }
+  close(pipes[0]);
+  close(pipes[1]);
+  return 0;
+}
+
+int main() {
+  if (pipe(pipes))
+    return 1;
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  // send shutdown signal
+  while (write(pipes[1], &t, 1) != 1) {
+  }
+  pthread_join(t, 0);
+  printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: OK
diff --git a/lib/tsan/lit_tests/fd_location.cc b/lib/tsan/lit_tests/fd_location.cc
index 35f9aab..2b1e9c5 100644
--- a/lib/tsan/lit_tests/fd_location.cc
+++ b/lib/tsan/lit_tests/fd_location.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/fd_pipe_race.cc b/lib/tsan/lit_tests/fd_pipe_race.cc
index dfdb779..4dd2b77 100644
--- a/lib/tsan/lit_tests/fd_pipe_race.cc
+++ b/lib/tsan/lit_tests/fd_pipe_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/fd_stdout_race.cc b/lib/tsan/lit_tests/fd_stdout_race.cc
index 6581fc5..4b512bb 100644
--- a/lib/tsan/lit_tests/fd_stdout_race.cc
+++ b/lib/tsan/lit_tests/fd_stdout_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/free_race.c b/lib/tsan/lit_tests/free_race.c
index ff71a4d..cca38ad 100644
--- a/lib/tsan/lit_tests/free_race.c
+++ b/lib/tsan/lit_tests/free_race.c
@@ -1,4 +1,7 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s --check-prefix=NOZUPP
+// RUN: TSAN_OPTIONS="suppressions=%s.supp print_suppressions=1" %t 2>&1 | FileCheck %s --check-prefix=SUPP
+
 #include <pthread.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -34,11 +37,13 @@
   return 0;
 }
 
-// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
-// CHECK:   Write of size 4 at {{.*}} by main thread{{.*}}:
-// CHECK:     #0 Thread2
-// CHECK:     #1 main
-// CHECK:   Previous write of size 8 at {{.*}} by thread T1{{.*}}:
-// CHECK:     #0 free
-// CHECK:     #{{(1|2)}} Thread1
-// CHECK: SUMMARY: ThreadSanitizer: heap-use-after-free{{.*}}Thread2
+// CHECK-NOZUPP: WARNING: ThreadSanitizer: heap-use-after-free
+// CHECK-NOZUPP:   Write of size 4 at {{.*}} by main thread{{.*}}:
+// CHECK-NOZUPP:     #0 Thread2
+// CHECK-NOZUPP:     #1 main
+// CHECK-NOZUPP:   Previous write of size 8 at {{.*}} by thread T1{{.*}}:
+// CHECK-NOZUPP:     #0 free
+// CHECK-NOZUPP:     #{{(1|2)}} Thread1
+// CHECK-NOZUPP: SUMMARY: ThreadSanitizer: heap-use-after-free{{.*}}Thread2
+// CHECK-SUPP:   ThreadSanitizer: Matched 1 suppressions
+// CHECK-SUPP:    1 race:^Thread2$
diff --git a/lib/tsan/lit_tests/free_race.c.supp b/lib/tsan/lit_tests/free_race.c.supp
new file mode 100644
index 0000000..f5d6a49
--- /dev/null
+++ b/lib/tsan/lit_tests/free_race.c.supp
@@ -0,0 +1,2 @@
+# Suppression for a use-after-free in free_race.c
+race:^Thread2$
diff --git a/lib/tsan/lit_tests/free_race2.c b/lib/tsan/lit_tests/free_race2.c
index f20774b..2b9a419 100644
--- a/lib/tsan/lit_tests/free_race2.c
+++ b/lib/tsan/lit_tests/free_race2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <stdlib.h>
 
 void __attribute__((noinline)) foo(int *mem) {
diff --git a/lib/tsan/lit_tests/global_race.cc b/lib/tsan/lit_tests/global_race.cc
index 0892d07..997f050 100644
--- a/lib/tsan/lit_tests/global_race.cc
+++ b/lib/tsan/lit_tests/global_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <stddef.h>
diff --git a/lib/tsan/lit_tests/heap_race.cc b/lib/tsan/lit_tests/heap_race.cc
index 297f8db..cc2c1fe 100644
--- a/lib/tsan/lit_tests/heap_race.cc
+++ b/lib/tsan/lit_tests/heap_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <stddef.h>
diff --git a/lib/tsan/lit_tests/inlined_memcpy_race.cc b/lib/tsan/lit_tests/inlined_memcpy_race.cc
new file mode 100644
index 0000000..5dda36e
--- /dev/null
+++ b/lib/tsan/lit_tests/inlined_memcpy_race.cc
@@ -0,0 +1,55 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int x[4], y[4], z[4];
+
+void *MemCpyThread(void *a) {
+  memcpy((int*)a, z, 16);
+  return NULL;
+}
+
+void *MemMoveThread(void *a) {
+  memmove((int*)a, z, 16);
+  return NULL;
+}
+
+void *MemSetThread(void *a) {
+  sleep(1);
+  memset((int*)a, 0, 16);
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  // Race on x between memcpy and memset
+  pthread_create(&t[0], NULL, MemCpyThread, x);
+  pthread_create(&t[1], NULL, MemSetThread, x);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  // Race on y between memmove and memset
+  pthread_create(&t[0], NULL, MemMoveThread, y);
+  pthread_create(&t[1], NULL, MemSetThread, y);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+
+  printf("PASS\n");
+  return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK:   #0 memset
+// CHECK:   #1 MemSetThread
+// CHECK:  Previous write
+// CHECK:   #0 memcpy
+// CHECK:   #1 MemCpyThread
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK:   #0 memset
+// CHECK:   #1 MemSetThread
+// CHECK:  Previous write
+// CHECK:   #0 memmove
+// CHECK:   #1 MemMoveThread
diff --git a/lib/tsan/lit_tests/java.h b/lib/tsan/lit_tests/java.h
index 7d61f58..0409419 100644
--- a/lib/tsan/lit_tests/java.h
+++ b/lib/tsan/lit_tests/java.h
@@ -14,4 +14,6 @@
 void __tsan_java_mutex_unlock(jptr addr);
 void __tsan_java_mutex_read_lock(jptr addr);
 void __tsan_java_mutex_read_unlock(jptr addr);
+void __tsan_java_mutex_lock_rec(jptr addr, int rec);
+int  __tsan_java_mutex_unlock_rec(jptr addr);
 }
diff --git a/lib/tsan/lit_tests/java_lock.cc b/lib/tsan/lit_tests/java_lock.cc
index f66f1e7..d9db103 100644
--- a/lib/tsan/lit_tests/java_lock.cc
+++ b/lib/tsan/lit_tests/java_lock.cc
@@ -1,10 +1,12 @@
 // RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
 #include "java.h"
+#include <unistd.h>
 
 jptr varaddr;
 jptr lockaddr;
 
 void *Thread(void *p) {
+  sleep(1);
   __tsan_java_mutex_lock(lockaddr);
   *(int*)varaddr = 42;
   __tsan_java_mutex_unlock(lockaddr);
diff --git a/lib/tsan/lit_tests/java_lock_rec.cc b/lib/tsan/lit_tests/java_lock_rec.cc
new file mode 100644
index 0000000..5cc80d4
--- /dev/null
+++ b/lib/tsan/lit_tests/java_lock_rec.cc
@@ -0,0 +1,54 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include "java.h"
+#include <unistd.h>
+
+jptr varaddr;
+jptr lockaddr;
+
+void *Thread(void *p) {
+  __tsan_java_mutex_lock(lockaddr);
+  __tsan_java_mutex_lock(lockaddr);
+  *(int*)varaddr = 42;
+  int rec = __tsan_java_mutex_unlock_rec(lockaddr);
+  if (rec != 2) {
+    printf("FAILED 0 rec=%d\n", rec);
+    exit(1);
+  }
+  sleep(2);
+  __tsan_java_mutex_lock_rec(lockaddr, rec);
+  if (*(int*)varaddr != 43) {
+    printf("FAILED 3 var=%d\n", *(int*)varaddr);
+    exit(1);
+  }
+  __tsan_java_mutex_unlock(lockaddr);
+  __tsan_java_mutex_unlock(lockaddr);
+  return 0;
+}
+
+int main() {
+  int const kHeapSize = 1024 * 1024;
+  void *jheap = malloc(kHeapSize);
+  __tsan_java_init((jptr)jheap, kHeapSize);
+  const int kBlockSize = 16;
+  __tsan_java_alloc((jptr)jheap, kBlockSize);
+  varaddr = (jptr)jheap;
+  *(int*)varaddr = 0;
+  lockaddr = (jptr)jheap + 8;
+  pthread_t th;
+  pthread_create(&th, 0, Thread, 0);
+  sleep(1);
+  __tsan_java_mutex_lock(lockaddr);
+  if (*(int*)varaddr != 42) {
+    printf("FAILED 1 var=%d\n", *(int*)varaddr);
+    exit(1);
+  }
+  *(int*)varaddr = 43;
+  __tsan_java_mutex_unlock(lockaddr);
+  pthread_join(th, 0);
+  __tsan_java_free((jptr)jheap, kBlockSize);
+  printf("OK\n");
+  return __tsan_java_fini();
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: FAILED
diff --git a/lib/tsan/lit_tests/java_lock_rec_race.cc b/lib/tsan/lit_tests/java_lock_rec_race.cc
new file mode 100644
index 0000000..a868e26
--- /dev/null
+++ b/lib/tsan/lit_tests/java_lock_rec_race.cc
@@ -0,0 +1,48 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include "java.h"
+#include <unistd.h>
+
+jptr varaddr;
+jptr lockaddr;
+
+void *Thread(void *p) {
+  __tsan_java_mutex_lock(lockaddr);
+  __tsan_java_mutex_lock(lockaddr);
+  __tsan_java_mutex_lock(lockaddr);
+  int rec = __tsan_java_mutex_unlock_rec(lockaddr);
+  if (rec != 3) {
+    printf("FAILED 0 rec=%d\n", rec);
+    exit(1);
+  }
+  *(int*)varaddr = 42;
+  sleep(2);
+  __tsan_java_mutex_lock_rec(lockaddr, rec);
+  __tsan_java_mutex_unlock(lockaddr);
+  __tsan_java_mutex_unlock(lockaddr);
+  __tsan_java_mutex_unlock(lockaddr);
+  return 0;
+}
+
+int main() {
+  int const kHeapSize = 1024 * 1024;
+  void *jheap = malloc(kHeapSize);
+  __tsan_java_init((jptr)jheap, kHeapSize);
+  const int kBlockSize = 16;
+  __tsan_java_alloc((jptr)jheap, kBlockSize);
+  varaddr = (jptr)jheap;
+  *(int*)varaddr = 0;
+  lockaddr = (jptr)jheap + 8;
+  pthread_t th;
+  pthread_create(&th, 0, Thread, 0);
+  sleep(1);
+  __tsan_java_mutex_lock(lockaddr);
+  *(int*)varaddr = 43;
+  __tsan_java_mutex_unlock(lockaddr);
+  pthread_join(th, 0);
+  __tsan_java_free((jptr)jheap, kBlockSize);
+  printf("OK\n");
+  return __tsan_java_fini();
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: FAILED
diff --git a/lib/tsan/lit_tests/java_race.cc b/lib/tsan/lit_tests/java_race.cc
index 722bb6e..4841a7d 100644
--- a/lib/tsan/lit_tests/java_race.cc
+++ b/lib/tsan/lit_tests/java_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include "java.h"
 
 void *Thread(void *p) {
diff --git a/lib/tsan/lit_tests/java_race_move.cc b/lib/tsan/lit_tests/java_race_move.cc
index bb63ea9..6da8a10 100644
--- a/lib/tsan/lit_tests/java_race_move.cc
+++ b/lib/tsan/lit_tests/java_race_move.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include "java.h"
 
 jptr varaddr;
diff --git a/lib/tsan/lit_tests/java_rwlock.cc b/lib/tsan/lit_tests/java_rwlock.cc
index 1e8940a..d1f3873 100644
--- a/lib/tsan/lit_tests/java_rwlock.cc
+++ b/lib/tsan/lit_tests/java_rwlock.cc
@@ -1,10 +1,12 @@
 // RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
 #include "java.h"
+#include <unistd.h>
 
 jptr varaddr;
 jptr lockaddr;
 
 void *Thread(void *p) {
+  sleep(1);
   __tsan_java_mutex_read_lock(lockaddr);
   *(int*)varaddr = 42;
   __tsan_java_mutex_read_unlock(lockaddr);
diff --git a/lib/tsan/lit_tests/lit.cfg b/lib/tsan/lit_tests/lit.cfg
index 7e2db7b..ce6c23a 100644
--- a/lib/tsan/lit_tests/lit.cfg
+++ b/lib/tsan/lit_tests/lit.cfg
@@ -2,6 +2,14 @@
 
 import os
 
+def get_required_attr(config, attr_name):
+  attr_value = getattr(config, attr_name, None)
+  if not attr_value:
+    lit.fatal("No attribute %r in test configuration! You may need to run "
+              "tests from your build directory or add this attribute "
+              "to lit.site.cfg " % attr_name)
+  return attr_value
+
 # Setup config name.
 config.name = 'ThreadSanitizer'
 
@@ -30,14 +38,6 @@
   if not llvm_config:
     DisplayNoConfigMessage()
 
-  # Validate that llvm-config points to the same source tree.
-  llvm_src_root = lit.util.capture(["llvm-config", "--src-root"]).strip()
-  tsan_test_src_root = os.path.join(llvm_src_root, "projects", "compiler-rt",
-                                    "lib", "tsan", "lit_tests")
-  if (os.path.realpath(tsan_test_src_root) !=
-      os.path.realpath(config.test_source_root)):
-    DisplayNoConfigMessage()
-
   # Find out the presumed location of generated site config.
   llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
   tsan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
@@ -48,35 +48,21 @@
   lit.load_config(config, tsan_site_cfg)
   raise SystemExit
 
-# Setup attributes common for all compiler-rt projects.
-compiler_rt_lit_cfg = os.path.join(llvm_src_root, "projects", "compiler-rt",
-                                   "lib", "lit.common.cfg")
-if (not compiler_rt_lit_cfg) or (not os.path.exists(compiler_rt_lit_cfg)):
-  lit.fatal("Can't find common compiler-rt lit config at: %r"
-            % compiler_rt_lit_cfg)
-lit.load_config(config, compiler_rt_lit_cfg)
-
 # Setup environment variables for running ThreadSanitizer.
 tsan_options = "atexit_sleep_ms=0"
-# Get path to external LLVM symbolizer to run ThreadSanitizer output tests.
-llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
-if llvm_tools_dir:
-  llvm_symbolizer_path = os.path.join(llvm_tools_dir, "llvm-symbolizer")
-  tsan_options += " " + "external_symbolizer_path=" + llvm_symbolizer_path
+# Set path to external LLVM symbolizer to run ThreadSanitizer output tests.
+tsan_options += " " + "external_symbolizer_path=" + config.llvm_symbolizer_path
 
 config.environment['TSAN_OPTIONS'] = tsan_options
 
 # Setup default compiler flags used with -fsanitize=thread option.
 # FIXME: Review the set of required flags and check if it can be reduced.
 clang_tsan_cflags = ("-fsanitize=thread "
-                      + "-fPIE "
-                      + "-fno-builtin "
                       + "-g "
                       + "-Wall "
-                      + "-pie "
                       + "-lpthread "
                       + "-ldl ")
-clang_tsan_cxxflags = "-ccc-cxx " + clang_tsan_cflags
+clang_tsan_cxxflags = "--driver-mode=g++ " + clang_tsan_cflags
 config.substitutions.append( ("%clangxx_tsan ", (" " + config.clang + " " +
                                                 clang_tsan_cxxflags + " ")) )
 config.substitutions.append( ("%clang_tsan ", (" " + config.clang + " " +
diff --git a/lib/tsan/lit_tests/lit.site.cfg.in b/lib/tsan/lit_tests/lit.site.cfg.in
index b1c6ccf..a212393 100644
--- a/lib/tsan/lit_tests/lit.site.cfg.in
+++ b/lib/tsan/lit_tests/lit.site.cfg.in
@@ -1,19 +1,8 @@
 ## Autogenerated by LLVM/Clang configuration.
 # Do not edit!
 
-config.clang = "@LLVM_BINARY_DIR@/bin/clang"
-config.host_os = "@HOST_OS@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.target_triple = "@TARGET_TRIPLE@"
+# Load common config for all compiler-rt lit tests.
+lit.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
 
-# LLVM tools dir can be passed in lit parameters, so try to
-# apply substitution.
-try:
-  config.llvm_tools_dir = config.llvm_tools_dir % lit.params
-except KeyError,e:
-  key, = e.args
-  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Let the main config do the real work.
+# Load tool-specific config that would do the real work.
 lit.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
diff --git a/lib/tsan/lit_tests/load_shared_lib.cc b/lib/tsan/lit_tests/load_shared_lib.cc
new file mode 100644
index 0000000..d60cd57
--- /dev/null
+++ b/lib/tsan/lit_tests/load_shared_lib.cc
@@ -0,0 +1,44 @@
+// Check that if the list of shared libraries changes between the two race
+// reports, the second report occurring in a new shared library is still
+// symbolized correctly.
+
+// RUN: %clangxx_tsan -O1 %p/SharedLibs/load_shared_lib-so.cc \
+// RUN:     -fPIC -shared -o %t-so.so
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#include <string>
+
+int GLOB = 0;
+
+void *write_glob(void *unused) {
+  GLOB++;
+  return NULL;
+}
+
+void race_two_threads(void *(*access_callback)(void *unused)) {
+  pthread_t t1, t2;
+  pthread_create(&t1, NULL, access_callback, NULL);
+  pthread_create(&t2, NULL, access_callback, NULL);
+  pthread_join(t1, NULL);
+  pthread_join(t2, NULL);
+}
+
+int main(int argc, char *argv[]) {
+  std::string path = std::string(argv[0]) + std::string("-so.so");
+  race_two_threads(write_glob);
+  // CHECK: write_glob
+  void *lib = dlopen(path.c_str(), RTLD_NOW);
+    if (!lib) {
+    printf("error in dlopen(): %s\n", dlerror());
+    return 1;
+  }
+  void *(*write_from_so)(void *unused);
+  *(void **)&write_from_so = dlsym(lib, "write_from_so");
+  race_two_threads(write_from_so);
+  // CHECK: write_from_so
+  return 0;
+}
diff --git a/lib/tsan/lit_tests/longjmp.cc b/lib/tsan/lit_tests/longjmp.cc
new file mode 100644
index 0000000..d9ca4ca
--- /dev/null
+++ b/lib/tsan/lit_tests/longjmp.cc
@@ -0,0 +1,22 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+int foo(jmp_buf env) {
+  longjmp(env, 42);
+}
+
+int main() {
+  jmp_buf env;
+  if (setjmp(env) == 42) {
+    printf("JUMPED\n");
+    return 0;
+  }
+  foo(env);
+  printf("FAILED\n");
+  return 0;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: JUMPED
diff --git a/lib/tsan/lit_tests/longjmp2.cc b/lib/tsan/lit_tests/longjmp2.cc
new file mode 100644
index 0000000..0d551fa
--- /dev/null
+++ b/lib/tsan/lit_tests/longjmp2.cc
@@ -0,0 +1,24 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+int foo(sigjmp_buf env) {
+  printf("env=%p\n", env);
+  siglongjmp(env, 42);
+}
+
+int main() {
+  sigjmp_buf env;
+  printf("env=%p\n", env);
+  if (sigsetjmp(env, 1) == 42) {
+    printf("JUMPED\n");
+    return 0;
+  }
+  foo(env);
+  printf("FAILED\n");
+  return 0;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: JUMPED
diff --git a/lib/tsan/lit_tests/longjmp3.cc b/lib/tsan/lit_tests/longjmp3.cc
new file mode 100644
index 0000000..ae2cfd0
--- /dev/null
+++ b/lib/tsan/lit_tests/longjmp3.cc
@@ -0,0 +1,48 @@
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+void bar(jmp_buf env) {
+  volatile int x = 42;
+  longjmp(env, 42);
+  x++;
+}
+
+void foo(jmp_buf env) {
+  volatile int x = 42;
+  bar(env);
+  x++;
+}
+
+void badguy() {
+  pthread_mutex_t mtx;
+  pthread_mutex_init(&mtx, 0);
+  pthread_mutex_lock(&mtx);
+  pthread_mutex_destroy(&mtx);
+}
+
+void mymain() {
+  jmp_buf env;
+  if (setjmp(env) == 42) {
+    badguy();
+    return;
+  }
+  foo(env);
+  printf("FAILED\n");
+}
+
+int main() {
+  volatile int x = 42;
+  mymain();
+  return x;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
+// CHECK:   #0 pthread_mutex_destroy
+// CHECK:   #1 badguy
+// CHECK:   #2 mymain
+// CHECK:   #3 main
+
diff --git a/lib/tsan/lit_tests/longjmp4.cc b/lib/tsan/lit_tests/longjmp4.cc
new file mode 100644
index 0000000..6b0526e
--- /dev/null
+++ b/lib/tsan/lit_tests/longjmp4.cc
@@ -0,0 +1,51 @@
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <string.h>
+
+void bar(jmp_buf env) {
+  volatile int x = 42;
+  jmp_buf env2;
+  memcpy(env2, env, sizeof(jmp_buf));
+  longjmp(env2, 42);
+  x++;
+}
+
+void foo(jmp_buf env) {
+  volatile int x = 42;
+  bar(env);
+  x++;
+}
+
+void badguy() {
+  pthread_mutex_t mtx;
+  pthread_mutex_init(&mtx, 0);
+  pthread_mutex_lock(&mtx);
+  pthread_mutex_destroy(&mtx);
+}
+
+void mymain() {
+  jmp_buf env;
+  if (setjmp(env) == 42) {
+    badguy();
+    return;
+  }
+  foo(env);
+  printf("FAILED\n");
+}
+
+int main() {
+  volatile int x = 42;
+  mymain();
+  return x;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
+// CHECK:   #0 pthread_mutex_destroy
+// CHECK:   #1 badguy
+// CHECK:   #2 mymain
+// CHECK:   #3 main
+
diff --git a/lib/tsan/lit_tests/malloc_overflow.cc b/lib/tsan/lit_tests/malloc_overflow.cc
new file mode 100644
index 0000000..19423c5
--- /dev/null
+++ b/lib/tsan/lit_tests/malloc_overflow.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+  void *p = malloc((size_t)-1);
+  if (p != 0)
+    printf("FAIL malloc(-1) = %p\n", p);
+  p = malloc((size_t)-1 / 2);
+  if (p != 0)
+    printf("FAIL malloc(-1/2) = %p\n", p);
+  p = calloc((size_t)-1, (size_t)-1);
+  if (p != 0)
+    printf("FAIL calloc(-1, -1) = %p\n", p);
+  p = calloc((size_t)-1 / 2, (size_t)-1 / 2);
+  if (p != 0)
+    printf("FAIL calloc(-1/2, -1/2) = %p\n", p);
+  printf("OK\n");
+}
+
+// CHECK-NOT: FAIL
+// CHECK-NOT: failed to allocate
diff --git a/lib/tsan/lit_tests/malloc_stack.cc b/lib/tsan/lit_tests/malloc_stack.cc
new file mode 100644
index 0000000..3603497
--- /dev/null
+++ b/lib/tsan/lit_tests/malloc_stack.cc
@@ -0,0 +1,25 @@
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+_Atomic(int*) p;
+
+void *thr(void *a) {
+  sleep(1);
+  int *pp = __c11_atomic_load(&p, __ATOMIC_RELAXED);
+  *pp = 42;
+  return 0;
+}
+
+int main() {
+  pthread_t th;
+  pthread_create(&th, 0, thr, p);
+  __c11_atomic_store(&p, new int, __ATOMIC_RELAXED);
+  pthread_join(th, 0);
+}
+
+// CHECK: data race
+// CHECK:   Previous write
+// CHECK:     #0 operator new
+// CHECK:   Location is heap block
+// CHECK:     #0 operator new
diff --git a/lib/tsan/lit_tests/memcpy_race.cc b/lib/tsan/lit_tests/memcpy_race.cc
index 806740d..8f39113 100644
--- a/lib/tsan/lit_tests/memcpy_race.cc
+++ b/lib/tsan/lit_tests/memcpy_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stddef.h>
 #include <stdio.h>
@@ -10,13 +10,15 @@
 char *data2 = new char[10];
 
 void *Thread1(void *x) {
-  memcpy(data+5, data1, 1);
+  static volatile int size = 1;
+  memcpy(data+5, data1, size);
   return NULL;
 }
 
 void *Thread2(void *x) {
+  static volatile int size = 4;
   sleep(1);
-  memcpy(data+3, data2, 4);
+  memcpy(data+3, data2, size);
   return NULL;
 }
 
diff --git a/lib/tsan/lit_tests/mop_with_offset.cc b/lib/tsan/lit_tests/mop_with_offset.cc
index 0c11ef6..2b6a4ff 100644
--- a/lib/tsan/lit_tests/mop_with_offset.cc
+++ b/lib/tsan/lit_tests/mop_with_offset.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stddef.h>
 #include <stdio.h>
diff --git a/lib/tsan/lit_tests/mop_with_offset2.cc b/lib/tsan/lit_tests/mop_with_offset2.cc
index ee0d64a..037c4db 100644
--- a/lib/tsan/lit_tests/mop_with_offset2.cc
+++ b/lib/tsan/lit_tests/mop_with_offset2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stddef.h>
 #include <stdio.h>
diff --git a/lib/tsan/lit_tests/mutex_destroy_locked.cc b/lib/tsan/lit_tests/mutex_destroy_locked.cc
index 27a0424..9b020d3 100644
--- a/lib/tsan/lit_tests/mutex_destroy_locked.cc
+++ b/lib/tsan/lit_tests/mutex_destroy_locked.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <unistd.h>
 
diff --git a/lib/tsan/lit_tests/mutexset1.cc b/lib/tsan/lit_tests/mutexset1.cc
index f32a770..ca87a7b 100644
--- a/lib/tsan/lit_tests/mutexset1.cc
+++ b/lib/tsan/lit_tests/mutexset1.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset2.cc b/lib/tsan/lit_tests/mutexset2.cc
index 15d2303..9ccf952 100644
--- a/lib/tsan/lit_tests/mutexset2.cc
+++ b/lib/tsan/lit_tests/mutexset2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset3.cc b/lib/tsan/lit_tests/mutexset3.cc
index 6ac7ad1..272ddaf 100644
--- a/lib/tsan/lit_tests/mutexset3.cc
+++ b/lib/tsan/lit_tests/mutexset3.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset4.cc b/lib/tsan/lit_tests/mutexset4.cc
index 75684cf..be751fa 100644
--- a/lib/tsan/lit_tests/mutexset4.cc
+++ b/lib/tsan/lit_tests/mutexset4.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset5.cc b/lib/tsan/lit_tests/mutexset5.cc
index 6e75810..e013edb 100644
--- a/lib/tsan/lit_tests/mutexset5.cc
+++ b/lib/tsan/lit_tests/mutexset5.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset6.cc b/lib/tsan/lit_tests/mutexset6.cc
index 4b19a12..f5e6e66 100644
--- a/lib/tsan/lit_tests/mutexset6.cc
+++ b/lib/tsan/lit_tests/mutexset6.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/mutexset7.cc b/lib/tsan/lit_tests/mutexset7.cc
index 141bde2..51451b2 100644
--- a/lib/tsan/lit_tests/mutexset7.cc
+++ b/lib/tsan/lit_tests/mutexset7.cc
@@ -1,9 +1,10 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
 
 int Global;
+__thread int huge[1024*1024];
 
 void *Thread1(void *x) {
   sleep(1);
diff --git a/lib/tsan/lit_tests/mutexset8.cc b/lib/tsan/lit_tests/mutexset8.cc
new file mode 100644
index 0000000..8822b05
--- /dev/null
+++ b/lib/tsan/lit_tests/mutexset8.cc
@@ -0,0 +1,39 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+pthread_mutex_t *mtx;
+
+void *Thread1(void *x) {
+  sleep(1);
+  pthread_mutex_lock(mtx);
+  Global++;
+  pthread_mutex_unlock(mtx);
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  Global--;
+  return NULL;
+}
+
+int main() {
+  // CHECK: WARNING: ThreadSanitizer: data race
+  // CHECK:   Write of size 4 at {{.*}} by thread T1
+  // CHECK:                         (mutexes: write [[M1:M[0-9]+]]):
+  // CHECK:   Previous write of size 4 at {{.*}} by thread T2:
+  // CHECK:   Mutex [[M1]] created at:
+  // CHECK:     #0 pthread_mutex_init
+  // CHECK:     #1 main {{.*}}/mutexset8.cc
+  mtx = new pthread_mutex_t;
+  pthread_mutex_init(mtx, 0);
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  pthread_mutex_destroy(mtx);
+  delete mtx;
+}
diff --git a/lib/tsan/lit_tests/oob_race.cc b/lib/tsan/lit_tests/oob_race.cc
new file mode 100644
index 0000000..9d8e222
--- /dev/null
+++ b/lib/tsan/lit_tests/oob_race.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+const long kOffset = 64*1024;
+
+void *Thread(void *p) {
+  ((char*)p)[-kOffset] = 43;
+  return 0;
+}
+
+int main() {
+  char *volatile p0 = new char[16];
+  delete[] p0;
+  char *p = new char[32];
+  pthread_t th;
+  pthread_create(&th, 0, Thread, p);
+  p[-kOffset] = 42;
+  pthread_join(th, 0);
+}
+
+// Used to crash with CHECK failed.
+// CHECK: WARNING: ThreadSanitizer: data race
+
diff --git a/lib/tsan/lit_tests/race_on_barrier.c b/lib/tsan/lit_tests/race_on_barrier.c
index 3e76f8b..3c0199d 100644
--- a/lib/tsan/lit_tests/race_on_barrier.c
+++ b/lib/tsan/lit_tests/race_on_barrier.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <stddef.h>
diff --git a/lib/tsan/lit_tests/race_on_barrier2.c b/lib/tsan/lit_tests/race_on_barrier2.c
index 46a4f50..62773d4 100644
--- a/lib/tsan/lit_tests/race_on_barrier2.c
+++ b/lib/tsan/lit_tests/race_on_barrier2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <stddef.h>
diff --git a/lib/tsan/lit_tests/race_on_heap.cc b/lib/tsan/lit_tests/race_on_heap.cc
index 35434ea..a84c0de 100644
--- a/lib/tsan/lit_tests/race_on_heap.cc
+++ b/lib/tsan/lit_tests/race_on_heap.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/lib/tsan/lit_tests/race_on_mutex.c b/lib/tsan/lit_tests/race_on_mutex.c
index aff32f9..e663414 100644
--- a/lib/tsan/lit_tests/race_on_mutex.c
+++ b/lib/tsan/lit_tests/race_on_mutex.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <stddef.h>
diff --git a/lib/tsan/lit_tests/race_on_mutex2.c b/lib/tsan/lit_tests/race_on_mutex2.c
index 84bef75..80c395e 100644
--- a/lib/tsan/lit_tests/race_on_mutex2.c
+++ b/lib/tsan/lit_tests/race_on_mutex2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <stddef.h>
diff --git a/lib/tsan/lit_tests/race_on_read.cc b/lib/tsan/lit_tests/race_on_read.cc
index 7d22681..4ca4b25 100644
--- a/lib/tsan/lit_tests/race_on_read.cc
+++ b/lib/tsan/lit_tests/race_on_read.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/race_on_write.cc b/lib/tsan/lit_tests/race_on_write.cc
index f1b0bb1..8a56c84 100644
--- a/lib/tsan/lit_tests/race_on_write.cc
+++ b/lib/tsan/lit_tests/race_on_write.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/race_with_finished_thread.cc b/lib/tsan/lit_tests/race_with_finished_thread.cc
index a267290..c713c67 100644
--- a/lib/tsan/lit_tests/race_with_finished_thread.cc
+++ b/lib/tsan/lit_tests/race_with_finished_thread.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stddef.h>
 #include <stdio.h>
diff --git a/lib/tsan/lit_tests/signal_errno.cc b/lib/tsan/lit_tests/signal_errno.cc
index 8181555..2febca3 100644
--- a/lib/tsan/lit_tests/signal_errno.cc
+++ b/lib/tsan/lit_tests/signal_errno.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/lib/tsan/lit_tests/signal_malloc.cc b/lib/tsan/lit_tests/signal_malloc.cc
index 4dbc2f7..ef180b8 100644
--- a/lib/tsan/lit_tests/signal_malloc.cc
+++ b/lib/tsan/lit_tests/signal_malloc.cc
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>
diff --git a/lib/tsan/lit_tests/sigsuspend.cc b/lib/tsan/lit_tests/sigsuspend.cc
new file mode 100644
index 0000000..78d507f
--- /dev/null
+++ b/lib/tsan/lit_tests/sigsuspend.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <assert.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdio.h>
+
+static bool signal_handler_ran = false;
+
+void do_nothing_signal_handler(int signum) {
+  write(1, "HANDLER\n", 8);
+  signal_handler_ran = true;
+}
+
+int main() {
+  const int kSignalToTest = SIGSYS;
+  assert(SIG_ERR != signal(kSignalToTest, do_nothing_signal_handler));
+  sigset_t empty_set;
+  assert(0 == sigemptyset(&empty_set));
+  sigset_t one_signal = empty_set;
+  assert(0 == sigaddset(&one_signal, kSignalToTest));
+  sigset_t old_set;
+  assert(0 == sigprocmask(SIG_BLOCK, &one_signal, &old_set));
+  raise(kSignalToTest);
+  assert(!signal_handler_ran);
+  sigset_t all_but_one;
+  assert(0 == sigfillset(&all_but_one));
+  assert(0 == sigdelset(&all_but_one, kSignalToTest));
+  sigsuspend(&all_but_one);
+  assert(signal_handler_ran);
+
+  // Restore the original set.
+  assert(0 == sigprocmask(SIG_SETMASK, &old_set, NULL));
+  printf("DONE");
+}
+
+// CHECK: HANDLER
+// CHECK: DONE
diff --git a/lib/tsan/lit_tests/simple_race.c b/lib/tsan/lit_tests/simple_race.c
index 44aff89..80a83e0 100644
--- a/lib/tsan/lit_tests/simple_race.c
+++ b/lib/tsan/lit_tests/simple_race.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 
diff --git a/lib/tsan/lit_tests/simple_race.cc b/lib/tsan/lit_tests/simple_race.cc
index 99cf228..47854cf 100644
--- a/lib/tsan/lit_tests/simple_race.cc
+++ b/lib/tsan/lit_tests/simple_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 
diff --git a/lib/tsan/lit_tests/simple_stack.c b/lib/tsan/lit_tests/simple_stack.c
index 4539cb7..a447e28 100644
--- a/lib/tsan/lit_tests/simple_stack.c
+++ b/lib/tsan/lit_tests/simple_stack.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/simple_stack2.cc b/lib/tsan/lit_tests/simple_stack2.cc
index bf27a15..7a034c4 100644
--- a/lib/tsan/lit_tests/simple_stack2.cc
+++ b/lib/tsan/lit_tests/simple_stack2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/sleep_sync.cc b/lib/tsan/lit_tests/sleep_sync.cc
index c3d47d3..217a52a 100644
--- a/lib/tsan/lit_tests/sleep_sync.cc
+++ b/lib/tsan/lit_tests/sleep_sync.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <unistd.h>
 
diff --git a/lib/tsan/lit_tests/sleep_sync2.cc b/lib/tsan/lit_tests/sleep_sync2.cc
index d9961bc..e229992 100644
--- a/lib/tsan/lit_tests/sleep_sync2.cc
+++ b/lib/tsan/lit_tests/sleep_sync2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <unistd.h>
 
diff --git a/lib/tsan/lit_tests/stack_race.cc b/lib/tsan/lit_tests/stack_race.cc
index beeb573..7fabce2 100644
--- a/lib/tsan/lit_tests/stack_race.cc
+++ b/lib/tsan/lit_tests/stack_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stddef.h>
 
diff --git a/lib/tsan/lit_tests/stack_race2.cc b/lib/tsan/lit_tests/stack_race2.cc
index 5bdf1bd..c759ec9 100644
--- a/lib/tsan/lit_tests/stack_race2.cc
+++ b/lib/tsan/lit_tests/stack_race2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stddef.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/static_init3.cc b/lib/tsan/lit_tests/static_init3.cc
index 40fd4b9..70a3c16 100644
--- a/lib/tsan/lit_tests/static_init3.cc
+++ b/lib/tsan/lit_tests/static_init3.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/lib/tsan/lit_tests/suppress_same_address.cc b/lib/tsan/lit_tests/suppress_same_address.cc
index 174d1cc..c516f89 100644
--- a/lib/tsan/lit_tests/suppress_same_address.cc
+++ b/lib/tsan/lit_tests/suppress_same_address.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 
 int X;
diff --git a/lib/tsan/lit_tests/suppress_same_stacks.cc b/lib/tsan/lit_tests/suppress_same_stacks.cc
index 32bff9d..f0ab8b3 100644
--- a/lib/tsan/lit_tests/suppress_same_stacks.cc
+++ b/lib/tsan/lit_tests/suppress_same_stacks.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 
 volatile int N;  // Prevent loop unrolling.
diff --git a/lib/tsan/lit_tests/suppressions_global.cc b/lib/tsan/lit_tests/suppressions_global.cc
new file mode 100644
index 0000000..181cb56
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_global.cc
@@ -0,0 +1,29 @@
+// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+int RacyGlobal;
+
+void *Thread1(void *x) {
+  RacyGlobal = 42;
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  RacyGlobal = 43;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  printf("OK\n");
+  return 0;
+}
+
+// CHECK-NOT: failed to open suppressions file
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+
diff --git a/lib/tsan/lit_tests/suppressions_global.cc.supp b/lib/tsan/lit_tests/suppressions_global.cc.supp
new file mode 100644
index 0000000..5fa8a2e
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_global.cc.supp
@@ -0,0 +1,2 @@
+race:RacyGlobal
+
diff --git a/lib/tsan/lit_tests/suppressions_race.cc b/lib/tsan/lit_tests/suppressions_race.cc
new file mode 100644
index 0000000..c88e69b
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_race.cc
@@ -0,0 +1,31 @@
+// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+  sleep(1);
+  Global = 42;
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  Global = 43;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  printf("OK\n");
+  return 0;
+}
+
+// CHECK-NOT: failed to open suppressions file
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+
diff --git a/lib/tsan/lit_tests/suppressions_race.cc.supp b/lib/tsan/lit_tests/suppressions_race.cc.supp
new file mode 100644
index 0000000..cbdba76
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_race.cc.supp
@@ -0,0 +1,2 @@
+race:Thread1
+
diff --git a/lib/tsan/lit_tests/suppressions_race2.cc b/lib/tsan/lit_tests/suppressions_race2.cc
new file mode 100644
index 0000000..57146f9
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_race2.cc
@@ -0,0 +1,31 @@
+// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+  Global = 42;
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  sleep(1);
+  Global = 43;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  printf("OK\n");
+  return 0;
+}
+
+// CHECK-NOT: failed to open suppressions file
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+
diff --git a/lib/tsan/lit_tests/suppressions_race2.cc.supp b/lib/tsan/lit_tests/suppressions_race2.cc.supp
new file mode 100644
index 0000000..b3c4dbc
--- /dev/null
+++ b/lib/tsan/lit_tests/suppressions_race2.cc.supp
@@ -0,0 +1,2 @@
+race:Thread2
+
diff --git a/lib/tsan/lit_tests/test_output.sh b/lib/tsan/lit_tests/test_output.sh
index f4f8a5c..94b742a 100755
--- a/lib/tsan/lit_tests/test_output.sh
+++ b/lib/tsan/lit_tests/test_output.sh
@@ -12,7 +12,7 @@
 : ${FILECHECK:=FileCheck}
 
 # TODO: add testing for all of -O0...-O3
-CFLAGS="-fsanitize=thread -fsanitize-blacklist=$BLACKLIST -fPIE -O1 -g -fno-builtin -Wall"
+CFLAGS="-fsanitize=thread -fsanitize-blacklist=$BLACKLIST -fPIE -O1 -g -Wall"
 LDFLAGS="-pie -lpthread -ldl $ROOTDIR/rtl/libtsan.a"
 
 test_file() {
@@ -36,6 +36,14 @@
       echo SKIPPING FAILING TEST $c
       continue
     fi
+    if [[ $c == */load_shared_lib.cc ]]; then
+      echo TEST $c is not supported
+      continue
+    fi
+    if [ "`grep "TSAN_OPTIONS" $c`" ]; then
+      echo SKIPPING $c -- requires TSAN_OPTIONS
+      continue
+    fi
     COMPILER=$CXX
     case $c in
       *.c) COMPILER=$CC
diff --git a/lib/tsan/lit_tests/thread_end_with_ignore.cc b/lib/tsan/lit_tests/thread_end_with_ignore.cc
new file mode 100644
index 0000000..960a477
--- /dev/null
+++ b/lib/tsan/lit_tests/thread_end_with_ignore.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+extern "C" void AnnotateIgnoreReadsBegin(const char *f, int l);
+
+void *Thread(void *x) {
+  AnnotateIgnoreReadsBegin("", 0);
+  return 0;
+}
+
+int main() {
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  pthread_join(t, 0);
+}
+
+// CHECK: ThreadSanitizer: thread T1 finished with ignores enabled
+
diff --git a/lib/tsan/lit_tests/thread_end_with_ignore2.cc b/lib/tsan/lit_tests/thread_end_with_ignore2.cc
new file mode 100644
index 0000000..8f743ae
--- /dev/null
+++ b/lib/tsan/lit_tests/thread_end_with_ignore2.cc
@@ -0,0 +1,9 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+extern "C" void AnnotateIgnoreWritesBegin(const char *f, int l);
+
+int main() {
+  AnnotateIgnoreWritesBegin("", 0);
+}
+
+// CHECK: ThreadSanitizer: thread T0 finished with ignores enabled
+
diff --git a/lib/tsan/lit_tests/thread_leak3.c b/lib/tsan/lit_tests/thread_leak3.c
index a39c93c..5f447db 100644
--- a/lib/tsan/lit_tests/thread_leak3.c
+++ b/lib/tsan/lit_tests/thread_leak3.c
@@ -1,5 +1,6 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
+#include <unistd.h>
 
 void *Thread(void *x) {
   return 0;
@@ -8,6 +9,7 @@
 int main() {
   pthread_t t;
   pthread_create(&t, 0, Thread, 0);
+  sleep(1);
   return 0;
 }
 
diff --git a/lib/tsan/lit_tests/thread_leak4.c b/lib/tsan/lit_tests/thread_leak4.c
new file mode 100644
index 0000000..f9fad03
--- /dev/null
+++ b/lib/tsan/lit_tests/thread_leak4.c
@@ -0,0 +1,18 @@
+// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+
+void *Thread(void *x) {
+  sleep(10);
+  return 0;
+}
+
+int main() {
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  printf("OK\n");
+  return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
diff --git a/lib/tsan/lit_tests/thread_leak5.c b/lib/tsan/lit_tests/thread_leak5.c
new file mode 100644
index 0000000..329f723
--- /dev/null
+++ b/lib/tsan/lit_tests/thread_leak5.c
@@ -0,0 +1,19 @@
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *x) {
+  return 0;
+}
+
+int main() {
+  for (int i = 0; i < 5; i++) {
+    pthread_t t;
+    pthread_create(&t, 0, Thread, 0);
+  }
+  sleep(1);
+  return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: thread leak
+// CHECK:   And 4 more similar thread leaks
diff --git a/lib/tsan/lit_tests/thread_name.cc b/lib/tsan/lit_tests/thread_name.cc
index afb882f..646ab58 100644
--- a/lib/tsan/lit_tests/thread_name.cc
+++ b/lib/tsan/lit_tests/thread_name.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -15,7 +15,7 @@
 }
 
 void *Thread2(void *x) {
-#if defined(__linux__) && __GLIBC_PREREQ(2, 12)
+#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 12)
   pthread_setname_np(pthread_self(), "Thread2");
 #else
   AnnotateThreadName(__FILE__, __LINE__, "Thread2");
diff --git a/lib/tsan/lit_tests/tiny_race.c b/lib/tsan/lit_tests/tiny_race.c
index 44cc133..f77e160 100644
--- a/lib/tsan/lit_tests/tiny_race.c
+++ b/lib/tsan/lit_tests/tiny_race.c
@@ -1,15 +1,21 @@
-// RUN: %clang_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clang_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
+#include <unistd.h>
+
 int Global;
+
 void *Thread1(void *x) {
+  sleep(1);
   Global = 42;
   return x;
 }
+
 int main() {
   pthread_t t;
-  pthread_create(&t, NULL, Thread1, NULL);
+  pthread_create(&t, 0, Thread1, 0);
   Global = 43;
-  pthread_join(t, NULL);
+  pthread_join(t, 0);
   return Global;
 }
+
 // CHECK: WARNING: ThreadSanitizer: data race
diff --git a/lib/tsan/lit_tests/tls_race.cc b/lib/tsan/lit_tests/tls_race.cc
index bed6aaf..3cbcc9d 100644
--- a/lib/tsan/lit_tests/tls_race.cc
+++ b/lib/tsan/lit_tests/tls_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stddef.h>
 
diff --git a/lib/tsan/lit_tests/tls_race2.cc b/lib/tsan/lit_tests/tls_race2.cc
index 110abaa..1360870 100644
--- a/lib/tsan/lit_tests/tls_race2.cc
+++ b/lib/tsan/lit_tests/tls_race2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <stddef.h>
 #include <unistd.h>
diff --git a/lib/tsan/lit_tests/unaligned_norace.cc b/lib/tsan/lit_tests/unaligned_norace.cc
new file mode 100644
index 0000000..792224b
--- /dev/null
+++ b/lib/tsan/lit_tests/unaligned_norace.cc
@@ -0,0 +1,84 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+uint64_t objs[8*3*3*2][3];
+
+extern "C" {
+uint16_t __tsan_unaligned_read2(void *addr);
+uint32_t __tsan_unaligned_read4(void *addr);
+uint64_t __tsan_unaligned_read8(void *addr);
+void __tsan_unaligned_write2(void *addr, uint16_t v);
+void __tsan_unaligned_write4(void *addr, uint32_t v);
+void __tsan_unaligned_write8(void *addr, uint64_t v);
+}
+
+static void access(char *p, int sz, int rw) {
+  if (rw) {
+    switch (sz) {
+    case 0: __tsan_unaligned_write2(p, 0); break;
+    case 1: __tsan_unaligned_write4(p, 0); break;
+    case 2: __tsan_unaligned_write8(p, 0); break;
+    default: exit(1);
+    }
+  } else {
+    switch (sz) {
+    case 0: __tsan_unaligned_read2(p); break;
+    case 1: __tsan_unaligned_read4(p); break;
+    case 2: __tsan_unaligned_read8(p); break;
+    default: exit(1);
+    }
+  }
+}
+
+static int accesssize(int sz) {
+  switch (sz) {
+  case 0: return 2;
+  case 1: return 4;
+  case 2: return 8;
+  }
+  exit(1);
+}
+
+void Test(bool main) {
+  uint64_t *obj = objs[0];
+  for (int off = 0; off < 8; off++) {
+    for (int sz1 = 0; sz1 < 3; sz1++) {
+      for (int sz2 = 0; sz2 < 3; sz2++) {
+        for (int rw = 0; rw < 2; rw++) {
+          char *p = (char*)obj + off;
+          if (main) {
+            // printf("thr=%d off=%d sz1=%d sz2=%d rw=%d p=%p\n",
+            //        main, off, sz1, sz2, rw, p);
+            access(p, sz1, true);
+          } else {
+            p += accesssize(sz1);
+            // printf("thr=%d off=%d sz1=%d sz2=%d rw=%d p=%p\n",
+            //        main, off, sz1, sz2, rw, p);
+            access(p, sz2, rw);
+          }
+          obj += 3;
+        }
+      }
+    }
+  }
+}
+
+void *Thread(void *p) {
+  (void)p;
+  Test(false);
+  return 0;
+}
+
+int main() {
+  pthread_t th;
+  pthread_create(&th, 0, Thread, 0);
+  Test(true);
+  pthread_join(th, 0);
+  printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: OK
diff --git a/lib/tsan/lit_tests/unaligned_race.cc b/lib/tsan/lit_tests/unaligned_race.cc
new file mode 100644
index 0000000..6ac87b5
--- /dev/null
+++ b/lib/tsan/lit_tests/unaligned_race.cc
@@ -0,0 +1,135 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+uint64_t objs[8*2*(2 + 4 + 8)][2];
+
+extern "C" {
+uint16_t __sanitizer_unaligned_load16(void *addr);
+uint32_t __sanitizer_unaligned_load32(void *addr);
+uint64_t __sanitizer_unaligned_load64(void *addr);
+void __sanitizer_unaligned_store16(void *addr, uint16_t v);
+void __sanitizer_unaligned_store32(void *addr, uint32_t v);
+void __sanitizer_unaligned_store64(void *addr, uint64_t v);
+}
+
+// All this mess is to generate unique stack for each race,
+// otherwise tsan will suppress similar stacks.
+
+static void access(char *p, int sz, int rw) {
+  if (rw) {
+    switch (sz) {
+    case 0: __sanitizer_unaligned_store16(p, 0); break;
+    case 1: __sanitizer_unaligned_store32(p, 0); break;
+    case 2: __sanitizer_unaligned_store64(p, 0); break;
+    default: exit(1);
+    }
+  } else {
+    switch (sz) {
+    case 0: __sanitizer_unaligned_load16(p); break;
+    case 1: __sanitizer_unaligned_load32(p); break;
+    case 2: __sanitizer_unaligned_load64(p); break;
+    default: exit(1);
+    }
+  }
+}
+
+static int accesssize(int sz) {
+  switch (sz) {
+  case 0: return 2;
+  case 1: return 4;
+  case 2: return 8;
+  }
+  exit(1);
+}
+
+template<int off, int off2>
+static void access3(bool main, int sz1, bool rw, char *p) {
+  p += off;
+  if (main) {
+    access(p, sz1, true);
+  } else {
+    p += off2;
+    if (rw) {
+      *p = 42;
+    } else {
+       if (*p == 42)
+         printf("bingo!\n");
+    }
+  }
+}
+
+template<int off>
+static void access2(bool main, int sz1, int off2, bool rw, char *obj) {
+  if (off2 == 0)
+    access3<off, 0>(main, sz1, rw, obj);
+  else if (off2 == 1)
+    access3<off, 1>(main, sz1, rw, obj);
+  else if (off2 == 2)
+    access3<off, 2>(main, sz1, rw, obj);
+  else if (off2 == 3)
+    access3<off, 3>(main, sz1, rw, obj);
+  else if (off2 == 4)
+    access3<off, 4>(main, sz1, rw, obj);
+  else if (off2 == 5)
+    access3<off, 5>(main, sz1, rw, obj);
+  else if (off2 == 6)
+    access3<off, 6>(main, sz1, rw, obj);
+  else if (off2 == 7)
+    access3<off, 7>(main, sz1, rw, obj);
+}
+
+static void access1(bool main, int off, int sz1, int off2, bool rw, char *obj) {
+  if (off == 0)
+    access2<0>(main, sz1, off2, rw, obj);
+  else if (off == 1)
+    access2<1>(main, sz1, off2, rw, obj);
+  else if (off == 2)
+    access2<2>(main, sz1, off2, rw, obj);
+  else if (off == 3)
+    access2<3>(main, sz1, off2, rw, obj);
+  else if (off == 4)
+    access2<4>(main, sz1, off2, rw, obj);
+  else if (off == 5)
+    access2<5>(main, sz1, off2, rw, obj);
+  else if (off == 6)
+    access2<6>(main, sz1, off2, rw, obj);
+  else if (off == 7)
+    access2<7>(main, sz1, off2, rw, obj);
+}
+
+void Test(bool main) {
+  uint64_t *obj = objs[0];
+  for (int off = 0; off < 8; off++) {
+    for (int sz1 = 0; sz1 < 3; sz1++) {
+      for (int off2 = 0; off2 < accesssize(sz1); off2++) {
+        for (int rw = 0; rw < 2; rw++) {
+          // printf("thr=%d off=%d sz1=%d off2=%d rw=%d p=%p\n",
+          //        main, off, sz1, off2, rw, obj);
+          access1(main, off, sz1, off2, rw, (char*)obj);
+          obj += 2;
+        }
+      }
+    }
+  }
+}
+
+void *Thread(void *p) {
+  (void)p;
+  sleep(1);
+  Test(false);
+  return 0;
+}
+
+int main() {
+  pthread_t th;
+  pthread_create(&th, 0, Thread, 0);
+  Test(true);
+  pthread_join(th, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: ThreadSanitizer: reported 224 warnings
diff --git a/lib/tsan/lit_tests/vptr_harmful_race.cc b/lib/tsan/lit_tests/vptr_harmful_race.cc
index f51ba7e..0105c4c 100644
--- a/lib/tsan/lit_tests/vptr_harmful_race.cc
+++ b/lib/tsan/lit_tests/vptr_harmful_race.cc
@@ -1,7 +1,8 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <semaphore.h>
 #include <stdio.h>
+#include <unistd.h>
 
 struct A {
   A() {
@@ -34,6 +35,7 @@
 }
 
 void *Thread2(void *x) {
+  sleep(1);
   delete obj;
   return NULL;
 }
@@ -46,4 +48,4 @@
   pthread_join(t[1], NULL);
 }
 
-// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: WARNING: ThreadSanitizer: data race on vptr
diff --git a/lib/tsan/lit_tests/vptr_harmful_race2.cc b/lib/tsan/lit_tests/vptr_harmful_race2.cc
new file mode 100644
index 0000000..378790c
--- /dev/null
+++ b/lib/tsan/lit_tests/vptr_harmful_race2.cc
@@ -0,0 +1,51 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <unistd.h>
+
+struct A {
+  A() {
+    sem_init(&sem_, 0, 0);
+  }
+  virtual void F() {
+  }
+  void Done() {
+    sem_post(&sem_);
+  }
+  virtual ~A() {
+    sem_wait(&sem_);
+    sem_destroy(&sem_);
+  }
+  sem_t sem_;
+};
+
+struct B : A {
+  virtual void F() {
+  }
+  virtual ~B() { }
+};
+
+static A *obj = new B;
+
+void *Thread1(void *x) {
+  sleep(1);
+  obj->F();
+  obj->Done();
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  delete obj;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race on vptr
diff --git a/lib/tsan/lit_tests/write_in_reader_lock.cc b/lib/tsan/lit_tests/write_in_reader_lock.cc
index db8bac3..e872fe3 100644
--- a/lib/tsan/lit_tests/write_in_reader_lock.cc
+++ b/lib/tsan/lit_tests/write_in_reader_lock.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
 #include <pthread.h>
 #include <unistd.h>
 
diff --git a/lib/tsan/rtl/CMakeLists.txt b/lib/tsan/rtl/CMakeLists.txt
index f2a8533..f1a8ff4 100644
--- a/lib/tsan/rtl/CMakeLists.txt
+++ b/lib/tsan/rtl/CMakeLists.txt
@@ -43,7 +43,9 @@
     SOURCES ${TSAN_SOURCES} ${TSAN_ASM_SOURCES}
             $<TARGET_OBJECTS:RTInterception.${arch}>
             $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+            $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
     CFLAGS ${TSAN_CFLAGS}
-    DEFS ${TSAN_COMMON_DEFINITIONS})
+    DEFS ${TSAN_COMMON_DEFINITIONS}
+    SYMS tsan.syms)
   list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch})
 endif()
diff --git a/lib/tsan/rtl/Makefile.old b/lib/tsan/rtl/Makefile.old
index cf4121e..33944ff 100644
--- a/lib/tsan/rtl/Makefile.old
+++ b/lib/tsan/rtl/Makefile.old
@@ -1,10 +1,8 @@
 CXXFLAGS = -fPIE -g -Wall -Werror -fno-builtin -DTSAN_DEBUG=$(DEBUG) -DSANITIZER_DEBUG=$(DEBUG)
+CLANG=clang
 ifeq ($(DEBUG), 0)
   CXXFLAGS += -O3
 endif
-ifeq ($(CXX), clang++)
-  CXXFLAGS+= -Wgnu
-endif
 
 # For interception. FIXME: move interception one level higher.
 INTERCEPTION=../../interception
@@ -21,7 +19,7 @@
 endif  # CXX=g++
 endif  # DEBUG=0
 
-ifeq ($(CXX), clang++)
+ifeq ($(CXX), $(CLANG)++)
   # Global constructors are banned.
   CXXFLAGS+=-Wglobal-constructors
 endif
diff --git a/lib/tsan/rtl/tsan.syms b/lib/tsan/rtl/tsan.syms
new file mode 100644
index 0000000..4464a0a
--- /dev/null
+++ b/lib/tsan/rtl/tsan.syms
@@ -0,0 +1,5 @@
+{
+  __tsan_*;
+  __sanitizer_syscall_pre_*;
+  __sanitizer_syscall_post_*;
+};
diff --git a/lib/tsan/rtl/tsan_fd.cc b/lib/tsan/rtl/tsan_fd.cc
index b3cb884..332a12d 100644
--- a/lib/tsan/rtl/tsan_fd.cc
+++ b/lib/tsan/rtl/tsan_fd.cc
@@ -74,13 +74,14 @@
   uptr l1 = atomic_load(pl1, memory_order_consume);
   if (l1 == 0) {
     uptr size = kTableSizeL2 * sizeof(FdDesc);
-    void *p = internal_alloc(MBlockFD, size);
+    // We need this to reside in user memory to properly catch races on it.
+    void *p = user_alloc(thr, pc, size);
     internal_memset(p, 0, size);
     MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size);
     if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel))
       l1 = (uptr)p;
     else
-      internal_free(p);
+      user_free(thr, pc, p);
   }
   return &((FdDesc*)l1)[fd % kTableSizeL2];  // NOLINT
 }
@@ -159,9 +160,9 @@
   FdDesc *d = fddesc(thr, pc, fd);
   FdSync *s = d->sync;
   DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, s);
+  MemoryRead(thr, pc, (uptr)d, kSizeLog8);
   if (s)
     Release(thr, pc, (uptr)s);
-  MemoryRead(thr, pc, (uptr)d, kSizeLog8);
 }
 
 void FdAccess(ThreadState *thr, uptr pc, int fd) {
diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc
index 1ed04dd..c062592 100644
--- a/lib/tsan/rtl/tsan_flags.cc
+++ b/lib/tsan/rtl/tsan_flags.cc
@@ -49,12 +49,15 @@
   f->force_seq_cst_atomics = false;
   f->strip_path_prefix = "";
   f->suppressions = "";
+  f->print_suppressions = false;
+  f->print_benign = false;
   f->exitcode = 66;
   f->log_path = "stderr";
   f->atexit_sleep_ms = 1000;
   f->verbosity = 0;
   f->profile_memory = "";
   f->flush_memory_ms = 0;
+  f->flush_symbolizer_ms = 5000;
   f->stop_on_start = false;
   f->running_on_valgrind = false;
   f->external_symbolizer_path = "";
@@ -77,12 +80,15 @@
   ParseFlag(env, &f->force_seq_cst_atomics, "force_seq_cst_atomics");
   ParseFlag(env, &f->strip_path_prefix, "strip_path_prefix");
   ParseFlag(env, &f->suppressions, "suppressions");
+  ParseFlag(env, &f->print_suppressions, "print_suppressions");
+  ParseFlag(env, &f->print_benign, "print_benign");
   ParseFlag(env, &f->exitcode, "exitcode");
   ParseFlag(env, &f->log_path, "log_path");
   ParseFlag(env, &f->atexit_sleep_ms, "atexit_sleep_ms");
   ParseFlag(env, &f->verbosity, "verbosity");
   ParseFlag(env, &f->profile_memory, "profile_memory");
   ParseFlag(env, &f->flush_memory_ms, "flush_memory_ms");
+  ParseFlag(env, &f->flush_symbolizer_ms, "flush_symbolizer_ms");
   ParseFlag(env, &f->stop_on_start, "stop_on_start");
   ParseFlag(env, &f->external_symbolizer_path, "external_symbolizer_path");
   ParseFlag(env, &f->history_size, "history_size");
diff --git a/lib/tsan/rtl/tsan_flags.h b/lib/tsan/rtl/tsan_flags.h
index 16849cd..aaacd98 100644
--- a/lib/tsan/rtl/tsan_flags.h
+++ b/lib/tsan/rtl/tsan_flags.h
@@ -52,6 +52,10 @@
   const char *strip_path_prefix;
   // Suppressions filename.
   const char *suppressions;
+  // Print matched suppressions at exit.
+  bool print_suppressions;
+  // Print matched "benign" races at exit.
+  bool print_benign;
   // Override exit status if something was reported.
   int exitcode;
   // Write logs to "log_path.pid".
@@ -67,6 +71,8 @@
   const char *profile_memory;
   // Flush shadow memory every X ms.
   int flush_memory_ms;
+  // Flush symbolizer caches every X ms.
+  int flush_symbolizer_ms;
   // Stops on start until __tsan_resume() is called (for debugging).
   bool stop_on_start;
   // Controls whether RunningOnValgrind() returns true or false.
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index 8bc2762..fd23d7d 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -10,11 +10,12 @@
 // This file is a part of ThreadSanitizer (TSan), a race detector.
 //
 // FIXME: move as many interceptors as possible into
-// sanitizer_common/sanitizer_common_interceptors.h
+// sanitizer_common/sanitizer_common_interceptors.inc
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_linux.h"
 #include "sanitizer_common/sanitizer_platform_limits_posix.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
@@ -27,18 +28,21 @@
 
 using namespace __tsan;  // NOLINT
 
-const int kSigCount = 128;
+const int kSigCount = 64;
 
 struct my_siginfo_t {
-  int opaque[128];
+  // The size is determined by looking at sizeof of real siginfo_t on linux.
+  u64 opaque[128 / sizeof(u64)];
 };
 
 struct sigset_t {
-  u64 val[1024 / 8 / sizeof(u64)];
+  // The size is determined by looking at sizeof of real sigset_t on linux.
+  u64 val[128 / sizeof(u64)];
 };
 
 struct ucontext_t {
-  uptr opaque[117];
+  // The size is determined by looking at sizeof of real ucontext_t on linux.
+  u64 opaque[936 / sizeof(u64) + 1];
 };
 
 extern "C" int pthread_attr_init(void *attr);
@@ -60,6 +64,7 @@
 extern "C" void *__libc_calloc(uptr size, uptr n);
 extern "C" void *__libc_realloc(void *ptr, uptr size);
 extern "C" void __libc_free(void *ptr);
+extern "C" int mallopt(int param, int value);
 const int PTHREAD_MUTEX_RECURSIVE = 1;
 const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
 const int kPthreadAttrSize = 56;
@@ -72,6 +77,7 @@
 const int SIGSEGV = 11;
 const int SIGPIPE = 13;
 const int SIGBUS = 7;
+const int SIGSYS = 31;
 void *const MAP_FAILED = (void*)-1;
 const int PTHREAD_BARRIER_SERIAL_THREAD = -1;
 const int MAP_FIXED = 0x10;
@@ -176,8 +182,7 @@
     StatInc(thr, StatInt_##func); \
     const uptr caller_pc = GET_CALLER_PC(); \
     ScopedInterceptor si(thr, #func, caller_pc); \
-    const uptr pc = __sanitizer::StackTrace::GetPreviousInstructionPc( \
-        __sanitizer::StackTrace::GetCurrentPc()); \
+    const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
     (void)pc; \
 /**/
 
@@ -291,15 +296,6 @@
 
 static AtExitContext *atexit_ctx;
 
-static void finalize(void *arg) {
-  ThreadState * thr = cur_thread();
-  uptr pc = 0;
-  atexit_ctx->exit(thr, pc);
-  int status = Finalize(cur_thread());
-  if (status)
-    _exit(status);
-}
-
 TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
   if (cur_thread()->in_symbolizer)
     return 0;
@@ -323,16 +319,106 @@
   return atexit_ctx->atexit(thr, pc, false, (void(*)())f, arg);
 }
 
-TSAN_INTERCEPTOR(void, longjmp, void *env, int val) {
-  SCOPED_TSAN_INTERCEPTOR(longjmp, env, val);
-  Printf("ThreadSanitizer: longjmp() is not supported\n");
-  Die();
+// Cleanup old bufs.
+static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) {
+  for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
+    JmpBuf *buf = &thr->jmp_bufs[i];
+    if (buf->sp <= sp) {
+      uptr sz = thr->jmp_bufs.Size();
+      thr->jmp_bufs[i] = thr->jmp_bufs[sz - 1];
+      thr->jmp_bufs.PopBack();
+      i--;
+    }
+  }
 }
 
-TSAN_INTERCEPTOR(void, siglongjmp, void *env, int val) {
-  SCOPED_TSAN_INTERCEPTOR(siglongjmp, env, val);
-  Printf("ThreadSanitizer: siglongjmp() is not supported\n");
-  Die();
+static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
+  if (thr->shadow_stack_pos == 0)  // called from libc guts during bootstrap
+    return;
+  // Cleanup old bufs.
+  JmpBufGarbageCollect(thr, sp);
+  // Remember the buf.
+  JmpBuf *buf = thr->jmp_bufs.PushBack();
+  buf->sp = sp;
+  buf->mangled_sp = mangled_sp;
+  buf->shadow_stack_pos = thr->shadow_stack_pos;
+}
+
+static void LongJmp(ThreadState *thr, uptr *env) {
+  uptr mangled_sp = env[6];
+  // Find the saved buf by mangled_sp.
+  for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
+    JmpBuf *buf = &thr->jmp_bufs[i];
+    if (buf->mangled_sp == mangled_sp) {
+      CHECK_GE(thr->shadow_stack_pos, buf->shadow_stack_pos);
+      // Unwind the stack.
+      while (thr->shadow_stack_pos > buf->shadow_stack_pos)
+        FuncExit(thr);
+      JmpBufGarbageCollect(thr, buf->sp - 1);  // do not collect buf->sp
+      return;
+    }
+  }
+  Printf("ThreadSanitizer: can't find longjmp buf\n");
+  CHECK(0);
+}
+
+extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) {
+  ScopedInRtl in_rtl;
+  SetJmp(cur_thread(), sp, mangled_sp);
+}
+
+// Not called.  Merely to satisfy TSAN_INTERCEPT().
+extern "C" int __interceptor_setjmp(void *env)
+    SANITIZER_INTERFACE_ATTRIBUTE;
+extern "C" int __interceptor_setjmp(void *env) {
+  CHECK(0);
+  return 0;
+}
+
+extern "C" int __interceptor__setjmp(void *env)
+    SANITIZER_INTERFACE_ATTRIBUTE;
+extern "C" int __interceptor__setjmp(void *env) {
+  CHECK(0);
+  return 0;
+}
+
+extern "C" int __interceptor_sigsetjmp(void *env)
+    SANITIZER_INTERFACE_ATTRIBUTE;
+extern "C" int __interceptor_sigsetjmp(void *env) {
+  CHECK(0);
+  return 0;
+}
+
+extern "C" int __interceptor___sigsetjmp(void *env)
+    SANITIZER_INTERFACE_ATTRIBUTE;
+extern "C" int __interceptor___sigsetjmp(void *env) {
+  CHECK(0);
+  return 0;
+}
+
+extern "C" int setjmp(void *env);
+extern "C" int _setjmp(void *env);
+extern "C" int sigsetjmp(void *env);
+extern "C" int __sigsetjmp(void *env);
+DEFINE_REAL(int, setjmp, void *env)
+DEFINE_REAL(int, _setjmp, void *env)
+DEFINE_REAL(int, sigsetjmp, void *env)
+DEFINE_REAL(int, __sigsetjmp, void *env)
+
+TSAN_INTERCEPTOR(void, longjmp, uptr *env, int val) {
+  {
+    SCOPED_TSAN_INTERCEPTOR(longjmp, env, val);
+  }
+  LongJmp(cur_thread(), env);
+  REAL(longjmp)(env, val);
+}
+
+TSAN_INTERCEPTOR(void, siglongjmp, uptr *env, int val) {
+  {
+    SCOPED_TSAN_INTERCEPTOR(siglongjmp, env, val);
+  }
+  LongJmp(cur_thread(), env);
+  REAL(siglongjmp)(env, val);
 }
 
 TSAN_INTERCEPTOR(void*, malloc, uptr size) {
@@ -360,7 +446,8 @@
   {
     SCOPED_INTERCEPTOR_RAW(calloc, size, n);
     p = user_alloc(thr, pc, n * size);
-    if (p) internal_memset(p, 0, n * size);
+    if (p)
+      internal_memset(p, 0, n * size);
   }
   invoke_malloc_hook(p, n * size);
   return p;
@@ -415,15 +502,26 @@
   invoke_malloc_hook(p, size);  \
   return p;
 
+void *operator new(__sanitizer::uptr size)
+    SANITIZER_INTERFACE_ATTRIBUTE;
 void *operator new(__sanitizer::uptr size) {
   OPERATOR_NEW_BODY(_Znwm);
 }
+
+void *operator new[](__sanitizer::uptr size)
+    SANITIZER_INTERFACE_ATTRIBUTE;
 void *operator new[](__sanitizer::uptr size) {
   OPERATOR_NEW_BODY(_Znam);
 }
+
+void *operator new(__sanitizer::uptr size, std::nothrow_t const&)
+    SANITIZER_INTERFACE_ATTRIBUTE;
 void *operator new(__sanitizer::uptr size, std::nothrow_t const&) {
   OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t);
 }
+
+void *operator new[](__sanitizer::uptr size, std::nothrow_t const&)
+    SANITIZER_INTERFACE_ATTRIBUTE;
 void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
   OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t);
 }
@@ -436,15 +534,26 @@
   SCOPED_INTERCEPTOR_RAW(mangled_name, ptr);  \
   user_free(thr, pc, ptr);
 
+void operator delete(void *ptr)
+    SANITIZER_INTERFACE_ATTRIBUTE;
 void operator delete(void *ptr) {
   OPERATOR_DELETE_BODY(_ZdlPv);
 }
+
+void operator delete[](void *ptr)
+    SANITIZER_INTERFACE_ATTRIBUTE;
 void operator delete[](void *ptr) {
   OPERATOR_DELETE_BODY(_ZdlPvRKSt9nothrow_t);
 }
+
+void operator delete(void *ptr, std::nothrow_t const&)
+    SANITIZER_INTERFACE_ATTRIBUTE;
 void operator delete(void *ptr, std::nothrow_t const&) {
   OPERATOR_DELETE_BODY(_ZdaPv);
 }
+
+void operator delete[](void *ptr, std::nothrow_t const&)
+    SANITIZER_INTERFACE_ATTRIBUTE;
 void operator delete[](void *ptr, std::nothrow_t const&) {
   OPERATOR_DELETE_BODY(_ZdaPvRKSt9nothrow_t);
 }
@@ -482,30 +591,6 @@
   return res;
 }
 
-TSAN_INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
-  SCOPED_TSAN_INTERCEPTOR(strcmp, s1, s2);
-  uptr len = 0;
-  for (; s1[len] && s2[len]; len++) {
-    if (s1[len] != s2[len])
-      break;
-  }
-  MemoryAccessRange(thr, pc, (uptr)s1, len + 1, false);
-  MemoryAccessRange(thr, pc, (uptr)s2, len + 1, false);
-  return s1[len] - s2[len];
-}
-
-TSAN_INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr n) {
-  SCOPED_TSAN_INTERCEPTOR(strncmp, s1, s2, n);
-  uptr len = 0;
-  for (; len < n && s1[len] && s2[len]; len++) {
-    if (s1[len] != s2[len])
-      break;
-  }
-  MemoryAccessRange(thr, pc, (uptr)s1, len < n ? len + 1 : n, false);
-  MemoryAccessRange(thr, pc, (uptr)s2, len < n ? len + 1 : n, false);
-  return len == n ? 0 : s1[len] - s2[len];
-}
-
 TSAN_INTERCEPTOR(void*, memchr, void *s, int c, uptr n) {
   SCOPED_TSAN_INTERCEPTOR(memchr, s, c, n);
   void *res = REAL(memchr)(s, c, n);
@@ -738,14 +823,14 @@
   }
   int detached = 0;
   pthread_attr_getdetachstate(attr, &detached);
-  uptr stacksize = 0;
-  pthread_attr_getstacksize(attr, &stacksize);
-  // We place the huge ThreadState object into TLS, account for that.
-  const uptr minstacksize = GetTlsSize() + 128*1024;
-  if (stacksize < minstacksize) {
-    DPrintf("ThreadSanitizer: stacksize %zu->%zu\n", stacksize, minstacksize);
-    pthread_attr_setstacksize(attr, minstacksize);
-  }
+
+#if defined(TSAN_DEBUG_OUTPUT)
+  int verbosity = (TSAN_DEBUG_OUTPUT);
+#else
+  int verbosity = 0;
+#endif
+  AdjustStackSizeLinux(attr, verbosity);
+
   ThreadParam p;
   p.callback = callback;
   p.param = param;
@@ -1313,22 +1398,6 @@
   return res;
 }
 
-TSAN_INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
-  SCOPED_TSAN_INTERCEPTOR(accept, fd, addr, addrlen);
-  int fd2 = REAL(accept)(fd, addr, addrlen);
-  if (fd >= 0 && fd2 >= 0)
-    FdSocketAccept(thr, pc, fd, fd2);
-  return fd2;
-}
-
-TSAN_INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
-  SCOPED_TSAN_INTERCEPTOR(accept4, fd, addr, addrlen, f);
-  int fd2 = REAL(accept4)(fd, addr, addrlen, f);
-  if (fd >= 0 && fd2 >= 0)
-    FdSocketAccept(thr, pc, fd, fd2);
-  return fd2;
-}
-
 TSAN_INTERCEPTOR(int, epoll_create, int size) {
   SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
   int fd = REAL(epoll_create)(size);
@@ -1387,40 +1456,6 @@
   return res;
 }
 
-TSAN_INTERCEPTOR(long_t, readv, int fd, void *vec, int cnt) {
-  SCOPED_TSAN_INTERCEPTOR(readv, fd, vec, cnt);
-  int res = REAL(readv)(fd, vec, cnt);
-  if (res >= 0 && fd >= 0) {
-    FdAcquire(thr, pc, fd);
-  }
-  return res;
-}
-
-TSAN_INTERCEPTOR(long_t, preadv64, int fd, void *vec, int cnt, u64 off) {
-  SCOPED_TSAN_INTERCEPTOR(preadv64, fd, vec, cnt, off);
-  int res = REAL(preadv64)(fd, vec, cnt, off);
-  if (res >= 0 && fd >= 0) {
-    FdAcquire(thr, pc, fd);
-  }
-  return res;
-}
-
-TSAN_INTERCEPTOR(long_t, writev, int fd, void *vec, int cnt) {
-  SCOPED_TSAN_INTERCEPTOR(writev, fd, vec, cnt);
-  if (fd >= 0)
-    FdRelease(thr, pc, fd);
-  int res = REAL(writev)(fd, vec, cnt);
-  return res;
-}
-
-TSAN_INTERCEPTOR(long_t, pwritev64, int fd, void *vec, int cnt, u64 off) {
-  SCOPED_TSAN_INTERCEPTOR(pwritev64, fd, vec, cnt, off);
-  if (fd >= 0)
-    FdRelease(thr, pc, fd);
-  int res = REAL(pwritev64)(fd, vec, cnt, off);
-  return res;
-}
-
 TSAN_INTERCEPTOR(long_t, send, int fd, void *buf, long_t len, int flags) {
   SCOPED_TSAN_INTERCEPTOR(send, fd, buf, len, flags);
   if (fd >= 0)
@@ -1446,15 +1481,6 @@
   return res;
 }
 
-TSAN_INTERCEPTOR(long_t, recvmsg, int fd, void *msg, int flags) {
-  SCOPED_TSAN_INTERCEPTOR(recvmsg, fd, msg, flags);
-  int res = REAL(recvmsg)(fd, msg, flags);
-  if (res >= 0 && fd >= 0) {
-    FdAcquire(thr, pc, fd);
-  }
-  return res;
-}
-
 TSAN_INTERCEPTOR(int, unlink, char *path) {
   SCOPED_TSAN_INTERCEPTOR(unlink, path);
   Release(thr, pc, File2addr(path));
@@ -1519,6 +1545,17 @@
   return REAL(fwrite)(p, size, nmemb, f);
 }
 
+TSAN_INTERCEPTOR(int, fflush, void *stream) {
+  SCOPED_TSAN_INTERCEPTOR(fflush, stream);
+  return REAL(fflush)(stream);
+}
+
+TSAN_INTERCEPTOR(void, abort, int fake) {
+  SCOPED_TSAN_INTERCEPTOR(abort, fake);
+  REAL(fflush)(0);
+  REAL(abort)(fake);
+}
+
 TSAN_INTERCEPTOR(int, puts, const char *s) {
   SCOPED_TSAN_INTERCEPTOR(puts, s);
   MemoryAccessRange(thr, pc, (uptr)s, internal_strlen(s), false);
@@ -1566,20 +1603,19 @@
   return res;
 }
 
-static void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
+void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
     my_siginfo_t *info, void *ctx) {
   ThreadState *thr = cur_thread();
   SignalContext *sctx = SigCtx(thr);
   // Don't mess with synchronous signals.
   if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
-      sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE ||
+      sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS ||
       // If we are sending signal to ourselves, we must process it now.
       (sctx && sig == sctx->int_signal_send) ||
       // If we are in blocking function, we can safely process it now
       // (but check if we are in a recursive interceptor,
       // i.e. pthread_join()->munmap()).
       (sctx && sctx->in_blocking_func == 1 && thr->in_rtl == 1)) {
-    CHECK(thr->in_rtl == 0 || thr->in_rtl == 1);
     int in_rtl = thr->in_rtl;
     thr->in_rtl = 0;
     CHECK_EQ(thr->in_signal_handler, false);
@@ -1648,6 +1684,11 @@
   return old.sa_handler;
 }
 
+TSAN_INTERCEPTOR(int, sigsuspend, const sigset_t *mask) {
+  SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask);
+  return REAL(sigsuspend)(mask);
+}
+
 TSAN_INTERCEPTOR(int, raise, int sig) {
   SCOPED_TSAN_INTERCEPTOR(raise, sig);
   SignalContext *sctx = SigCtx(thr);
@@ -1665,11 +1706,11 @@
   SignalContext *sctx = SigCtx(thr);
   CHECK_NE(sctx, 0);
   int prev = sctx->int_signal_send;
-  if (pid == GetPid()) {
+  if (pid == (int)internal_getpid()) {
     sctx->int_signal_send = sig;
   }
   int res = REAL(kill)(pid, sig);
-  if (pid == GetPid()) {
+  if (pid == (int)internal_getpid()) {
     CHECK_EQ(sctx->int_signal_send, sig);
     sctx->int_signal_send = prev;
   }
@@ -1704,7 +1745,8 @@
   static atomic_uint8_t printed;
   if (atomic_exchange(&printed, 1, memory_order_relaxed))
     return;
-  Printf("INFO: ThreadSanitizer ignores mlock/mlockall/munlock/munlockall\n");
+  if (flags()->verbosity > 0)
+    Printf("INFO: ThreadSanitizer ignores mlock/mlockall/munlock/munlockall\n");
 }
 
 TSAN_INTERCEPTOR(int, mlock, const void *addr, uptr len) {
@@ -1746,27 +1788,49 @@
   const uptr pc;
 };
 
-#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
-    MemoryAccessRange(((TsanInterceptorContext*)ctx)->thr,  \
-                      ((TsanInterceptorContext*)ctx)->pc,   \
-                      (uptr)ptr, size, true)
-#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size)       \
-    MemoryAccessRange(((TsanInterceptorContext*)ctx)->thr,  \
-                      ((TsanInterceptorContext*)ctx)->pc,   \
-                      (uptr)ptr, size, false)
-#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
-    SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__) \
-    TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \
-    ctx = (void*)&_ctx; \
-    (void)ctx;
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+// Causes interceptor recursion (getpwuid_r() calls fopen())
+#undef SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
+#undef SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+// Causes interceptor recursion (getaddrinfo() and fopen())
+#undef SANITIZER_INTERCEPT_GETADDRINFO
+#undef SANITIZER_INTERCEPT_GETNAMEINFO
+// Causes interceptor recursion (glob64() calls lstat64())
+#undef SANITIZER_INTERCEPT_GLOB
+
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
+  do {                                                \
+  } while (false)
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size)                    \
+  MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr,                 \
+                    ((TsanInterceptorContext *)ctx)->pc, (uptr)ptr, size, \
+                    true)
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size)                       \
+  MemoryAccessRange(((TsanInterceptorContext *) ctx)->thr,                  \
+                    ((TsanInterceptorContext *) ctx)->pc, (uptr) ptr, size, \
+                    false)
+#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...)      \
+  SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__);         \
+  TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \
+  ctx = (void *)&_ctx;                                \
+  (void) ctx;
 #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
-    FdAcquire(((TsanInterceptorContext*)ctx)->thr, pc, fd)
+  FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd)
 #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
-    FdRelease(((TsanInterceptorContext*)ctx)->thr, pc, fd)
+  FdRelease(((TsanInterceptorContext *) ctx)->thr, pc, fd)
+#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
+  FdSocketAccept(((TsanInterceptorContext *) ctx)->thr, pc, fd, newfd)
 #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
-    ThreadSetName(((TsanInterceptorContext*)ctx)->thr, name)
+  ThreadSetName(((TsanInterceptorContext *) ctx)->thr, name)
 #include "sanitizer_common/sanitizer_common_interceptors.inc"
 
+// FIXME: Implement these with MemoryAccessRange().
+#define COMMON_SYSCALL_PRE_READ_RANGE(p, s)
+#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
+#define COMMON_SYSCALL_POST_READ_RANGE(p, s)
+#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
+#include "sanitizer_common/sanitizer_common_syscalls.inc"
+
 namespace __tsan {
 
 void ProcessPendingSignals(ThreadState *thr) {
@@ -1800,6 +1864,7 @@
           uptr pc = signal->sigaction ?
               (uptr)sigactions[sig].sa_sigaction :
               (uptr)sigactions[sig].sa_handler;
+          pc += 1;  // return address is expected, OutputReport() will undo this
           stack.Init(&pc, 1);
           ThreadRegistryLock l(ctx->thread_registry);
           ScopedReport rep(ReportTypeErrnoInSignal);
@@ -1817,6 +1882,16 @@
   thr->in_signal_handler = false;
 }
 
+static void finalize(void *arg) {
+  ThreadState * thr = cur_thread();
+  uptr pc = 0;
+  atexit_ctx->exit(thr, pc);
+  int status = Finalize(cur_thread());
+  REAL(fflush)(0);
+  if (status)
+    _exit(status);
+}
+
 static void unreachable() {
   Printf("FATAL: ThreadSanitizer: unreachable called\n");
   Die();
@@ -1830,8 +1905,16 @@
   REAL(memcpy) = internal_memcpy;
   REAL(memcmp) = internal_memcmp;
 
+  // Instruct libc malloc to consume less memory.
+  mallopt(1, 0);  // M_MXFAST
+  mallopt(-3, 32*1024);  // M_MMAP_THRESHOLD
+
   SANITIZER_COMMON_INTERCEPTORS_INIT;
 
+  TSAN_INTERCEPT(setjmp);
+  TSAN_INTERCEPT(_setjmp);
+  TSAN_INTERCEPT(sigsetjmp);
+  TSAN_INTERCEPT(__sigsetjmp);
   TSAN_INTERCEPT(longjmp);
   TSAN_INTERCEPT(siglongjmp);
 
@@ -1852,7 +1935,6 @@
   TSAN_INTERCEPT(strlen);
   TSAN_INTERCEPT(memset);
   TSAN_INTERCEPT(memcpy);
-  TSAN_INTERCEPT(strcmp);
   TSAN_INTERCEPT(memchr);
   TSAN_INTERCEPT(memrchr);
   TSAN_INTERCEPT(memmove);
@@ -1860,7 +1942,6 @@
   TSAN_INTERCEPT(strchr);
   TSAN_INTERCEPT(strchrnul);
   TSAN_INTERCEPT(strrchr);
-  TSAN_INTERCEPT(strncmp);
   TSAN_INTERCEPT(strcpy);  // NOLINT
   TSAN_INTERCEPT(strncpy);
   TSAN_INTERCEPT(strstr);
@@ -1941,8 +2022,6 @@
   TSAN_INTERCEPT(connect);
   TSAN_INTERCEPT(bind);
   TSAN_INTERCEPT(listen);
-  TSAN_INTERCEPT(accept);
-  TSAN_INTERCEPT(accept4);
   TSAN_INTERCEPT(epoll_create);
   TSAN_INTERCEPT(epoll_create1);
   TSAN_INTERCEPT(close);
@@ -1951,14 +2030,9 @@
   TSAN_INTERCEPT(pipe);
   TSAN_INTERCEPT(pipe2);
 
-  TSAN_INTERCEPT(readv);
-  TSAN_INTERCEPT(preadv64);
-  TSAN_INTERCEPT(writev);
-  TSAN_INTERCEPT(pwritev64);
   TSAN_INTERCEPT(send);
   TSAN_INTERCEPT(sendmsg);
   TSAN_INTERCEPT(recv);
-  TSAN_INTERCEPT(recvmsg);
 
   TSAN_INTERCEPT(unlink);
   TSAN_INTERCEPT(fopen);
@@ -1966,6 +2040,8 @@
   TSAN_INTERCEPT(fclose);
   TSAN_INTERCEPT(fread);
   TSAN_INTERCEPT(fwrite);
+  TSAN_INTERCEPT(fflush);
+  TSAN_INTERCEPT(abort);
   TSAN_INTERCEPT(puts);
   TSAN_INTERCEPT(rmdir);
   TSAN_INTERCEPT(opendir);
@@ -1976,6 +2052,7 @@
 
   TSAN_INTERCEPT(sigaction);
   TSAN_INTERCEPT(signal);
+  TSAN_INTERCEPT(sigsuspend);
   TSAN_INTERCEPT(raise);
   TSAN_INTERCEPT(kill);
   TSAN_INTERCEPT(pthread_kill);
diff --git a/lib/tsan/rtl/tsan_interface.cc b/lib/tsan/rtl/tsan_interface.cc
index dd06bbe..b4cdb3a 100644
--- a/lib/tsan/rtl/tsan_interface.cc
+++ b/lib/tsan/rtl/tsan_interface.cc
@@ -14,11 +14,16 @@
 #include "tsan_interface.h"
 #include "tsan_interface_ann.h"
 #include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
 
 #define CALLERPC ((uptr)__builtin_return_address(0))
 
 using namespace __tsan;  // NOLINT
 
+typedef u16 uint16_t;
+typedef u32 uint32_t;
+typedef u64 uint64_t;
+
 void __tsan_init() {
   Initialize(cur_thread());
 }
@@ -33,6 +38,51 @@
   MemoryWrite(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
 }
 
+u16 __tsan_unaligned_read2(const uu16 *addr) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, false, false);
+  return *addr;
+}
+
+u32 __tsan_unaligned_read4(const uu32 *addr) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, false, false);
+  return *addr;
+}
+
+u64 __tsan_unaligned_read8(const uu64 *addr) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, false, false);
+  return *addr;
+}
+
+void __tsan_unaligned_write2(uu16 *addr, u16 v) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, true, false);
+  *addr = v;
+}
+
+void __tsan_unaligned_write4(uu32 *addr, u32 v) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, true, false);
+  *addr = v;
+}
+
+void __tsan_unaligned_write8(uu64 *addr, u64 v) {
+  UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, true, false);
+  *addr = v;
+}
+
+extern "C" {
+uint16_t __sanitizer_unaligned_load16(void *addr)
+    ALIAS("__tsan_unaligned_read2") SANITIZER_INTERFACE_ATTRIBUTE;
+uint32_t __sanitizer_unaligned_load32(void *addr)
+    ALIAS("__tsan_unaligned_read4") SANITIZER_INTERFACE_ATTRIBUTE;
+uint64_t __sanitizer_unaligned_load64(void *addr)
+    ALIAS("__tsan_unaligned_read8") SANITIZER_INTERFACE_ATTRIBUTE;
+void __sanitizer_unaligned_store16(void *addr, uint16_t v)
+    ALIAS("__tsan_unaligned_write2") SANITIZER_INTERFACE_ATTRIBUTE;
+void __sanitizer_unaligned_store32(void *addr, uint32_t v)
+    ALIAS("__tsan_unaligned_write4") SANITIZER_INTERFACE_ATTRIBUTE;
+void __sanitizer_unaligned_store64(void *addr, uint64_t v)
+    ALIAS("__tsan_unaligned_write8") SANITIZER_INTERFACE_ATTRIBUTE;
+}
+
 void __tsan_acquire(void *addr) {
   Acquire(cur_thread(), CALLERPC, (uptr)addr);
 }
diff --git a/lib/tsan/rtl/tsan_interface.h b/lib/tsan/rtl/tsan_interface.h
index 28eea14..eb75400 100644
--- a/lib/tsan/rtl/tsan_interface.h
+++ b/lib/tsan/rtl/tsan_interface.h
@@ -41,6 +41,14 @@
 void __tsan_write8(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
 void __tsan_write16(void *addr) SANITIZER_INTERFACE_ATTRIBUTE;
 
+u16 __tsan_unaligned_read2(const uu16 *addr) SANITIZER_INTERFACE_ATTRIBUTE;
+u32 __tsan_unaligned_read4(const uu32 *addr) SANITIZER_INTERFACE_ATTRIBUTE;
+u64 __tsan_unaligned_read8(const uu64 *addr) SANITIZER_INTERFACE_ATTRIBUTE;
+void __tsan_unaligned_write2(uu16 *addr, u16 v) SANITIZER_INTERFACE_ATTRIBUTE;
+void __tsan_unaligned_write4(uu32 *addr, u32 v) SANITIZER_INTERFACE_ATTRIBUTE;
+void __tsan_unaligned_write8(uu64 *addr, u64 v) SANITIZER_INTERFACE_ATTRIBUTE;
+
+void __tsan_vptr_read(void **vptr_p) SANITIZER_INTERFACE_ATTRIBUTE;
 void __tsan_vptr_update(void **vptr_p, void *new_val)
     SANITIZER_INTERFACE_ATTRIBUTE;
 
diff --git a/lib/tsan/rtl/tsan_interface_ann.cc b/lib/tsan/rtl/tsan_interface_ann.cc
index 51ebbf2..36a7b53 100644
--- a/lib/tsan/rtl/tsan_interface_ann.cc
+++ b/lib/tsan/rtl/tsan_interface_ann.cc
@@ -13,6 +13,7 @@
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 #include "tsan_interface_ann.h"
 #include "tsan_mutex.h"
 #include "tsan_report.h"
@@ -20,6 +21,7 @@
 #include "tsan_mman.h"
 #include "tsan_flags.h"
 #include "tsan_platform.h"
+#include "tsan_vector.h"
 
 #define CALLERPC ((uptr)__builtin_return_address(0))
 
@@ -67,6 +69,7 @@
   ExpectRace *next;
   ExpectRace *prev;
   int hitcount;
+  int addcount;
   uptr addr;
   uptr size;
   char *file;
@@ -91,16 +94,19 @@
     char *f, int l, uptr addr, uptr size, char *desc) {
   ExpectRace *race = list->next;
   for (; race != list; race = race->next) {
-    if (race->addr == addr && race->size == size)
+    if (race->addr == addr && race->size == size) {
+      race->addcount++;
       return;
+    }
   }
   race = (ExpectRace*)internal_alloc(MBlockExpectRace, sizeof(ExpectRace));
-  race->hitcount = 0;
   race->addr = addr;
   race->size = size;
   race->file = f;
   race->line = l;
   race->desc[0] = 0;
+  race->hitcount = 0;
+  race->addcount = 1;
   if (desc) {
     int i = 0;
     for (; i < kMaxDescLen - 1 && desc[i]; i++)
@@ -155,6 +161,68 @@
   return false;
 }
 
+static void CollectMatchedBenignRaces(Vector<ExpectRace> *matched,
+    int *unique_count, int *hit_count, int ExpectRace::*counter) {
+  ExpectRace *list = &dyn_ann_ctx->benign;
+  for (ExpectRace *race = list->next; race != list; race = race->next) {
+    (*unique_count)++;
+    if (race->*counter == 0)
+      continue;
+    (*hit_count) += race->*counter;
+    uptr i = 0;
+    for (; i < matched->Size(); i++) {
+      ExpectRace *race0 = &(*matched)[i];
+      if (race->line == race0->line
+          && internal_strcmp(race->file, race0->file) == 0
+          && internal_strcmp(race->desc, race0->desc) == 0) {
+        race0->*counter += race->*counter;
+        break;
+      }
+    }
+    if (i == matched->Size())
+      matched->PushBack(*race);
+  }
+}
+
+void PrintMatchedBenignRaces() {
+  Lock lock(&dyn_ann_ctx->mtx);
+  int unique_count = 0;
+  int hit_count = 0;
+  int add_count = 0;
+  Vector<ExpectRace> hit_matched(MBlockScopedBuf);
+  CollectMatchedBenignRaces(&hit_matched, &unique_count, &hit_count,
+      &ExpectRace::hitcount);
+  Vector<ExpectRace> add_matched(MBlockScopedBuf);
+  CollectMatchedBenignRaces(&add_matched, &unique_count, &add_count,
+      &ExpectRace::addcount);
+  if (hit_matched.Size()) {
+    Printf("ThreadSanitizer: Matched %d \"benign\" races (pid=%d):\n",
+        hit_count, (int)internal_getpid());
+    for (uptr i = 0; i < hit_matched.Size(); i++) {
+      Printf("%d %s:%d %s\n",
+          hit_matched[i].hitcount, hit_matched[i].file,
+          hit_matched[i].line, hit_matched[i].desc);
+    }
+  }
+  if (hit_matched.Size()) {
+    Printf("ThreadSanitizer: Annotated %d \"benign\" races, %d unique"
+           " (pid=%d):\n",
+        add_count, unique_count, (int)internal_getpid());
+    for (uptr i = 0; i < add_matched.Size(); i++) {
+      Printf("%d %s:%d %s\n",
+          add_matched[i].addcount, add_matched[i].file,
+          add_matched[i].line, add_matched[i].desc);
+    }
+  }
+}
+
+static void ReportMissedExpectedRace(ExpectRace *race) {
+  Printf("==================\n");
+  Printf("WARNING: ThreadSanitizer: missed expected data race\n");
+  Printf("  %s addr=%zx %s:%d\n",
+      race->desc, race->addr, race->file, race->line);
+  Printf("==================\n");
+}
 }  // namespace __tsan
 
 using namespace __tsan;  // NOLINT
@@ -162,12 +230,12 @@
 extern "C" {
 void INTERFACE_ATTRIBUTE AnnotateHappensBefore(char *f, int l, uptr addr) {
   SCOPED_ANNOTATION(AnnotateHappensBefore);
-  Release(cur_thread(), CALLERPC, addr);
+  Release(cur_thread(), pc, addr);
 }
 
 void INTERFACE_ATTRIBUTE AnnotateHappensAfter(char *f, int l, uptr addr) {
   SCOPED_ANNOTATION(AnnotateHappensAfter);
-  Acquire(cur_thread(), CALLERPC, addr);
+  Acquire(cur_thread(), pc, addr);
 }
 
 void INTERFACE_ATTRIBUTE AnnotateCondVarSignal(char *f, int l, uptr cv) {
@@ -237,14 +305,6 @@
   SCOPED_ANNOTATION(AnnotateNoOp);
 }
 
-static void ReportMissedExpectedRace(ExpectRace *race) {
-  Printf("==================\n");
-  Printf("WARNING: ThreadSanitizer: missed expected data race\n");
-  Printf("  %s addr=%zx %s:%d\n",
-      race->desc, race->addr, race->file, race->line);
-  Printf("==================\n");
-}
-
 void INTERFACE_ATTRIBUTE AnnotateFlushExpectedRaces(char *f, int l) {
   SCOPED_ANNOTATION(AnnotateFlushExpectedRaces);
   Lock lock(&dyn_ann_ctx->mtx);
@@ -357,6 +417,9 @@
   ThreadSetName(thr, name);
 }
 
+// We deliberately omit the implementation of WTFAnnotateHappensBefore() and
+// WTFAnnotateHappensAfter(). Those are being used by Webkit to annotate
+// atomic operations, which should be handled by ThreadSanitizer correctly.
 void INTERFACE_ATTRIBUTE WTFAnnotateHappensBefore(char *f, int l, uptr addr) {
   SCOPED_ANNOTATION(AnnotateHappensBefore);
 }
@@ -368,6 +431,7 @@
 void INTERFACE_ATTRIBUTE WTFAnnotateBenignRaceSized(
     char *f, int l, uptr mem, uptr sz, char *desc) {
   SCOPED_ANNOTATION(AnnotateBenignRaceSized);
+  BenignRaceImpl(f, l, mem, 1, desc);
 }
 
 int INTERFACE_ATTRIBUTE RunningOnValgrind() {
diff --git a/lib/tsan/rtl/tsan_interface_atomic.cc b/lib/tsan/rtl/tsan_interface_atomic.cc
index a2f7ff4..24ce428 100644
--- a/lib/tsan/rtl/tsan_interface_atomic.cc
+++ b/lib/tsan/rtl/tsan_interface_atomic.cc
@@ -30,34 +30,14 @@
 #define SCOPED_ATOMIC(func, ...) \
     const uptr callpc = (uptr)__builtin_return_address(0); \
     uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
-    pc = __sanitizer::StackTrace::GetPreviousInstructionPc(pc); \
     mo = ConvertOrder(mo); \
     mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
     ThreadState *const thr = cur_thread(); \
     AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
-    ScopedAtomic sa(thr, callpc, __FUNCTION__); \
+    ScopedAtomic sa(thr, callpc, a, mo, __FUNCTION__); \
     return Atomic##func(thr, pc, __VA_ARGS__); \
 /**/
 
-class ScopedAtomic {
- public:
-  ScopedAtomic(ThreadState *thr, uptr pc, const char *func)
-      : thr_(thr) {
-    CHECK_EQ(thr_->in_rtl, 0);
-    ProcessPendingSignals(thr);
-    FuncEntry(thr_, pc);
-    DPrintf("#%d: %s\n", thr_->tid, func);
-    thr_->in_rtl++;
-  }
-  ~ScopedAtomic() {
-    thr_->in_rtl--;
-    CHECK_EQ(thr_->in_rtl, 0);
-    FuncExit(thr_);
-  }
- private:
-  ThreadState *thr_;
-};
-
 // Some shortcuts.
 typedef __tsan_memory_order morder;
 typedef __tsan_atomic8 a8;
@@ -72,6 +52,26 @@
 const morder mo_acq_rel = __tsan_memory_order_acq_rel;
 const morder mo_seq_cst = __tsan_memory_order_seq_cst;
 
+class ScopedAtomic {
+ public:
+  ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a,
+               morder mo, const char *func)
+      : thr_(thr) {
+    CHECK_EQ(thr_->in_rtl, 0);
+    ProcessPendingSignals(thr);
+    FuncEntry(thr_, pc);
+    DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
+    thr_->in_rtl++;
+  }
+  ~ScopedAtomic() {
+    thr_->in_rtl--;
+    CHECK_EQ(thr_->in_rtl, 0);
+    FuncExit(thr_);
+  }
+ private:
+  ThreadState *thr_;
+};
+
 static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) {
   StatInc(thr, StatAtomic);
   StatInc(thr, t);
@@ -290,16 +290,20 @@
 template<typename T, T (*F)(volatile T *v, T op)>
 static T AtomicRMW(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) {
   MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
-  SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
-  thr->clock.set(thr->tid, thr->fast_state.epoch());
-  if (IsAcqRelOrder(mo))
-    thr->clock.acq_rel(&s->clock);
-  else if (IsReleaseOrder(mo))
-    thr->clock.release(&s->clock);
-  else if (IsAcquireOrder(mo))
-    thr->clock.acquire(&s->clock);
+  SyncVar *s = 0;
+  if (mo != mo_relaxed) {
+    s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
+    thr->clock.set(thr->tid, thr->fast_state.epoch());
+    if (IsAcqRelOrder(mo))
+      thr->clock.acq_rel(&s->clock);
+    else if (IsReleaseOrder(mo))
+      thr->clock.release(&s->clock);
+    else if (IsAcquireOrder(mo))
+      thr->clock.acquire(&s->clock);
+  }
   v = F(a, v);
-  s->mtx.Unlock();
+  if (s)
+    s->mtx.Unlock();
   return v;
 }
 
@@ -350,17 +354,21 @@
     volatile T *a, T *c, T v, morder mo, morder fmo) {
   (void)fmo;  // Unused because llvm does not pass it yet.
   MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
-  SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
-  thr->clock.set(thr->tid, thr->fast_state.epoch());
-  if (IsAcqRelOrder(mo))
-    thr->clock.acq_rel(&s->clock);
-  else if (IsReleaseOrder(mo))
-    thr->clock.release(&s->clock);
-  else if (IsAcquireOrder(mo))
-    thr->clock.acquire(&s->clock);
+  SyncVar *s = 0;
+  if (mo != mo_relaxed) {
+    s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
+    thr->clock.set(thr->tid, thr->fast_state.epoch());
+    if (IsAcqRelOrder(mo))
+      thr->clock.acq_rel(&s->clock);
+    else if (IsReleaseOrder(mo))
+      thr->clock.release(&s->clock);
+    else if (IsAcquireOrder(mo))
+      thr->clock.acquire(&s->clock);
+  }
   T cc = *c;
   T pr = func_cas(a, cc, v);
-  s->mtx.Unlock();
+  if (s)
+    s->mtx.Unlock();
   if (pr == cc)
     return true;
   *c = pr;
@@ -651,14 +659,14 @@
 }
 
 #if __TSAN_HAS_INT128
-a128 __tsan_atomic64_compare_exchange_val(volatile a128 *a, a128 c, a128 v,
+a128 __tsan_atomic128_compare_exchange_val(volatile a128 *a, a128 c, a128 v,
     morder mo, morder fmo) {
   SCOPED_ATOMIC(CAS, a, c, v, mo, fmo);
 }
 #endif
 
 void __tsan_atomic_thread_fence(morder mo) {
-  char* a;
+  char* a = 0;
   SCOPED_ATOMIC(Fence, mo);
 }
 
diff --git a/lib/tsan/rtl/tsan_interface_inl.h b/lib/tsan/rtl/tsan_interface_inl.h
index 29e2b21..0187e49 100644
--- a/lib/tsan/rtl/tsan_interface_inl.h
+++ b/lib/tsan/rtl/tsan_interface_inl.h
@@ -52,8 +52,20 @@
 
 void __tsan_vptr_update(void **vptr_p, void *new_val) {
   CHECK_EQ(sizeof(vptr_p), 8);
-  if (*vptr_p != new_val)
-    MemoryWrite(cur_thread(), CALLERPC, (uptr)vptr_p, kSizeLog8);
+  if (*vptr_p != new_val) {
+    ThreadState *thr = cur_thread();
+    thr->is_vptr_access = true;
+    MemoryWrite(thr, CALLERPC, (uptr)vptr_p, kSizeLog8);
+    thr->is_vptr_access = false;
+  }
+}
+
+void __tsan_vptr_read(void **vptr_p) {
+  CHECK_EQ(sizeof(vptr_p), 8);
+  ThreadState *thr = cur_thread();
+  thr->is_vptr_access = true;
+  MemoryRead(thr, CALLERPC, (uptr)vptr_p, kSizeLog8);
+  thr->is_vptr_access = false;
 }
 
 void __tsan_func_entry(void *pc) {
diff --git a/lib/tsan/rtl/tsan_interface_java.cc b/lib/tsan/rtl/tsan_interface_java.cc
index ee12001..358fd15 100644
--- a/lib/tsan/rtl/tsan_interface_java.cc
+++ b/lib/tsan/rtl/tsan_interface_java.cc
@@ -17,6 +17,7 @@
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 
 using namespace __tsan;  // NOLINT
 
@@ -157,7 +158,7 @@
 #define SCOPED_JAVA_FUNC(func) \
   ThreadState *thr = cur_thread(); \
   const uptr caller_pc = GET_CALLER_PC(); \
-  const uptr pc = (uptr)&func; \
+  const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
   (void)pc; \
   ScopedJavaFunc scoped(thr, caller_pc); \
 /**/
@@ -271,6 +272,7 @@
   CHECK_GE(addr, jctx->heap_begin);
   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
 
+  MutexCreate(thr, pc, addr, true, true, true);
   MutexLock(thr, pc, addr);
 }
 
@@ -291,6 +293,7 @@
   CHECK_GE(addr, jctx->heap_begin);
   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
 
+  MutexCreate(thr, pc, addr, true, true, true);
   MutexReadLock(thr, pc, addr);
 }
 
@@ -303,3 +306,25 @@
 
   MutexReadUnlock(thr, pc, addr);
 }
+
+void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
+  SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec);
+  DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec);
+  CHECK_NE(jctx, 0);
+  CHECK_GE(addr, jctx->heap_begin);
+  CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
+  CHECK_GT(rec, 0);
+
+  MutexCreate(thr, pc, addr, true, true, true);
+  MutexLock(thr, pc, addr, rec);
+}
+
+int __tsan_java_mutex_unlock_rec(jptr addr) {
+  SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec);
+  DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr);
+  CHECK_NE(jctx, 0);
+  CHECK_GE(addr, jctx->heap_begin);
+  CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
+
+  return MutexUnlock(thr, pc, addr, true);
+}
diff --git a/lib/tsan/rtl/tsan_interface_java.h b/lib/tsan/rtl/tsan_interface_java.h
index 241483a..9ac78e0 100644
--- a/lib/tsan/rtl/tsan_interface_java.h
+++ b/lib/tsan/rtl/tsan_interface_java.h
@@ -55,8 +55,7 @@
 
 // Mutex lock.
 // Addr is any unique address associated with the mutex.
-// Must not be called on recursive reentry.
-// Object.wait() is handled as a pair of unlock/lock.
+// Can be called on recursive reentry.
 void __tsan_java_mutex_lock(jptr addr) INTERFACE_ATTRIBUTE;
 // Mutex unlock.
 void __tsan_java_mutex_unlock(jptr addr) INTERFACE_ATTRIBUTE;
@@ -64,6 +63,16 @@
 void __tsan_java_mutex_read_lock(jptr addr) INTERFACE_ATTRIBUTE;
 // Mutex read unlock.
 void __tsan_java_mutex_read_unlock(jptr addr) INTERFACE_ATTRIBUTE;
+// Recursive mutex lock, intended for handling of Object.wait().
+// The 'rec' value must be obtained from the previous
+// __tsan_java_mutex_unlock_rec().
+void __tsan_java_mutex_lock_rec(jptr addr, int rec) INTERFACE_ATTRIBUTE;
+// Recursive mutex unlock, intended for handling of Object.wait().
+// The return value says how many times this thread called lock()
+// w/o a pairing unlock() (i.e. how many recursive levels it unlocked).
+// It must be passed back to __tsan_java_mutex_lock_rec() to restore
+// the same recursion level.
+int __tsan_java_mutex_unlock_rec(jptr addr) INTERFACE_ATTRIBUTE;
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc
index 35cf43d..07fd589 100644
--- a/lib/tsan/rtl/tsan_mman.cc
+++ b/lib/tsan/rtl/tsan_mman.cc
@@ -75,10 +75,12 @@
 
 void AllocatorThreadStart(ThreadState *thr) {
   allocator()->InitCache(&thr->alloc_cache);
+  internal_allocator()->InitCache(&thr->internal_alloc_cache);
 }
 
 void AllocatorThreadFinish(ThreadState *thr) {
   allocator()->DestroyCache(&thr->alloc_cache);
+  internal_allocator()->DestroyCache(&thr->internal_alloc_cache);
 }
 
 void AllocatorPrintStats() {
@@ -101,6 +103,8 @@
 
 void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
   CHECK_GT(thr->in_rtl, 0);
+  if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
+    return 0;
   void *p = allocator()->Allocate(&thr->alloc_cache, sz, align);
   if (p == 0)
     return 0;
@@ -147,6 +151,7 @@
       return 0;
     if (p) {
       MBlock *b = user_mblock(thr, p);
+      CHECK_NE(b, 0);
       internal_memcpy(p2, p, min(b->Size(), sz));
     }
   }
@@ -164,10 +169,11 @@
 }
 
 MBlock *user_mblock(ThreadState *thr, void *p) {
-  CHECK_NE(p, (void*)0);
+  CHECK_NE(p, 0);
   Allocator *a = allocator();
   void *b = a->GetBlockBegin(p);
-  CHECK_NE(b, 0);
+  if (b == 0)
+    return 0;
   return (MBlock*)a->GetMetaData(b);
 }
 
@@ -190,11 +196,12 @@
 void *internal_alloc(MBlockType typ, uptr sz) {
   ThreadState *thr = cur_thread();
   CHECK_GT(thr->in_rtl, 0);
+  CHECK_LE(sz, InternalSizeClassMap::kMaxSize);
   if (thr->nomalloc) {
     thr->nomalloc = 0;  // CHECK calls internal_malloc().
     CHECK(0);
   }
-  return InternalAlloc(sz);
+  return InternalAlloc(sz, &thr->internal_alloc_cache);
 }
 
 void internal_free(void *p) {
@@ -204,7 +211,7 @@
     thr->nomalloc = 0;  // CHECK calls internal_malloc().
     CHECK(0);
   }
-  InternalFree(p);
+  InternalFree(p, &thr->internal_alloc_cache);
 }
 
 }  // namespace __tsan
@@ -257,5 +264,6 @@
 void __tsan_on_thread_idle() {
   ThreadState *thr = cur_thread();
   allocator()->SwallowCache(&thr->alloc_cache);
+  internal_allocator()->SwallowCache(&thr->internal_alloc_cache);
 }
 }  // extern "C"
diff --git a/lib/tsan/rtl/tsan_mman.h b/lib/tsan/rtl/tsan_mman.h
index 4a9240f..19d5554 100644
--- a/lib/tsan/rtl/tsan_mman.h
+++ b/lib/tsan/rtl/tsan_mman.h
@@ -63,6 +63,7 @@
   MBlockExpectRace,
   MBlockSignal,
   MBlockFD,
+  MBlockJmpBuf,
 
   // This must be the last.
   MBlockTypeCount
diff --git a/lib/tsan/rtl/tsan_mutex.cc b/lib/tsan/rtl/tsan_mutex.cc
index 335ca22..a92fd90 100644
--- a/lib/tsan/rtl/tsan_mutex.cc
+++ b/lib/tsan/rtl/tsan_mutex.cc
@@ -31,8 +31,8 @@
   /*0  MutexTypeInvalid*/     {},
   /*1  MutexTypeTrace*/       {MutexTypeLeaf},
   /*2  MutexTypeThreads*/     {MutexTypeReport},
-  /*3  MutexTypeReport*/      {MutexTypeSyncTab, MutexTypeMBlock,
-                               MutexTypeJavaMBlock},
+  /*3  MutexTypeReport*/      {MutexTypeSyncTab, MutexTypeSyncVar,
+                               MutexTypeMBlock, MutexTypeJavaMBlock},
   /*4  MutexTypeSyncVar*/     {},
   /*5  MutexTypeSyncTab*/     {MutexTypeSyncVar},
   /*6  MutexTypeSlab*/        {MutexTypeLeaf},
diff --git a/lib/tsan/rtl/tsan_mutexset.h b/lib/tsan/rtl/tsan_mutexset.h
index 09223ff..eebfd4d 100644
--- a/lib/tsan/rtl/tsan_mutexset.h
+++ b/lib/tsan/rtl/tsan_mutexset.h
@@ -22,7 +22,7 @@
  public:
   // Holds limited number of mutexes.
   // The oldest mutexes are discarded on overflow.
-  static const uptr kMaxSize = 64;
+  static const uptr kMaxSize = 16;
   struct Desc {
     u64 id;
     u64 epoch;
diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h
index d6b331a..666b4d0 100644
--- a/lib/tsan/rtl/tsan_platform.h
+++ b/lib/tsan/rtl/tsan_platform.h
@@ -37,9 +37,9 @@
 Go linux and darwin memory layout:
 0000 0000 0000 - 0000 1000 0000: executable
 0000 1000 0000 - 00f8 0000 0000: -
-00f8 0000 0000 - 0118 0000 0000: heap
-0118 0000 0000 - 1000 0000 0000: -
-1000 0000 0000 - 1460 0000 0000: shadow
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 1000 0000 0000: -
+1000 0000 0000 - 1380 0000 0000: shadow
 1460 0000 0000 - 6000 0000 0000: -
 6000 0000 0000 - 6200 0000 0000: traces
 6200 0000 0000 - 7fff ffff ffff: -
@@ -47,8 +47,8 @@
 Go windows memory layout:
 0000 0000 0000 - 0000 1000 0000: executable
 0000 1000 0000 - 00f8 0000 0000: -
-00f8 0000 0000 - 0118 0000 0000: heap
-0118 0000 0000 - 0100 0000 0000: -
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 0100 0000 0000: -
 0100 0000 0000 - 0560 0000 0000: shadow
 0560 0000 0000 - 0760 0000 0000: traces
 0760 0000 0000 - 07ff ffff ffff: -
@@ -65,11 +65,11 @@
 
 #if defined(TSAN_GO)
 static const uptr kLinuxAppMemBeg = 0x000000000000ULL;
-static const uptr kLinuxAppMemEnd = 0x00fcffffffffULL;
-# if defined(_WIN32)
+static const uptr kLinuxAppMemEnd = 0x04dfffffffffULL;
+# if SANITIZER_WINDOWS
 static const uptr kLinuxShadowMsk = 0x010000000000ULL;
 # else
-static const uptr kLinuxShadowMsk = 0x100000000000ULL;
+static const uptr kLinuxShadowMsk = 0x200000000000ULL;
 # endif
 // TSAN_COMPAT_SHADOW is intended for COMPAT virtual memory layout,
 // when memory addresses are of the 0x2axxxxxxxxxx form.
@@ -84,7 +84,7 @@
 
 static const uptr kLinuxAppMemMsk = 0x7c0000000000ULL;
 
-#if defined(_WIN32)
+#if SANITIZER_WINDOWS
 const uptr kTraceMemBegin = 0x056000000000ULL;
 #else
 const uptr kTraceMemBegin = 0x600000000000ULL;
@@ -137,8 +137,14 @@
 
 const char *InitializePlatform();
 void FinalizePlatform();
-uptr ALWAYS_INLINE INLINE GetThreadTrace(int tid) {
-  uptr p = kTraceMemBegin + (uptr)tid * kTraceSize * sizeof(Event);
+uptr ALWAYS_INLINE GetThreadTrace(int tid) {
+  uptr p = kTraceMemBegin + (uptr)(tid * 2) * kTraceSize * sizeof(Event);
+  DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
+  return p;
+}
+
+uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
+  uptr p = kTraceMemBegin + (uptr)(tid * 2 + 1) * kTraceSize * sizeof(Event);
   DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
   return p;
 }
@@ -148,8 +154,6 @@
 // Says whether the addr relates to a global var.
 // Guesses with high probability, may yield both false positives and negatives.
 bool IsGlobalVar(uptr addr);
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size);
 int ExtractResolvFDs(void *state, int *fds, int nfd);
 
 }  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc
index 02a6648..a0d71e8 100644
--- a/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/lib/tsan/rtl/tsan_platform_linux.cc
@@ -12,7 +12,9 @@
 // Linux-specific code.
 //===----------------------------------------------------------------------===//
 
-#ifdef __linux__
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_LINUX
 
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
@@ -21,7 +23,6 @@
 #include "tsan_rtl.h"
 #include "tsan_flags.h"
 
-#include <asm/prctl.h>
 #include <fcntl.h>
 #include <pthread.h>
 #include <signal.h>
@@ -44,11 +45,12 @@
 #include <resolv.h>
 #include <malloc.h>
 
-extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
 extern "C" struct mallinfo __libc_mallinfo();
 
 namespace __tsan {
 
+const uptr kPageSize = 4096;
+
 #ifndef TSAN_GO
 ScopedInRtl::ScopedInRtl()
     : thr_(cur_thread()) {
@@ -160,6 +162,63 @@
 #endif
 
 #ifndef TSAN_GO
+// Mark shadow for .rodata sections with the special kShadowRodata marker.
+// Accesses to .rodata can't race, so this saves time, memory and trace space.
+static void MapRodata() {
+  // First create temp file.
+  const char *tmpdir = GetEnv("TMPDIR");
+  if (tmpdir == 0)
+    tmpdir = GetEnv("TEST_TMPDIR");
+#ifdef P_tmpdir
+  if (tmpdir == 0)
+    tmpdir = P_tmpdir;
+#endif
+  if (tmpdir == 0)
+    return;
+  char filename[256];
+  internal_snprintf(filename, sizeof(filename), "%s/tsan.rodata.%d",
+                    tmpdir, (int)internal_getpid());
+  uptr openrv = internal_open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+  if (internal_iserror(openrv))
+    return;
+  fd_t fd = openrv;
+  // Fill the file with kShadowRodata.
+  const uptr kMarkerSize = 512 * 1024 / sizeof(u64);
+  InternalScopedBuffer<u64> marker(kMarkerSize);
+  for (u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++)
+    *p = kShadowRodata;
+  internal_write(fd, marker.data(), marker.size());
+  // Map the file into memory.
+  uptr page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE,
+                            MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
+  if (internal_iserror(page)) {
+    internal_close(fd);
+    internal_unlink(filename);
+    return;
+  }
+  // Map the file into shadow of .rodata sections.
+  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+  uptr start, end, offset, prot;
+  char name[128];
+  while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), &prot)) {
+    if (name[0] != 0 && name[0] != '['
+        && (prot & MemoryMappingLayout::kProtectionRead)
+        && (prot & MemoryMappingLayout::kProtectionExecute)
+        && !(prot & MemoryMappingLayout::kProtectionWrite)
+        && IsAppMem(start)) {
+      // Assume it's .rodata
+      char *shadow_start = (char*)MemToShadow(start);
+      char *shadow_end = (char*)MemToShadow(end);
+      for (char *p = shadow_start; p < shadow_end; p += marker.size()) {
+        internal_mmap(p, Min<uptr>(marker.size(), shadow_end - p),
+                      PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
+      }
+    }
+  }
+  internal_close(fd);
+  internal_unlink(filename);
+}
+
 void InitializeShadowMemory() {
   uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
     kLinuxShadowEnd - kLinuxShadowBeg);
@@ -186,6 +245,8 @@
       kLinuxAppMemBeg, kLinuxAppMemEnd,
       (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
   DPrintf("stack        %zx\n", (uptr)&shadow);
+
+  MapRodata();
 }
 #endif
 
@@ -195,7 +256,7 @@
 #ifndef TSAN_GO
 static void CheckPIE() {
   // Ensure that the binary is indeed compiled with -pie.
-  MemoryMappingLayout proc_maps;
+  MemoryMappingLayout proc_maps(true);
   uptr start, end;
   if (proc_maps.Next(&start, &end,
                      /*offset*/0, /*filename*/0, /*filename_size*/0,
@@ -212,7 +273,7 @@
 }
 
 static void InitDataSeg() {
-  MemoryMappingLayout proc_maps;
+  MemoryMappingLayout proc_maps(true);
   uptr start, end, offset;
   char name[128];
   bool prev_is_data = false;
@@ -296,39 +357,6 @@
   return GetEnv(kTsanOptionsEnv);
 }
 
-void FinalizePlatform() {
-  fflush(0);
-}
-
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size) {
-#ifndef TSAN_GO
-  arch_prctl(ARCH_GET_FS, tls_addr);
-  *tls_size = GetTlsSize();
-  *tls_addr -= *tls_size;
-
-  uptr stack_top, stack_bottom;
-  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
-  *stk_addr = stack_bottom;
-  *stk_size = stack_top - stack_bottom;
-
-  if (!main) {
-    // If stack and tls intersect, make them non-intersecting.
-    if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
-      CHECK_GT(*tls_addr + *tls_size, *stk_addr);
-      CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
-      *stk_size -= *tls_size;
-      *tls_addr = *stk_addr + *stk_size;
-    }
-  }
-#else
-  *stk_addr = 0;
-  *stk_size = 0;
-  *tls_addr = 0;
-  *tls_size = 0;
-#endif
-}
-
 bool IsGlobalVar(uptr addr) {
   return g_data_start && addr >= g_data_start && addr < g_data_end;
 }
@@ -348,4 +376,4 @@
 
 }  // namespace __tsan
 
-#endif  // #ifdef __linux__
+#endif  // SANITIZER_LINUX
diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc
index d5caea3..99d4533 100644
--- a/lib/tsan/rtl/tsan_platform_mac.cc
+++ b/lib/tsan/rtl/tsan_platform_mac.cc
@@ -12,7 +12,8 @@
 // Mac-specific code.
 //===----------------------------------------------------------------------===//
 
-#ifdef __APPLE__
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
 
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
@@ -89,14 +90,6 @@
   fflush(0);
 }
 
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size) {
-  *stk_addr = 0;
-  *stk_size = 0;
-  *tls_addr = 0;
-  *tls_size = 0;
-}
-
 }  // namespace __tsan
 
-#endif  // #ifdef __APPLE__
+#endif  // SANITIZER_MAC
diff --git a/lib/tsan/rtl/tsan_platform_windows.cc b/lib/tsan/rtl/tsan_platform_windows.cc
index 9bd3958..711db72 100644
--- a/lib/tsan/rtl/tsan_platform_windows.cc
+++ b/lib/tsan/rtl/tsan_platform_windows.cc
@@ -12,7 +12,8 @@
 // Windows-specific code.
 //===----------------------------------------------------------------------===//
 
-#ifdef _WIN32
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS
 
 #include "tsan_platform.h"
 
@@ -41,14 +42,6 @@
   fflush(0);
 }
 
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size) {
-  *stk_addr = 0;
-  *stk_size = 0;
-  *tls_addr = 0;
-  *tls_size = 0;
-}
-
 }  // namespace __tsan
 
-#endif  // #ifdef _WIN32
+#endif  // SANITIZER_WINDOWS
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index b394c40..c95c5c8 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -22,7 +22,8 @@
     , locs(MBlockReportLoc)
     , mutexes(MBlockReportMutex)
     , threads(MBlockReportThread)
-    , sleep() {
+    , sleep()
+    , count() {
 }
 
 ReportMop::ReportMop()
@@ -46,6 +47,8 @@
 static const char *ReportTypeString(ReportType typ) {
   if (typ == ReportTypeRace)
     return "data race";
+  if (typ == ReportTypeVptrRace)
+    return "data race on vptr (ctor/dtor vs virtual call)";
   if (typ == ReportTypeUseAfterFree)
     return "heap-use-after-free";
   if (typ == ReportTypeThreadLeak)
@@ -176,7 +179,8 @@
 void PrintReport(const ReportDesc *rep) {
   Printf("==================\n");
   const char *rep_typ_str = ReportTypeString(rep->typ);
-  Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, GetPid());
+  Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str,
+         (int)internal_getpid());
 
   for (uptr i = 0; i < rep->stacks.Size(); i++) {
     if (i)
@@ -199,6 +203,9 @@
   for (uptr i = 0; i < rep->threads.Size(); i++)
     PrintThread(rep->threads[i]);
 
+  if (rep->typ == ReportTypeThreadLeak && rep->count > 1)
+    Printf("  And %d more similar thread leaks.\n\n", rep->count - 1);
+
   if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep)))
     ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
 
diff --git a/lib/tsan/rtl/tsan_report.h b/lib/tsan/rtl/tsan_report.h
index b2b7b53..b2ce0dd 100644
--- a/lib/tsan/rtl/tsan_report.h
+++ b/lib/tsan/rtl/tsan_report.h
@@ -20,6 +20,7 @@
 
 enum ReportType {
   ReportTypeRace,
+  ReportTypeVptrRace,
   ReportTypeUseAfterFree,
   ReportTypeThreadLeak,
   ReportTypeMutexDestroyLocked,
@@ -101,6 +102,7 @@
   Vector<ReportMutex*> mutexes;
   Vector<ReportThread*> threads;
   ReportStack *sleep;
+  int count;
 
   ReportDesc();
   ~ReportDesc();
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index 37f65eb..820a6ee 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -23,6 +23,7 @@
 #include "tsan_rtl.h"
 #include "tsan_mman.h"
 #include "tsan_suppressions.h"
+#include "tsan_symbolize.h"
 
 volatile int __tsan_resumed = 0;
 
@@ -52,7 +53,9 @@
 static ThreadContextBase *CreateThreadContext(u32 tid) {
   // Map thread trace when context is created.
   MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event));
-  void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
+  MapThreadTrace(GetThreadTraceHeader(tid), sizeof(Trace));
+  new(ThreadTrace(tid)) Trace();
+  void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
   return new(mem) ThreadContext(tid);
 }
 
@@ -71,7 +74,7 @@
       CreateThreadContext, kMaxTid, kThreadQuarantineSize))
   , racy_stacks(MBlockRacyStacks)
   , racy_addresses(MBlockRacyAddresses)
-  , fired_suppressions(MBlockRacyAddresses) {
+  , fired_suppressions(8) {
 }
 
 // The objects are allocated in TLS, so one may rely on zero-initialization.
@@ -81,10 +84,12 @@
   : fast_state(tid, epoch)
   // Do not touch these, rely on zero initialization,
   // they may be accessed before the ctor.
-  // , fast_ignore_reads()
-  // , fast_ignore_writes()
+  // , ignore_reads_and_writes()
   // , in_rtl()
   , shadow_stack_pos(&shadow_stack[0])
+#ifndef TSAN_GO
+  , jmp_bufs(MBlockJmpBuf)
+#endif
   , tid(tid)
   , unique_id(unique_id)
   , stk_addr(stk_addr)
@@ -93,36 +98,68 @@
   , tls_size(tls_size) {
 }
 
-static void MemoryProfileThread(void *arg) {
-  ScopedInRtl in_rtl;
-  fd_t fd = (fd_t)(uptr)arg;
-  Context *ctx = CTX();
-  for (int i = 0; ; i++) {
-    InternalScopedBuffer<char> buf(4096);
-    uptr n_threads;
-    uptr n_running_threads;
-    ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads);
-    internal_snprintf(buf.data(), buf.size(), "%d: nthr=%d nlive=%d\n",
-        i, n_threads, n_running_threads);
-    internal_write(fd, buf.data(), internal_strlen(buf.data()));
-    WriteMemoryProfile(buf.data(), buf.size());
-    internal_write(fd, buf.data(), internal_strlen(buf.data()));
-    SleepForSeconds(1);
-  }
+static void MemoryProfiler(Context *ctx, fd_t fd, int i) {
+  uptr n_threads;
+  uptr n_running_threads;
+  ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads);
+  InternalScopedBuffer<char> buf(4096);
+  internal_snprintf(buf.data(), buf.size(), "%d: nthr=%d nlive=%d\n",
+      i, n_threads, n_running_threads);
+  internal_write(fd, buf.data(), internal_strlen(buf.data()));
+  WriteMemoryProfile(buf.data(), buf.size());
+  internal_write(fd, buf.data(), internal_strlen(buf.data()));
 }
 
-static void InitializeMemoryProfile() {
-  if (flags()->profile_memory == 0 || flags()->profile_memory[0] == 0)
-    return;
-  InternalScopedBuffer<char> filename(4096);
-  internal_snprintf(filename.data(), filename.size(), "%s.%d",
-      flags()->profile_memory, GetPid());
-  fd_t fd = OpenFile(filename.data(), true);
-  if (fd == kInvalidFd) {
-    Printf("Failed to open memory profile file '%s'\n", &filename[0]);
-    Die();
+static void BackgroundThread(void *arg) {
+  ScopedInRtl in_rtl;
+  Context *ctx = CTX();
+  const u64 kMs2Ns = 1000 * 1000;
+
+  fd_t mprof_fd = kInvalidFd;
+  if (flags()->profile_memory && flags()->profile_memory[0]) {
+    InternalScopedBuffer<char> filename(4096);
+    internal_snprintf(filename.data(), filename.size(), "%s.%d",
+        flags()->profile_memory, (int)internal_getpid());
+    uptr openrv = OpenFile(filename.data(), true);
+    if (internal_iserror(openrv)) {
+      Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
+          &filename[0]);
+    } else {
+      mprof_fd = openrv;
+    }
   }
-  internal_start_thread(&MemoryProfileThread, (void*)(uptr)fd);
+
+  u64 last_flush = NanoTime();
+  for (int i = 0; ; i++) {
+    SleepForSeconds(1);
+    u64 now = NanoTime();
+
+    // Flush memory if requested.
+    if (flags()->flush_memory_ms) {
+      if (last_flush + flags()->flush_memory_ms * kMs2Ns < now) {
+        FlushShadowMemory();
+        last_flush = NanoTime();
+      }
+    }
+
+    // Write memory profile if requested.
+    if (mprof_fd != kInvalidFd)
+      MemoryProfiler(ctx, mprof_fd, i);
+
+#ifndef TSAN_GO
+    // Flush symbolizer cache if requested.
+    if (flags()->flush_symbolizer_ms > 0) {
+      u64 last = atomic_load(&ctx->last_symbolize_time_ns,
+                             memory_order_relaxed);
+      if (last != 0 && last + flags()->flush_symbolizer_ms * kMs2Ns < now) {
+        Lock l(&ctx->report_mtx);
+        SpinMutexLock l2(&CommonSanitizerReportMutex);
+        SymbolizeFlush();
+        atomic_store(&ctx->last_symbolize_time_ns, 0, memory_order_relaxed);
+      }
+    }
+#endif
+  }
 }
 
 void DontNeedShadowFor(uptr addr, uptr size) {
@@ -131,22 +168,6 @@
   FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
 }
 
-static void MemoryFlushThread(void *arg) {
-  ScopedInRtl in_rtl;
-  for (int i = 0; ; i++) {
-    SleepForMillis(flags()->flush_memory_ms);
-    FlushShadowMemory();
-  }
-}
-
-static void InitializeMemoryFlush() {
-  if (flags()->flush_memory_ms == 0)
-    return;
-  if (flags()->flush_memory_ms < 100)
-    flags()->flush_memory_ms = 100;
-  internal_start_thread(&MemoryFlushThread, 0);
-}
-
 void MapShadow(uptr addr, uptr size) {
   MmapFixedNoReserve(MemToShadow(addr), size * kShadowMultiplier);
 }
@@ -203,24 +224,23 @@
     }
   }
 #endif
-  InitializeMemoryProfile();
-  InitializeMemoryFlush();
+  internal_start_thread(&BackgroundThread, 0);
 
   if (ctx->flags.verbosity)
     Printf("***** Running under ThreadSanitizer v2 (pid %d) *****\n",
-               GetPid());
+           (int)internal_getpid());
 
   // Initialize thread 0.
   int tid = ThreadCreate(thr, 0, 0, true);
   CHECK_EQ(tid, 0);
-  ThreadStart(thr, tid, GetPid());
+  ThreadStart(thr, tid, internal_getpid());
   CHECK_EQ(thr->in_rtl, 1);
   ctx->initialized = true;
 
   if (flags()->stop_on_start) {
     Printf("ThreadSanitizer is suspended at startup (pid %d)."
            " Call __tsan_resume().\n",
-           GetPid());
+           (int)internal_getpid());
     while (__tsan_resumed == 0) {}
   }
 }
@@ -235,6 +255,8 @@
 
   // Wait for pending reports.
   ctx->report_mtx.Lock();
+  CommonSanitizerReportMutex.Lock();
+  CommonSanitizerReportMutex.Unlock();
   ctx->report_mtx.Unlock();
 
 #ifndef TSAN_GO
@@ -259,6 +281,13 @@
         ctx->nmissed_expected);
   }
 
+  if (flags()->print_suppressions)
+    PrintMatchedSuppressions();
+#ifndef TSAN_GO
+  if (flags()->print_benign)
+    PrintMatchedBenignRaces();
+#endif
+
   failed = OnFinalize(failed);
 
   StatAggregate(ctx->stat, thr->stat);
@@ -285,15 +314,20 @@
 void TraceSwitch(ThreadState *thr) {
   thr->nomalloc++;
   ScopedInRtl in_rtl;
-  Lock l(&thr->trace.mtx);
+  Trace *thr_trace = ThreadTrace(thr->tid);
+  Lock l(&thr_trace->mtx);
   unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % TraceParts();
-  TraceHeader *hdr = &thr->trace.headers[trace];
+  TraceHeader *hdr = &thr_trace->headers[trace];
   hdr->epoch0 = thr->fast_state.epoch();
   hdr->stack0.ObtainCurrent(thr, 0);
   hdr->mset0 = thr->mset;
   thr->nomalloc--;
 }
 
+Trace *ThreadTrace(int tid) {
+  return (Trace*)GetThreadTraceHeader(tid);
+}
+
 uptr TraceTopPC(ThreadState *thr) {
   Event *events = (Event*)GetThreadTrace(thr->tid);
   uptr pc = events[thr->fast_state.GetTracePos()];
@@ -319,18 +353,18 @@
 #endif
 
 ALWAYS_INLINE
-static Shadow LoadShadow(u64 *p) {
+Shadow LoadShadow(u64 *p) {
   u64 raw = atomic_load((atomic_uint64_t*)p, memory_order_relaxed);
   return Shadow(raw);
 }
 
 ALWAYS_INLINE
-static void StoreShadow(u64 *sp, u64 s) {
+void StoreShadow(u64 *sp, u64 s) {
   atomic_store((atomic_uint64_t*)sp, s, memory_order_relaxed);
 }
 
 ALWAYS_INLINE
-static void StoreIfNotYetStored(u64 *sp, u64 *s) {
+void StoreIfNotYetStored(u64 *sp, u64 *s) {
   StoreShadow(sp, *s);
   *s = 0;
 }
@@ -355,7 +389,7 @@
   return thr->clock.get(old.TidWithIgnore()) >= old.epoch();
 }
 
-ALWAYS_INLINE
+ALWAYS_INLINE USED
 void MemoryAccessImpl(ThreadState *thr, uptr addr,
     int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
     u64 *shadow_mem, Shadow cur) {
@@ -429,7 +463,28 @@
   return;
 }
 
-ALWAYS_INLINE
+void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr,
+    int size, bool kAccessIsWrite, bool kIsAtomic) {
+  while (size) {
+    int size1 = 1;
+    int kAccessSizeLog = kSizeLog1;
+    if (size >= 8 && (addr & ~7) == ((addr + 8) & ~7)) {
+      size1 = 8;
+      kAccessSizeLog = kSizeLog8;
+    } else if (size >= 4 && (addr & ~7) == ((addr + 4) & ~7)) {
+      size1 = 4;
+      kAccessSizeLog = kSizeLog4;
+    } else if (size >= 2 && (addr & ~7) == ((addr + 2) & ~7)) {
+      size1 = 2;
+      kAccessSizeLog = kSizeLog2;
+    }
+    MemoryAccess(thr, pc, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic);
+    addr += size1;
+    size -= size1;
+  }
+}
+
+ALWAYS_INLINE USED
 void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
     int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) {
   u64 *shadow_mem = (u64*)MemToShadow(addr);
@@ -450,6 +505,16 @@
   }
 #endif
 
+  if (*shadow_mem == kShadowRodata) {
+    // Access to .rodata section, no races here.
+    // Measurements show that it can be 10-20% of all memory accesses.
+    StatInc(thr, StatMop);
+    StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
+    StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
+    StatInc(thr, StatMopRodata);
+    return;
+  }
+
   FastState fast_state = thr->fast_state;
   if (fast_state.GetIgnoreBit())
     return;
@@ -491,7 +556,9 @@
   // Don't want to touch lots of shadow memory.
   // If a program maps 10MB stack, there is no need reset the whole range.
   size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1);
-  if (size < 64*1024) {
+  // UnmapOrDie/MmapFixedNoReserve does not work on Windows,
+  // so we do it only for C/C++.
+  if (kGoMode || size < 64*1024) {
     u64 *p = (u64*)MemToShadow(addr);
     CHECK(IsShadowMem((uptr)p));
     CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1)));
@@ -541,6 +608,8 @@
   thr->is_freeing = true;
   MemoryAccessRange(thr, pc, addr, size, true);
   thr->is_freeing = false;
+  thr->fast_state.IncrementEpoch();
+  TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
   Shadow s(thr->fast_state);
   s.ClearIgnoreBit();
   s.MarkAsFreed();
@@ -550,6 +619,8 @@
 }
 
 void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) {
+  thr->fast_state.IncrementEpoch();
+  TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc);
   Shadow s(thr->fast_state);
   s.ClearIgnoreBit();
   s.SetWrite(true);
@@ -557,7 +628,7 @@
   MemoryRangeSet(thr, pc, addr, size, s.raw());
 }
 
-ALWAYS_INLINE
+ALWAYS_INLINE USED
 void FuncEntry(ThreadState *thr, uptr pc) {
   DCHECK_EQ(thr->in_rtl, 0);
   StatInc(thr, StatFuncEnter);
@@ -587,7 +658,7 @@
   thr->shadow_stack_pos++;
 }
 
-ALWAYS_INLINE
+ALWAYS_INLINE USED
 void FuncExit(ThreadState *thr) {
   DCHECK_EQ(thr->in_rtl, 0);
   StatInc(thr, StatFuncExit);
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 053f24a..5445f57 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -27,7 +27,9 @@
 #define TSAN_RTL_H
 
 #include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
 #include "sanitizer_common/sanitizer_thread_registry.h"
 #include "tsan_clock.h"
 #include "tsan_defs.h"
@@ -137,6 +139,8 @@
 void TsanCheckFailed(const char *file, int line, const char *cond,
                      u64 v1, u64 v2);
 
+const u64 kShadowRodata = (u64)-1;  // .rodata shadow marker
+
 // FastState (from most significant bit):
 //   ignore          : 1
 //   tid             : kTidBits
@@ -382,6 +386,12 @@
 
 struct SignalContext;
 
+struct JmpBuf {
+  uptr sp;
+  uptr mangled_sp;
+  uptr *shadow_stack_pos;
+};
+
 // This struct is stored in TLS.
 struct ThreadState {
   FastState fast_state;
@@ -404,7 +414,6 @@
   uptr *shadow_stack_pos;
   u64 *racy_shadow_addr;
   u64 racy_state[2];
-  Trace trace;
 #ifndef TSAN_GO
   // C/C++ uses embed shadow stack of fixed size.
   uptr shadow_stack[kShadowStackSize];
@@ -417,6 +426,8 @@
   ThreadClock clock;
 #ifndef TSAN_GO
   AllocatorCache alloc_cache;
+  InternalAllocatorCache internal_alloc_cache;
+  Vector<JmpBuf> jmp_bufs;
 #endif
   u64 stat[StatCnt];
   const int tid;
@@ -425,6 +436,7 @@
   bool in_symbolizer;
   bool is_alive;
   bool is_freeing;
+  bool is_vptr_access;
   const uptr stk_addr;
   const uptr stk_size;
   const uptr tls_addr;
@@ -458,11 +470,6 @@
 }
 #endif
 
-// An info about a thread that is hold for some time after its termination.
-struct ThreadDeadInfo {
-  Trace trace;
-};
-
 class ThreadContext : public ThreadContextBase {
  public:
   explicit ThreadContext(int tid);
@@ -479,7 +486,6 @@
   // the event is from a dead thread that shared tid with this thread.
   u64 epoch0;
   u64 epoch1;
-  ThreadDeadInfo *dead_info;
 
   // Override superclass callbacks.
   void OnDead();
@@ -487,7 +493,7 @@
   void OnFinished();
   void OnStarted(void *arg);
   void OnCreated(void *arg);
-  void OnReset(void *arg);
+  void OnReset();
 };
 
 struct RacyStacks {
@@ -509,6 +515,7 @@
 struct FiredSuppression {
   ReportType type;
   uptr pc;
+  Suppression *supp;
 };
 
 struct Context {
@@ -521,12 +528,14 @@
   Mutex report_mtx;
   int nreported;
   int nmissed_expected;
+  atomic_uint64_t last_symbolize_time_ns;
 
   ThreadRegistry *thread_registry;
 
   Vector<RacyStacks> racy_stacks;
   Vector<RacyAddress> racy_addresses;
-  Vector<FiredSuppression> fired_suppressions;
+  // Number of fired suppressions may be large enough.
+  InternalMmapVector<FiredSuppression> fired_suppressions;
 
   Flags flags;
 
@@ -557,6 +566,7 @@
   void AddMutex(const SyncVar *s);
   void AddLocation(uptr addr, uptr size);
   void AddSleep(u32 stack_id);
+  void SetCount(int count);
 
   const ReportDesc *GetReport() const;
 
@@ -574,11 +584,11 @@
 
 void StatAggregate(u64 *dst, u64 *src);
 void StatOutput(u64 *stat);
-void ALWAYS_INLINE INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) {
+void ALWAYS_INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) {
   if (kCollectStats)
     thr->stat[typ] += n;
 }
-void ALWAYS_INLINE INLINE StatSet(ThreadState *thr, StatType typ, u64 n) {
+void ALWAYS_INLINE StatSet(ThreadState *thr, StatType typ, u64 n) {
   if (kCollectStats)
     thr->stat[typ] = n;
 }
@@ -594,11 +604,13 @@
 bool OutputReport(Context *ctx,
                   const ScopedReport &srep,
                   const ReportStack *suppress_stack1 = 0,
-                  const ReportStack *suppress_stack2 = 0);
+                  const ReportStack *suppress_stack2 = 0,
+                  const ReportLocation *suppress_loc = 0);
 bool IsFiredSuppression(Context *ctx,
                         const ScopedReport &srep,
                         const StackTrace &trace);
 bool IsExpectedReport(uptr addr, uptr size);
+void PrintMatchedBenignRaces();
 bool FrameIsInternal(const ReportStack *frame);
 ReportStack *SkipTsanInternalFrames(ReportStack *ent);
 
@@ -634,28 +646,30 @@
     uptr size, bool is_write);
 void MemoryAccessRangeStep(ThreadState *thr, uptr pc, uptr addr,
     uptr size, uptr step, bool is_write);
+void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr,
+    int size, bool kAccessIsWrite, bool kIsAtomic);
 
 const int kSizeLog1 = 0;
 const int kSizeLog2 = 1;
 const int kSizeLog4 = 2;
 const int kSizeLog8 = 3;
 
-void ALWAYS_INLINE INLINE MemoryRead(ThreadState *thr, uptr pc,
+void ALWAYS_INLINE MemoryRead(ThreadState *thr, uptr pc,
                                      uptr addr, int kAccessSizeLog) {
   MemoryAccess(thr, pc, addr, kAccessSizeLog, false, false);
 }
 
-void ALWAYS_INLINE INLINE MemoryWrite(ThreadState *thr, uptr pc,
+void ALWAYS_INLINE MemoryWrite(ThreadState *thr, uptr pc,
                                       uptr addr, int kAccessSizeLog) {
   MemoryAccess(thr, pc, addr, kAccessSizeLog, true, false);
 }
 
-void ALWAYS_INLINE INLINE MemoryReadAtomic(ThreadState *thr, uptr pc,
+void ALWAYS_INLINE MemoryReadAtomic(ThreadState *thr, uptr pc,
                                            uptr addr, int kAccessSizeLog) {
   MemoryAccess(thr, pc, addr, kAccessSizeLog, false, true);
 }
 
-void ALWAYS_INLINE INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
+void ALWAYS_INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
                                             uptr addr, int kAccessSizeLog) {
   MemoryAccess(thr, pc, addr, kAccessSizeLog, true, true);
 }
@@ -682,8 +696,8 @@
 void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
                  bool rw, bool recursive, bool linker_init);
 void MutexDestroy(ThreadState *thr, uptr pc, uptr addr);
-void MutexLock(ThreadState *thr, uptr pc, uptr addr);
-void MutexUnlock(ThreadState *thr, uptr pc, uptr addr);
+void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec = 1);
+int  MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false);
 void MutexReadLock(ThreadState *thr, uptr pc, uptr addr);
 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
@@ -719,9 +733,10 @@
 uptr TraceTopPC(ThreadState *thr);
 uptr TraceSize();
 uptr TraceParts();
+Trace *ThreadTrace(int tid);
 
 extern "C" void __tsan_trace_switch();
-void ALWAYS_INLINE INLINE TraceAddEvent(ThreadState *thr, FastState fs,
+void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs,
                                         EventType typ, u64 addr) {
   DCHECK_GE((int)typ, 0);
   DCHECK_LE((int)typ, 7);
diff --git a/lib/tsan/rtl/tsan_rtl_amd64.S b/lib/tsan/rtl/tsan_rtl_amd64.S
index af87856..11c75c7 100644
--- a/lib/tsan/rtl/tsan_rtl_amd64.S
+++ b/lib/tsan/rtl/tsan_rtl_amd64.S
@@ -160,6 +160,143 @@
   ret
   .cfi_endproc
 
+.hidden __tsan_setjmp
+.comm _ZN14__interception11real_setjmpE,8,8
+.globl setjmp
+.type setjmp, @function
+setjmp:
+  .cfi_startproc
+  // save env parameter
+  push %rdi
+  .cfi_adjust_cfa_offset 8
+  .cfi_rel_offset %rdi, 0
+  // obtain %rsp
+  lea 16(%rsp), %rdi
+  mov %rdi, %rsi
+  xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
+  rol $0x11, %rsi
+  // call tsan interceptor
+  call __tsan_setjmp
+  // restore env parameter
+  pop %rdi
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore %rdi
+  // tail jump to libc setjmp
+  movl $0, %eax
+  movq _ZN14__interception11real_setjmpE@GOTPCREL(%rip), %rdx
+  jmp *(%rdx)
+  .cfi_endproc
+.size setjmp, .-setjmp
+
+.comm _ZN14__interception12real__setjmpE,8,8
+.globl _setjmp
+.type _setjmp, @function
+_setjmp:
+  .cfi_startproc
+  // save env parameter
+  push %rdi
+  .cfi_adjust_cfa_offset 8
+  .cfi_rel_offset %rdi, 0
+  // obtain %rsp
+  lea 16(%rsp), %rdi
+  mov %rdi, %rsi
+  xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
+  rol $0x11, %rsi
+  // call tsan interceptor
+  call __tsan_setjmp
+  // restore env parameter
+  pop %rdi
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore %rdi
+  // tail jump to libc setjmp
+  movl $0, %eax
+  movq _ZN14__interception12real__setjmpE@GOTPCREL(%rip), %rdx
+  jmp *(%rdx)
+  .cfi_endproc
+.size _setjmp, .-_setjmp
+
+.comm _ZN14__interception14real_sigsetjmpE,8,8
+.globl sigsetjmp
+.type sigsetjmp, @function
+sigsetjmp:
+  .cfi_startproc
+  // save env parameter
+  push %rdi
+  .cfi_adjust_cfa_offset 8
+  .cfi_rel_offset %rdi, 0
+  // save savesigs parameter
+  push %rsi
+  .cfi_adjust_cfa_offset 8
+  .cfi_rel_offset %rsi, 0
+  // align stack frame
+  sub $8, %rsp
+  .cfi_adjust_cfa_offset 8
+  // obtain %rsp
+  lea 32(%rsp), %rdi
+  mov %rdi, %rsi
+  xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
+  rol $0x11, %rsi
+  // call tsan interceptor
+  call __tsan_setjmp
+  // unalign stack frame
+  add $8, %rsp
+  .cfi_adjust_cfa_offset -8
+  // restore savesigs parameter
+  pop %rsi
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore %rsi
+  // restore env parameter
+  pop %rdi
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore %rdi
+  // tail jump to libc sigsetjmp
+  movl $0, %eax
+  movq _ZN14__interception14real_sigsetjmpE@GOTPCREL(%rip), %rdx
+  jmp *(%rdx)
+  .cfi_endproc
+.size sigsetjmp, .-sigsetjmp
+
+.comm _ZN14__interception16real___sigsetjmpE,8,8
+.globl __sigsetjmp
+.type __sigsetjmp, @function
+__sigsetjmp:
+  .cfi_startproc
+  // save env parameter
+  push %rdi
+  .cfi_adjust_cfa_offset 8
+  .cfi_rel_offset %rdi, 0
+  // save savesigs parameter
+  push %rsi
+  .cfi_adjust_cfa_offset 8
+  .cfi_rel_offset %rsi, 0
+  // align stack frame
+  sub $8, %rsp
+  .cfi_adjust_cfa_offset 8
+  // obtain %rsp
+  lea 32(%rsp), %rdi
+  mov %rdi, %rsi
+  xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
+  rol $0x11, %rsi
+  // call tsan interceptor
+  call __tsan_setjmp
+  // unalign stack frame
+  add $8, %rsp
+  .cfi_adjust_cfa_offset -8
+  // restore savesigs parameter
+  pop %rsi
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore %rsi
+  // restore env parameter
+  pop %rdi
+  .cfi_adjust_cfa_offset -8
+  .cfi_restore %rdi
+  // tail jump to libc sigsetjmp
+  movl $0, %eax
+  movq _ZN14__interception16real___sigsetjmpE@GOTPCREL(%rip), %rdx
+  jmp *(%rdx)
+  .cfi_endproc
+.size __sigsetjmp, .-__sigsetjmp
+
 #ifdef __linux__
 /* We do not need executable stack.  */
 .section        .note.GNU-stack,"",@progbits
diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc
index 1f3c7ac..cf2e44d 100644
--- a/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -79,9 +79,10 @@
   DestroyAndFree(s);
 }
 
-void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
+void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) {
   CHECK_GT(thr->in_rtl, 0);
-  DPrintf("#%d: MutexLock %zx\n", thr->tid, addr);
+  DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec);
+  CHECK_GT(rec, 0);
   if (IsAppMem(addr))
     MemoryReadAtomic(thr, pc, addr, kSizeLog1);
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
@@ -107,19 +108,20 @@
   } else if (!s->is_recursive) {
     StatInc(thr, StatMutexRecLock);
   }
-  s->recursion++;
+  s->recursion += rec;
   thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
   s->mtx.Unlock();
 }
 
-void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) {
+int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
   CHECK_GT(thr->in_rtl, 0);
-  DPrintf("#%d: MutexUnlock %zx\n", thr->tid, addr);
+  DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all);
   if (IsAppMem(addr))
     MemoryReadAtomic(thr, pc, addr, kSizeLog1);
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
+  int rec = 0;
   if (s->recursion == 0) {
     if (!s->is_broken) {
       s->is_broken = true;
@@ -133,7 +135,8 @@
       PrintCurrentStack(thr, pc);
     }
   } else {
-    s->recursion--;
+    rec = all ? s->recursion : 1;
+    s->recursion -= rec;
     if (s->recursion == 0) {
       StatInc(thr, StatMutexUnlock);
       s->owner_tid = SyncVar::kInvalidTid;
@@ -147,6 +150,7 @@
   }
   thr->mset.Del(s->GetId(), true);
   s->mtx.Unlock();
+  return rec;
 }
 
 void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc
index 2df4234..94419ce 100644
--- a/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/lib/tsan/rtl/tsan_rtl_report.cc
@@ -95,8 +95,9 @@
     DPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc);
   }
 #else
-  if (last && 0 == internal_strcmp(last, "schedunlock"))
-    last_frame2->next = 0;
+  // The last frame always point into runtime (gosched0, goexit0, runtime.main).
+  last_frame2->next = 0;
+  (void)last;
 #endif
 }
 
@@ -105,17 +106,25 @@
     return 0;
   ReportStack *stack = 0;
   for (uptr si = 0; si < trace.Size(); si++) {
+    const uptr pc = trace.Get(si);
+#ifndef TSAN_GO
     // We obtain the return address, that is, address of the next instruction,
     // so offset it by 1 byte.
-    bool is_last = (si == trace.Size() - 1);
-    ReportStack *ent = SymbolizeCode(trace.Get(si) - !is_last);
+    const uptr pc1 = __sanitizer::StackTrace::GetPreviousInstructionPc(pc);
+#else
+    // FIXME(dvyukov): Go sometimes uses address of a function as top pc.
+    uptr pc1 = pc;
+    if (si != trace.Size() - 1)
+      pc1 -= 1;
+#endif
+    ReportStack *ent = SymbolizeCode(pc1);
     CHECK_NE(ent, 0);
     ReportStack *last = ent;
     while (last->next) {
-      last->pc += !is_last;
+      last->pc = pc;  // restore original pc for report
       last = last->next;
     }
-    last->pc += !is_last;
+    last->pc = pc;  // restore original pc for report
     last->next = stack;
     stack = ent;
   }
@@ -130,9 +139,11 @@
   rep_ = new(mem) ReportDesc;
   rep_->typ = typ;
   ctx_->report_mtx.Lock();
+  CommonSanitizerReportMutex.Lock();
 }
 
 ScopedReport::~ScopedReport() {
+  CommonSanitizerReportMutex.Unlock();
   ctx_->report_mtx.Unlock();
   DestroyAndFree(rep_);
 }
@@ -311,8 +322,9 @@
       AddThread(tctx);
     return;
   }
-  if (allocator()->PointerIsMine((void*)addr)) {
-    MBlock *b = user_mblock(0, (void*)addr);
+  MBlock *b = 0;
+  if (allocator()->PointerIsMine((void*)addr)
+      && (b = user_mblock(0, (void*)addr))) {
     ThreadContext *tctx = FindThreadByTidLocked(b->Tid());
     void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
     ReportLocation *loc = new(mem) ReportLocation();
@@ -365,6 +377,10 @@
 }
 #endif
 
+void ScopedReport::SetCount(int count) {
+  rep_->count = count;
+}
+
 const ReportDesc *ScopedReport::GetReport() const {
   return rep_;
 }
@@ -379,18 +395,11 @@
       ctx->thread_registry->GetThreadLocked(tid));
   if (tctx == 0)
     return;
-  Trace* trace = 0;
-  if (tctx->status == ThreadStatusRunning) {
-    CHECK(tctx->thr);
-    trace = &tctx->thr->trace;
-  } else if (tctx->status == ThreadStatusFinished
-      || tctx->status == ThreadStatusDead) {
-    if (tctx->dead_info == 0)
-      return;
-    trace = &tctx->dead_info->trace;
-  } else {
+  if (tctx->status != ThreadStatusRunning
+      && tctx->status != ThreadStatusFinished
+      && tctx->status != ThreadStatusDead)
     return;
-  }
+  Trace* trace = ThreadTrace(tctx->tid);
   Lock l(&trace->mtx);
   const int partidx = (epoch / kTracePartSize) % TraceParts();
   TraceHeader* hdr = &trace->headers[partidx];
@@ -501,14 +510,19 @@
 bool OutputReport(Context *ctx,
                   const ScopedReport &srep,
                   const ReportStack *suppress_stack1,
-                  const ReportStack *suppress_stack2) {
+                  const ReportStack *suppress_stack2,
+                  const ReportLocation *suppress_loc) {
+  atomic_store(&ctx->last_symbolize_time_ns, NanoTime(), memory_order_relaxed);
   const ReportDesc *rep = srep.GetReport();
-  uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1);
+  Suppression *supp = 0;
+  uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1, &supp);
   if (suppress_pc == 0)
-    suppress_pc = IsSuppressed(rep->typ, suppress_stack2);
+    suppress_pc = IsSuppressed(rep->typ, suppress_stack2, &supp);
+  if (suppress_pc == 0)
+    suppress_pc = IsSuppressed(rep->typ, suppress_loc, &supp);
   if (suppress_pc != 0) {
-    FiredSuppression supp = {srep.GetReport()->typ, suppress_pc};
-    ctx->fired_suppressions.PushBack(supp);
+    FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp};
+    ctx->fired_suppressions.push_back(s);
   }
   if (OnReport(rep, suppress_pc != 0))
     return false;
@@ -520,12 +534,32 @@
 bool IsFiredSuppression(Context *ctx,
                         const ScopedReport &srep,
                         const StackTrace &trace) {
-  for (uptr k = 0; k < ctx->fired_suppressions.Size(); k++) {
+  for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
     if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
       continue;
     for (uptr j = 0; j < trace.Size(); j++) {
-      if (trace.Get(j) == ctx->fired_suppressions[k].pc)
+      FiredSuppression *s = &ctx->fired_suppressions[k];
+      if (trace.Get(j) == s->pc) {
+        if (s->supp)
+          s->supp->hit_count++;
         return true;
+      }
+    }
+  }
+  return false;
+}
+
+static bool IsFiredSuppression(Context *ctx,
+                               const ScopedReport &srep,
+                               uptr addr) {
+  for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
+    if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
+      continue;
+    FiredSuppression *s = &ctx->fired_suppressions[k];
+    if (addr == s->pc) {
+      if (s->supp)
+        s->supp->hit_count++;
+      return true;
     }
   }
   return false;
@@ -562,8 +596,8 @@
           || (frame->func == 0 && frame->file == 0 && frame->line == 0
           && frame->module == 0)) {
         if (frame) {
-          FiredSuppression supp = {rep->typ, frame->pc};
-          CTX()->fired_suppressions.PushBack(supp);
+          FiredSuppression supp = {rep->typ, frame->pc, 0};
+          CTX()->fired_suppressions.push_back(supp);
         }
         return true;
       }
@@ -594,10 +628,6 @@
   if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
     return;
 
-  if (thr->in_signal_handler)
-    Printf("ThreadSanitizer: printing report from signal handler."
-           " Can crash or hang.\n");
-
   bool freed = false;
   {
     Shadow s(thr->racy_state[1]);
@@ -622,7 +652,14 @@
   Context *ctx = CTX();
   ThreadRegistryLock l0(ctx->thread_registry);
 
-  ScopedReport rep(freed ? ReportTypeUseAfterFree : ReportTypeRace);
+  ReportType typ = ReportTypeRace;
+  if (thr->is_vptr_access)
+    typ = ReportTypeVptrRace;
+  else if (freed)
+    typ = ReportTypeUseAfterFree;
+  ScopedReport rep(typ);
+  if (IsFiredSuppression(ctx, rep, addr))
+    return;
   const uptr kMop = 2;
   StackTrace traces[kMop];
   const uptr toppc = TraceTopPC(thr);
@@ -633,6 +670,8 @@
   new(mset2.data()) MutexSet();
   Shadow s2(thr->racy_state[1]);
   RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2.data());
+  if (IsFiredSuppression(ctx, rep, traces[1]))
+    return;
 
   if (HandleRacyStacks(thr, traces, addr_min, addr_max))
     return;
@@ -665,8 +704,11 @@
   }
 #endif
 
+  ReportLocation *suppress_loc = rep.GetReport()->locs.Size() ?
+                                 rep.GetReport()->locs[0] : 0;
   if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack,
-                              rep.GetReport()->mops[1]->stack))
+                              rep.GetReport()->mops[1]->stack,
+                              suppress_loc))
     return;
 
   AddRacyStacks(thr, traces, addr_min, addr_max);
@@ -684,6 +726,11 @@
       sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
   ptrace->SlowUnwindStack(__sanitizer::StackTrace::GetCurrentPc(),
       kStackTraceMax);
+  for (uptr i = 0; i < ptrace->size / 2; i++) {
+    uptr tmp = ptrace->trace[i];
+    ptrace->trace[i] = ptrace->trace[ptrace->size - i - 1];
+    ptrace->trace[ptrace->size - i - 1] = tmp;
+  }
   StackTrace trace;
   trace.Init(ptrace->trace, ptrace->size);
   PrintStack(SymbolizeStack(trace));
diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc
index 72b9f1a..81e1b0a 100644
--- a/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -27,8 +27,7 @@
   , thr()
   , sync()
   , epoch0()
-  , epoch1()
-  , dead_info() {
+  , epoch1() {
 }
 
 #ifndef TSAN_GO
@@ -44,6 +43,7 @@
   ThreadState *caller_thr = static_cast<ThreadState *>(arg);
   caller_thr->clock.acquire(&sync);
   StatInc(caller_thr, StatSyncAcquire);
+  sync.Reset();
 }
 
 struct OnCreatedArgs {
@@ -72,11 +72,10 @@
     StatInc(args->thr, StatThreadMaxTid);
 }
 
-void ThreadContext::OnReset(void *arg) {
-  OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
-  StatInc(args->thr, StatThreadReuse);
+void ThreadContext::OnReset() {
   sync.Reset();
-  DestroyAndFree(dead_info);
+  FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event));
+  //!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace));
 }
 
 struct OnStartedArgs {
@@ -113,8 +112,10 @@
   thr->clock.acquire(&sync);
   thr->fast_state.SetHistorySize(flags()->history_size);
   const uptr trace = (epoch0 / kTracePartSize) % TraceParts();
-  thr->trace.headers[trace].epoch0 = epoch0;
+  Trace *thr_trace = ThreadTrace(thr->tid);
+  thr_trace->headers[trace].epoch0 = epoch0;
   StatInc(thr, StatSyncAcquire);
+  sync.Reset();
   DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
           "tls_addr=%zx tls_size=%zx\n",
           tid, (uptr)epoch0, args->stk_addr, args->stk_size,
@@ -132,14 +133,6 @@
     thr->clock.release(&sync);
     StatInc(thr, StatSyncRelease);
   }
-  // Save from info about the thread.
-  dead_info = new(internal_alloc(MBlockDeadInfo, sizeof(ThreadDeadInfo)))
-      ThreadDeadInfo();
-  for (uptr i = 0; i < TraceParts(); i++) {
-    dead_info->trace.headers[i].epoch0 = thr->trace.headers[i].epoch0;
-    dead_info->trace.headers[i].stack0.CopyFrom(
-        thr->trace.headers[i].stack0);
-  }
   epoch1 = thr->fast_state.epoch();
 
 #ifndef TSAN_GO
@@ -150,26 +143,52 @@
   thr = 0;
 }
 
-static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *unused) {
+#ifndef TSAN_GO
+struct ThreadLeak {
+  ThreadContext *tctx;
+  int count;
+};
+
+static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
+  Vector<ThreadLeak> &leaks = *(Vector<ThreadLeak>*)arg;
   ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
-  if (tctx->detached)
+  if (tctx->detached || tctx->status != ThreadStatusFinished)
     return;
-  if (tctx->status != ThreadStatusCreated
-      && tctx->status != ThreadStatusRunning
-      && tctx->status != ThreadStatusFinished)
-    return;
-  ScopedReport rep(ReportTypeThreadLeak);
-  rep.AddThread(tctx);
-  OutputReport(CTX(), rep);
+  for (uptr i = 0; i < leaks.Size(); i++) {
+    if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) {
+      leaks[i].count++;
+      return;
+    }
+  }
+  ThreadLeak leak = {tctx, 1};
+  leaks.PushBack(leak);
+}
+#endif
+
+static void ThreadCheckIgnore(ThreadState *thr) {
+  if (thr->ignore_reads_and_writes) {
+    Printf("ThreadSanitizer: thread T%d finished with ignores enabled.\n",
+           thr->tid);
+  }
 }
 
 void ThreadFinalize(ThreadState *thr) {
   CHECK_GT(thr->in_rtl, 0);
+  ThreadCheckIgnore(thr);
+#ifndef TSAN_GO
   if (!flags()->report_thread_leaks)
     return;
   ThreadRegistryLock l(CTX()->thread_registry);
+  Vector<ThreadLeak> leaks(MBlockScopedBuf);
   CTX()->thread_registry->RunCallbackForEachThreadLocked(
-      MaybeReportThreadLeak, 0);
+      MaybeReportThreadLeak, &leaks);
+  for (uptr i = 0; i < leaks.Size(); i++) {
+    ScopedReport rep(ReportTypeThreadLeak);
+    rep.AddThread(leaks[i].tctx);
+    rep.SetCount(leaks[i].count);
+    OutputReport(CTX(), rep);
+  }
+#endif
 }
 
 int ThreadCount(ThreadState *thr) {
@@ -224,6 +243,7 @@
 
 void ThreadFinish(ThreadState *thr) {
   CHECK_GT(thr->in_rtl, 0);
+  ThreadCheckIgnore(thr);
   StatInc(thr, StatThreadFinish);
   if (thr->stk_addr && thr->stk_size)
     DontNeedShadowFor(thr->stk_addr, thr->stk_size);
@@ -305,6 +325,13 @@
 
   StatInc(thr, StatMopRange);
 
+  if (*shadow_mem == kShadowRodata) {
+    // Access to .rodata section, no races here.
+    // Measurements show that it can be 10-20% of all memory accesses.
+    StatInc(thr, StatMopRangeRodata);
+    return;
+  }
+
   FastState fast_state = thr->fast_state;
   if (fast_state.GetIgnoreBit())
     return;
@@ -347,25 +374,4 @@
   }
 }
 
-void MemoryAccessRangeStep(ThreadState *thr, uptr pc, uptr addr,
-    uptr size, uptr step, bool is_write) {
-  if (size == 0)
-    return;
-  FastState fast_state = thr->fast_state;
-  if (fast_state.GetIgnoreBit())
-    return;
-  StatInc(thr, StatMopRange);
-  fast_state.IncrementEpoch();
-  thr->fast_state = fast_state;
-  TraceAddEvent(thr, fast_state, EventTypeMop, pc);
-
-  for (uptr addr_end = addr + size; addr < addr_end; addr += step) {
-    u64 *shadow_mem = (u64*)MemToShadow(addr);
-    Shadow cur(fast_state);
-    cur.SetWrite(is_write);
-    cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kSizeLog1);
-    MemoryAccessImpl(thr, addr, kSizeLog1, is_write, false,
-        shadow_mem, cur);
-  }
-}
 }  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_stat.cc b/lib/tsan/rtl/tsan_stat.cc
index 4a0d0f4..dacc498 100644
--- a/lib/tsan/rtl/tsan_stat.cc
+++ b/lib/tsan/rtl/tsan_stat.cc
@@ -38,6 +38,8 @@
   name[StatMop8]                         = "            size 8                ";
   name[StatMopSame]                      = "  Including same                  ";
   name[StatMopRange]                     = "  Including range                 ";
+  name[StatMopRodata]                    = "  Including .rodata               ";
+  name[StatMopRangeRodata]               = "  Including .rodata range         ";
   name[StatShadowProcessed]              = "Shadow processed                  ";
   name[StatShadowZero]                   = "  Including empty                 ";
   name[StatShadowNonZero]                = "  Including non empty             ";
@@ -105,6 +107,7 @@
   name[StatInt_realloc]                  = "  realloc                         ";
   name[StatInt_free]                     = "  free                            ";
   name[StatInt_cfree]                    = "  cfree                           ";
+  name[StatInt_malloc_usable_size]       = "  malloc_usable_size              ";
   name[StatInt_mmap]                     = "  mmap                            ";
   name[StatInt_mmap64]                   = "  mmap64                          ";
   name[StatInt_munmap]                   = "  munmap                          ";
@@ -135,6 +138,8 @@
   name[StatInt_strcpy]                   = "  strcpy                          ";
   name[StatInt_strncpy]                  = "  strncpy                         ";
   name[StatInt_strstr]                   = "  strstr                          ";
+  name[StatInt_strcasecmp]               = "  strcasecmp                      ";
+  name[StatInt_strncasecmp]              = "  strncasecmp                     ";
   name[StatInt_atexit]                   = "  atexit                          ";
   name[StatInt___cxa_guard_acquire]      = "  __cxa_guard_acquire             ";
   name[StatInt___cxa_guard_release]      = "  __cxa_guard_release             ";
@@ -174,6 +179,7 @@
   name[StatInt_pthread_barrier_destroy]  = "  pthread_barrier_destroy         ";
   name[StatInt_pthread_barrier_wait]     = "  pthread_barrier_wait            ";
   name[StatInt_pthread_once]             = "  pthread_once                    ";
+  name[StatInt_pthread_getschedparam]    = "  pthread_getschedparam           ";
   name[StatInt_sem_init]                 = "  sem_init                        ";
   name[StatInt_sem_destroy]              = "  sem_destroy                     ";
   name[StatInt_sem_wait]                 = "  sem_wait                        ";
@@ -223,11 +229,13 @@
   name[StatInt_pread]                    = "  pread                           ";
   name[StatInt_pread64]                  = "  pread64                         ";
   name[StatInt_readv]                    = "  readv                           ";
+  name[StatInt_preadv]                   = "  preadv                          ";
   name[StatInt_preadv64]                 = "  preadv64                        ";
   name[StatInt_write]                    = "  write                           ";
   name[StatInt_pwrite]                   = "  pwrite                          ";
   name[StatInt_pwrite64]                 = "  pwrite64                        ";
   name[StatInt_writev]                   = "  writev                          ";
+  name[StatInt_pwritev]                  = "  pwritev                         ";
   name[StatInt_pwritev64]                = "  pwritev64                       ";
   name[StatInt_send]                     = "  send                            ";
   name[StatInt_sendmsg]                  = "  sendmsg                         ";
@@ -239,6 +247,8 @@
   name[StatInt_fclose]                   = "  fclose                          ";
   name[StatInt_fread]                    = "  fread                           ";
   name[StatInt_fwrite]                   = "  fwrite                          ";
+  name[StatInt_fflush]                   = "  fflush                          ";
+  name[StatInt_abort]                    = "  abort                           ";
   name[StatInt_puts]                     = "  puts                            ";
   name[StatInt_rmdir]                    = "  rmdir                           ";
   name[StatInt_opendir]                  = "  opendir                         ";
@@ -246,6 +256,11 @@
   name[StatInt_epoll_wait]               = "  epoll_wait                      ";
   name[StatInt_poll]                     = "  poll                            ";
   name[StatInt_sigaction]                = "  sigaction                       ";
+  name[StatInt_signal]                   = "  signal                          ";
+  name[StatInt_sigsuspend]               = "  sigsuspend                      ";
+  name[StatInt_raise]                    = "  raise                           ";
+  name[StatInt_kill]                     = "  kill                            ";
+  name[StatInt_pthread_kill]             = "  pthread_kill                    ";
   name[StatInt_sleep]                    = "  sleep                           ";
   name[StatInt_usleep]                   = "  usleep                          ";
   name[StatInt_nanosleep]                = "  nanosleep                       ";
@@ -276,6 +291,69 @@
   name[StatInt_frexp]                    = "  frexp                           ";
   name[StatInt_frexpf]                   = "  frexpf                          ";
   name[StatInt_frexpl]                   = "  frexpl                          ";
+  name[StatInt_getpwnam]                 = "  getpwnam                        ";
+  name[StatInt_getpwuid]                 = "  getpwuid                        ";
+  name[StatInt_getgrnam]                 = "  getgrnam                        ";
+  name[StatInt_getgrgid]                 = "  getgrgid                        ";
+  name[StatInt_getpwnam_r]               = "  getpwnam_r                      ";
+  name[StatInt_getpwuid_r]               = "  getpwuid_r                      ";
+  name[StatInt_getgrnam_r]               = "  getgrnam_r                      ";
+  name[StatInt_getgrgid_r]               = "  getgrgid_r                      ";
+  name[StatInt_clock_getres]             = "  clock_getres                    ";
+  name[StatInt_clock_gettime]            = "  clock_gettime                   ";
+  name[StatInt_clock_settime]            = "  clock_settime                   ";
+  name[StatInt_getitimer]                = "  getitimer                       ";
+  name[StatInt_setitimer]                = "  setitimer                       ";
+  name[StatInt_time]                     = "  time                            ";
+  name[StatInt_glob]                     = "  glob                            ";
+  name[StatInt_glob64]                   = "  glob64                          ";
+  name[StatInt_wait]                     = "  wait                            ";
+  name[StatInt_waitid]                   = "  waitid                          ";
+  name[StatInt_waitpid]                  = "  waitpid                         ";
+  name[StatInt_wait3]                    = "  wait3                           ";
+  name[StatInt_wait4]                    = "  wait4                           ";
+  name[StatInt_inet_ntop]                = "  inet_ntop                       ";
+  name[StatInt_inet_pton]                = "  inet_pton                       ";
+  name[StatInt_inet_aton]                = "  inet_aton                       ";
+  name[StatInt_getaddrinfo]              = "  getaddrinfo                     ";
+  name[StatInt_getnameinfo]              = "  getnameinfo                     ";
+  name[StatInt_getsockname]              = "  getsockname                     ";
+  name[StatInt_gethostent]               = "  gethostent                      ";
+  name[StatInt_gethostbyname]            = "  gethostbyname                   ";
+  name[StatInt_gethostbyname2]           = "  gethostbyname2                  ";
+  name[StatInt_gethostbyaddr]            = "  gethostbyaddr                   ";
+  name[StatInt_gethostent_r]             = "  gethostent_r                    ";
+  name[StatInt_gethostbyname_r]          = "  gethostbyname_r                 ";
+  name[StatInt_gethostbyname2_r]         = "  gethostbyname2_r                ";
+  name[StatInt_gethostbyaddr_r]          = "  gethostbyaddr_r                 ";
+  name[StatInt_getsockopt]               = "  getsockopt                      ";
+  name[StatInt_modf]                     = "  modf                            ";
+  name[StatInt_modff]                    = "  modff                           ";
+  name[StatInt_modfl]                    = "  modfl                           ";
+  name[StatInt_getpeername]              = "  getpeername                     ";
+  name[StatInt_ioctl]                    = "  ioctl                           ";
+  name[StatInt_sysinfo]                  = "  sysinfo                         ";
+  name[StatInt_readdir]                  = "  readdir                         ";
+  name[StatInt_readdir64]                = "  readdir64                       ";
+  name[StatInt_readdir_r]                = "  readdir_r                       ";
+  name[StatInt_readdir64_r]              = "  readdir64_r                     ";
+  name[StatInt_ptrace]                   = "  ptrace                          ";
+  name[StatInt_setlocale]                = "  setlocale                       ";
+  name[StatInt_getcwd]                   = "  getcwd                          ";
+  name[StatInt_get_current_dir_name]     = "  get_current_dir_name            ";
+  name[StatInt_strtoimax]                = "  strtoimax                       ";
+  name[StatInt_strtoumax]                = "  strtoumax                       ";
+  name[StatInt_mbstowcs]                 = "  mbstowcs                        ";
+  name[StatInt_mbsrtowcs]                = "  mbsrtowcs                       ";
+  name[StatInt_mbsnrtowcs]               = "  mbsnrtowcs                      ";
+  name[StatInt_wcstombs]                 = "  wcstombs                        ";
+  name[StatInt_wcsrtombs]                = "  wcsrtombs                       ";
+  name[StatInt_wcsnrtombs]               = "  wcsnrtombs                      ";
+  name[StatInt_tcgetattr]                = "  tcgetattr                       ";
+  name[StatInt_realpath]                 = "  realpath                        ";
+  name[StatInt_canonicalize_file_name]   = "  canonicalize_file_name          ";
+  name[StatInt_confstr]                  = "  confstr                         ";
+  name[StatInt_sched_getaffinity]        = "  sched_getaffinity               ";
 
   name[StatAnnotation]                   = "Dynamic annotations               ";
   name[StatAnnotateHappensBefore]        = "  HappensBefore                   ";
@@ -285,6 +363,7 @@
   name[StatAnnotateMutexIsNotPHB]        = "  MutexIsNotPHB                   ";
   name[StatAnnotateCondVarWait]          = "  CondVarWait                     ";
   name[StatAnnotateRWLockCreate]         = "  RWLockCreate                    ";
+  name[StatAnnotateRWLockCreateStatic]   = "  StatAnnotateRWLockCreateStatic  ";
   name[StatAnnotateRWLockDestroy]        = "  RWLockDestroy                   ";
   name[StatAnnotateRWLockAcquired]       = "  RWLockAcquired                  ";
   name[StatAnnotateRWLockReleased]       = "  RWLockReleased                  ";
diff --git a/lib/tsan/rtl/tsan_stat.h b/lib/tsan/rtl/tsan_stat.h
index 131dd66..b3a850a 100644
--- a/lib/tsan/rtl/tsan_stat.h
+++ b/lib/tsan/rtl/tsan_stat.h
@@ -27,6 +27,8 @@
   StatMop8,
   StatMopSame,
   StatMopRange,
+  StatMopRodata,
+  StatMopRangeRodata,
   StatShadowProcessed,
   StatShadowZero,
   StatShadowNonZero,  // Derived.
@@ -132,6 +134,8 @@
   StatInt_strncmp,
   StatInt_strcpy,
   StatInt_strncpy,
+  StatInt_strcasecmp,
+  StatInt_strncasecmp,
   StatInt_strstr,
   StatInt_atexit,
   StatInt___cxa_guard_acquire,
@@ -170,6 +174,7 @@
   StatInt_pthread_barrier_destroy,
   StatInt_pthread_barrier_wait,
   StatInt_pthread_once,
+  StatInt_pthread_getschedparam,
   StatInt_sem_init,
   StatInt_sem_destroy,
   StatInt_sem_wait,
@@ -219,11 +224,13 @@
   StatInt_pread,
   StatInt_pread64,
   StatInt_readv,
+  StatInt_preadv,
   StatInt_preadv64,
   StatInt_write,
   StatInt_pwrite,
   StatInt_pwrite64,
   StatInt_writev,
+  StatInt_pwritev,
   StatInt_pwritev64,
   StatInt_send,
   StatInt_sendmsg,
@@ -235,6 +242,8 @@
   StatInt_fclose,
   StatInt_fread,
   StatInt_fwrite,
+  StatInt_fflush,
+  StatInt_abort,
   StatInt_puts,
   StatInt_rmdir,
   StatInt_opendir,
@@ -243,6 +252,7 @@
   StatInt_poll,
   StatInt_sigaction,
   StatInt_signal,
+  StatInt_sigsuspend,
   StatInt_raise,
   StatInt_kill,
   StatInt_pthread_kill,
@@ -276,6 +286,69 @@
   StatInt_frexp,
   StatInt_frexpf,
   StatInt_frexpl,
+  StatInt_getpwnam,
+  StatInt_getpwuid,
+  StatInt_getgrnam,
+  StatInt_getgrgid,
+  StatInt_getpwnam_r,
+  StatInt_getpwuid_r,
+  StatInt_getgrnam_r,
+  StatInt_getgrgid_r,
+  StatInt_clock_getres,
+  StatInt_clock_gettime,
+  StatInt_clock_settime,
+  StatInt_getitimer,
+  StatInt_setitimer,
+  StatInt_time,
+  StatInt_glob,
+  StatInt_glob64,
+  StatInt_wait,
+  StatInt_waitid,
+  StatInt_waitpid,
+  StatInt_wait3,
+  StatInt_wait4,
+  StatInt_inet_ntop,
+  StatInt_inet_pton,
+  StatInt_inet_aton,
+  StatInt_getaddrinfo,
+  StatInt_getnameinfo,
+  StatInt_getsockname,
+  StatInt_gethostent,
+  StatInt_gethostbyname,
+  StatInt_gethostbyname2,
+  StatInt_gethostbyaddr,
+  StatInt_gethostent_r,
+  StatInt_gethostbyname_r,
+  StatInt_gethostbyname2_r,
+  StatInt_gethostbyaddr_r,
+  StatInt_getsockopt,
+  StatInt_modf,
+  StatInt_modff,
+  StatInt_modfl,
+  StatInt_getpeername,
+  StatInt_ioctl,
+  StatInt_sysinfo,
+  StatInt_readdir,
+  StatInt_readdir64,
+  StatInt_readdir_r,
+  StatInt_readdir64_r,
+  StatInt_ptrace,
+  StatInt_setlocale,
+  StatInt_getcwd,
+  StatInt_get_current_dir_name,
+  StatInt_strtoimax,
+  StatInt_strtoumax,
+  StatInt_mbstowcs,
+  StatInt_mbsrtowcs,
+  StatInt_mbsnrtowcs,
+  StatInt_wcstombs,
+  StatInt_wcsrtombs,
+  StatInt_wcsnrtombs,
+  StatInt_tcgetattr,
+  StatInt_realpath,
+  StatInt_canonicalize_file_name,
+  StatInt_confstr,
+  StatInt_sched_getaffinity,
 
   // Dynamic annotations.
   StatAnnotation,
diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc
index 941c208..69e616c 100644
--- a/lib/tsan/rtl/tsan_suppressions.cc
+++ b/lib/tsan/rtl/tsan_suppressions.cc
@@ -13,6 +13,8 @@
 
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
 #include "tsan_suppressions.h"
 #include "tsan_rtl.h"
 #include "tsan_flags.h"
@@ -28,7 +30,7 @@
 
 namespace __tsan {
 
-static Suppression *g_suppressions;
+static SuppressionContext* g_ctx;
 
 static char *ReadFile(const char *filename) {
   if (filename == 0 || filename[0] == 0)
@@ -38,12 +40,13 @@
     internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
   else
     internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
-  fd_t fd = OpenFile(tmp.data(), false);
-  if (fd == kInvalidFd) {
+  uptr openrv = OpenFile(tmp.data(), false);
+  if (internal_iserror(openrv)) {
     Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
                tmp.data());
     Die();
   }
+  fd_t fd = openrv;
   const uptr fsize = internal_filesize(fd);
   if (fsize == (uptr)-1) {
     Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
@@ -61,114 +64,90 @@
   return buf;
 }
 
-bool SuppressionMatch(char *templ, const char *str) {
-  if (str == 0 || str[0] == 0)
-    return false;
-  char *tpos;
-  const char *spos;
-  while (templ && templ[0]) {
-    if (templ[0] == '*') {
-      templ++;
-      continue;
-    }
-    if (str[0] == 0)
-      return false;
-    tpos = (char*)internal_strchr(templ, '*');
-    if (tpos != 0)
-      tpos[0] = 0;
-    spos = internal_strstr(str, templ);
-    str = spos + internal_strlen(templ);
-    templ = tpos;
-    if (tpos)
-      tpos[0] = '*';
-    if (spos == 0)
-      return false;
-  }
-  return true;
-}
-
-Suppression *SuppressionParse(Suppression *head, const char* supp) {
-  const char *line = supp;
-  while (line) {
-    while (line[0] == ' ' || line[0] == '\t')
-      line++;
-    const char *end = internal_strchr(line, '\n');
-    if (end == 0)
-      end = line + internal_strlen(line);
-    if (line != end && line[0] != '#') {
-      const char *end2 = end;
-      while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
-        end2--;
-      SuppressionType stype;
-      if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
-        stype = SuppressionRace;
-        line += sizeof("race:") - 1;
-      } else if (0 == internal_strncmp(line, "thread:",
-          sizeof("thread:") - 1)) {
-        stype = SuppressionThread;
-        line += sizeof("thread:") - 1;
-      } else if (0 == internal_strncmp(line, "mutex:",
-          sizeof("mutex:") - 1)) {
-        stype = SuppressionMutex;
-        line += sizeof("mutex:") - 1;
-      } else if (0 == internal_strncmp(line, "signal:",
-          sizeof("signal:") - 1)) {
-        stype = SuppressionSignal;
-        line += sizeof("signal:") - 1;
-      } else {
-        Printf("ThreadSanitizer: failed to parse suppressions file\n");
-        Die();
-      }
-      Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
-          sizeof(Suppression));
-      s->next = head;
-      head = s;
-      s->type = stype;
-      s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
-      internal_memcpy(s->templ, line, end2 - line);
-      s->templ[end2 - line] = 0;
-    }
-    if (end[0] == 0)
-      break;
-    line = end + 1;
-  }
-  return head;
-}
-
 void InitializeSuppressions() {
+  ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
+  g_ctx = new(placeholder_) SuppressionContext;
   const char *supp = ReadFile(flags()->suppressions);
-  g_suppressions = SuppressionParse(0, supp);
+  g_ctx->Parse(supp);
 #ifndef TSAN_GO
   supp = __tsan_default_suppressions();
-  g_suppressions = SuppressionParse(g_suppressions, supp);
+  g_ctx->Parse(supp);
 #endif
 }
 
-uptr IsSuppressed(ReportType typ, const ReportStack *stack) {
-  if (g_suppressions == 0 || stack == 0)
-    return 0;
-  SuppressionType stype;
+SuppressionType conv(ReportType typ) {
   if (typ == ReportTypeRace)
-    stype = SuppressionRace;
+    return SuppressionRace;
+  else if (typ == ReportTypeVptrRace)
+    return SuppressionRace;
+  else if (typ == ReportTypeUseAfterFree)
+    return SuppressionRace;
   else if (typ == ReportTypeThreadLeak)
-    stype = SuppressionThread;
+    return SuppressionThread;
   else if (typ == ReportTypeMutexDestroyLocked)
-    stype = SuppressionMutex;
+    return SuppressionMutex;
   else if (typ == ReportTypeSignalUnsafe)
-    stype = SuppressionSignal;
-  else
+    return SuppressionSignal;
+  else if (typ == ReportTypeErrnoInSignal)
+    return SuppressionNone;
+  Printf("ThreadSanitizer: unknown report type %d\n", typ),
+  Die();
+}
+
+uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
+  CHECK(g_ctx);
+  if (!g_ctx->SuppressionCount() || stack == 0) return 0;
+  SuppressionType stype = conv(typ);
+  if (stype == SuppressionNone)
     return 0;
+  Suppression *s;
   for (const ReportStack *frame = stack; frame; frame = frame->next) {
-    for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
-      if (stype == supp->type &&
-          (SuppressionMatch(supp->templ, frame->func) ||
-           SuppressionMatch(supp->templ, frame->file) ||
-           SuppressionMatch(supp->templ, frame->module))) {
-        DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
-        return frame->pc;
-      }
+    if (g_ctx->Match(frame->func, stype, &s) ||
+        g_ctx->Match(frame->file, stype, &s) ||
+        g_ctx->Match(frame->module, stype, &s)) {
+      DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
+      s->hit_count++;
+      *sp = s;
+      return frame->pc;
     }
   }
   return 0;
 }
+
+uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
+  CHECK(g_ctx);
+  if (!g_ctx->SuppressionCount() || loc == 0 ||
+      loc->type != ReportLocationGlobal)
+    return 0;
+  SuppressionType stype = conv(typ);
+  if (stype == SuppressionNone)
+    return 0;
+  Suppression *s;
+  if (g_ctx->Match(loc->name, stype, &s) ||
+      g_ctx->Match(loc->file, stype, &s) ||
+      g_ctx->Match(loc->module, stype, &s)) {
+      DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
+      s->hit_count++;
+      *sp = s;
+      return loc->addr;
+  }
+  return 0;
+}
+
+void PrintMatchedSuppressions() {
+  CHECK(g_ctx);
+  InternalMmapVector<Suppression *> matched(1);
+  g_ctx->GetMatched(&matched);
+  if (!matched.size())
+    return;
+  int hit_count = 0;
+  for (uptr i = 0; i < matched.size(); i++)
+    hit_count += matched[i]->hit_count;
+  Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
+         (int)internal_getpid());
+  for (uptr i = 0; i < matched.size(); i++) {
+    Printf("%d %s:%s\n", matched[i]->hit_count,
+           SuppressionTypeString(matched[i]->type), matched[i]->templ);
+  }
+}
 }  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_suppressions.h b/lib/tsan/rtl/tsan_suppressions.h
index c588316..c618b3d 100644
--- a/lib/tsan/rtl/tsan_suppressions.h
+++ b/lib/tsan/rtl/tsan_suppressions.h
@@ -13,30 +13,15 @@
 #ifndef TSAN_SUPPRESSIONS_H
 #define TSAN_SUPPRESSIONS_H
 
+#include "sanitizer_common/sanitizer_suppressions.h"
 #include "tsan_report.h"
 
 namespace __tsan {
 
 void InitializeSuppressions();
-void FinalizeSuppressions();
-uptr IsSuppressed(ReportType typ, const ReportStack *stack);
-
-// Exposed for testing.
-enum SuppressionType {
-  SuppressionRace,
-  SuppressionMutex,
-  SuppressionThread,
-  SuppressionSignal
-};
-
-struct Suppression {
-  Suppression *next;
-  SuppressionType type;
-  char *templ;
-};
-
-Suppression *SuppressionParse(Suppression *head, const char* supp);
-bool SuppressionMatch(char *templ, const char *str);
+void PrintMatchedSuppressions();
+uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp);
+uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp);
 
 }  // namespace __tsan
 
diff --git a/lib/tsan/rtl/tsan_symbolize.cc b/lib/tsan/rtl/tsan_symbolize.cc
index a58b958..1222606 100644
--- a/lib/tsan/rtl/tsan_symbolize.cc
+++ b/lib/tsan/rtl/tsan_symbolize.cc
@@ -116,4 +116,11 @@
   return ent;
 }
 
+void SymbolizeFlush() {
+  if (!IsSymbolizerAvailable())
+    return;
+  ScopedInSymbolizer in_symbolizer;
+  __sanitizer::FlushSymbolizer();
+}
+
 }  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_symbolize.h b/lib/tsan/rtl/tsan_symbolize.h
index 2919304..7bc6123 100644
--- a/lib/tsan/rtl/tsan_symbolize.h
+++ b/lib/tsan/rtl/tsan_symbolize.h
@@ -20,6 +20,7 @@
 
 ReportStack *SymbolizeCode(uptr addr);
 ReportLocation *SymbolizeData(uptr addr);
+void SymbolizeFlush();
 
 ReportStack *SymbolizeCodeAddr2Line(uptr addr);
 
diff --git a/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc b/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
index 76926e2..47f9e1f 100644
--- a/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
+++ b/lib/tsan/rtl/tsan_symbolize_addr2line_linux.cc
@@ -87,7 +87,8 @@
   DlIteratePhdrCtx *ctx = (DlIteratePhdrCtx*)arg;
   InternalScopedBuffer<char> tmp(128);
   if (ctx->is_first) {
-    internal_snprintf(tmp.data(), tmp.size(), "/proc/%d/exe", GetPid());
+    internal_snprintf(tmp.data(), tmp.size(), "/proc/%d/exe",
+                      (int)internal_getpid());
     info->dlpi_name = tmp.data();
   }
   ctx->is_first = false;
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index 94bad21..c6ddcdb 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -82,6 +82,7 @@
   // the hashmap anyway.
   if (PrimaryAllocator::PointerIsMine((void*)addr)) {
     MBlock *b = user_mblock(thr, (void*)addr);
+    CHECK_NE(b, 0);
     MBlock::ScopedLock l(b);
     SyncVar *res = 0;
     for (res = b->ListHead(); res; res = res->next) {
@@ -146,6 +147,7 @@
   }
   if (PrimaryAllocator::PointerIsMine((void*)addr)) {
     MBlock *b = user_mblock(thr, (void*)addr);
+    CHECK_NE(b, 0);
     SyncVar *res = 0;
     {
       MBlock::ScopedLock l(b);
diff --git a/lib/tsan/rtl/tsan_update_shadow_word_inl.h b/lib/tsan/rtl/tsan_update_shadow_word_inl.h
index e7c036c..a11c9bc 100644
--- a/lib/tsan/rtl/tsan_update_shadow_word_inl.h
+++ b/lib/tsan/rtl/tsan_update_shadow_word_inl.h
@@ -57,8 +57,7 @@
     goto RACE;
   }
   // Do the memory access intersect?
-  // In Go all memory accesses are 1 byte, so there can be no intersections.
-  if (kCppMode && Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
+  if (Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
     StatInc(thr, StatShadowIntersect);
     if (Shadow::TidsAreEqual(old, cur)) {
       StatInc(thr, StatShadowSameThread);
diff --git a/lib/tsan/rtl/tsan_vector.h b/lib/tsan/rtl/tsan_vector.h
index 64328d0..fa236b1 100644
--- a/lib/tsan/rtl/tsan_vector.h
+++ b/lib/tsan/rtl/tsan_vector.h
@@ -64,6 +64,11 @@
     return &end_[-1];
   }
 
+  void PopBack() {
+    DCHECK_GT(end_, begin_);
+    end_--;
+  }
+
   void Resize(uptr size) {
     uptr old_size = Size();
     EnsureSize(size);
diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt
index 0fcc6b2..7cc079f 100644
--- a/lib/tsan/tests/CMakeLists.txt
+++ b/lib/tsan/tests/CMakeLists.txt
@@ -12,9 +12,9 @@
     add_unittest(TsanUnitTests ${testname} ${ARGN})
     # Link with TSan runtime.
     target_link_libraries(${testname} clang_rt.tsan-x86_64)
-    # Build tests with PIE and debug info.
-    set_property(TARGET ${testname} APPEND_STRING
-      PROPERTY COMPILE_FLAGS " -fPIE -g")
+    # Compile tests with the same flags as TSan runtime.
+    set_target_compile_flags(${testname} ${TSAN_CFLAGS})
+    # Link tests with -pie.
     set_property(TARGET ${testname} APPEND_STRING
       PROPERTY LINK_FLAGS " -pie")
   endif()
diff --git a/lib/tsan/tests/unit/CMakeLists.txt b/lib/tsan/tests/unit/CMakeLists.txt
index 52ebdb8..1cd2abe 100644
--- a/lib/tsan/tests/unit/CMakeLists.txt
+++ b/lib/tsan/tests/unit/CMakeLists.txt
@@ -3,10 +3,8 @@
   tsan_flags_test.cc
   tsan_mman_test.cc
   tsan_mutex_test.cc
-  tsan_platform_test.cc
   tsan_shadow_test.cc
   tsan_stack_test.cc
-  tsan_suppressions_test.cc
   tsan_sync_test.cc
   tsan_vector_test.cc
   )
diff --git a/lib/tsan/tests/unit/tsan_mutexset_test.cc b/lib/tsan/tests/unit/tsan_mutexset_test.cc
index da1ae2e..335a774 100644
--- a/lib/tsan/tests/unit/tsan_mutexset_test.cc
+++ b/lib/tsan/tests/unit/tsan_mutexset_test.cc
@@ -115,7 +115,8 @@
   EXPECT_EQ(mset.Size(), MutexSet::kMaxSize);
   for (uptr i = 0; i < MutexSet::kMaxSize; i++) {
     if (i == 0)
-      Expect(mset, i, 63, true, 64, 2);
+      Expect(mset, i, MutexSet::kMaxSize - 1,
+             true, MutexSet::kMaxSize, 2);
     else if (i == MutexSet::kMaxSize - 1)
       Expect(mset, i, 100, true, 200, 1);
     else
diff --git a/lib/tsan/tests/unit/tsan_platform_test.cc b/lib/tsan/tests/unit/tsan_platform_test.cc
deleted file mode 100644
index 733cc54..0000000
--- a/lib/tsan/tests/unit/tsan_platform_test.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-//===-- tsan_platform_test.cc ---------------------------------------------===//
-//
-//                     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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_libc.h"
-#include "tsan_platform.h"
-#include "tsan_rtl.h"
-#include "gtest/gtest.h"
-
-namespace __tsan {
-
-static void TestThreadInfo(bool main) {
-  ScopedInRtl in_rtl;
-  uptr stk_addr = 0;
-  uptr stk_size = 0;
-  uptr tls_addr = 0;
-  uptr tls_size = 0;
-  GetThreadStackAndTls(main, &stk_addr, &stk_size, &tls_addr, &tls_size);
-  // Printf("stk=%zx-%zx(%zu)\n", stk_addr, stk_addr + stk_size, stk_size);
-  // Printf("tls=%zx-%zx(%zu)\n", tls_addr, tls_addr + tls_size, tls_size);
-
-  int stack_var;
-  EXPECT_NE(stk_addr, (uptr)0);
-  EXPECT_NE(stk_size, (uptr)0);
-  EXPECT_GT((uptr)&stack_var, stk_addr);
-  EXPECT_LT((uptr)&stack_var, stk_addr + stk_size);
-
-  static __thread int thread_var;
-  EXPECT_NE(tls_addr, (uptr)0);
-  EXPECT_NE(tls_size, (uptr)0);
-  EXPECT_GT((uptr)&thread_var, tls_addr);
-  EXPECT_LT((uptr)&thread_var, tls_addr + tls_size);
-
-  // Ensure that tls and stack do not intersect.
-  uptr tls_end = tls_addr + tls_size;
-  EXPECT_TRUE(tls_addr < stk_addr || tls_addr >= stk_addr + stk_size);
-  EXPECT_TRUE(tls_end  < stk_addr || tls_end  >=  stk_addr + stk_size);
-  EXPECT_TRUE((tls_addr < stk_addr) == (tls_end  < stk_addr));
-}
-
-static void *WorkerThread(void *arg) {
-  TestThreadInfo(false);
-  return 0;
-}
-
-TEST(Platform, ThreadInfoMain) {
-  TestThreadInfo(true);
-}
-
-TEST(Platform, ThreadInfoWorker) {
-  pthread_t t;
-  pthread_create(&t, 0, WorkerThread, 0);
-  pthread_join(t, 0);
-}
-
-}  // namespace __tsan
diff --git a/lib/tsan/tests/unit/tsan_suppressions_test.cc b/lib/tsan/tests/unit/tsan_suppressions_test.cc
deleted file mode 100644
index decfa32..0000000
--- a/lib/tsan/tests/unit/tsan_suppressions_test.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-//===-- tsan_suppressions_test.cc -----------------------------------------===//
-//
-//                     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 ThreadSanitizer (TSan), a race detector.
-//
-//===----------------------------------------------------------------------===//
-#include "tsan_suppressions.h"
-#include "tsan_rtl.h"
-#include "gtest/gtest.h"
-
-#include <string.h>
-
-namespace __tsan {
-
-TEST(Suppressions, Parse) {
-  ScopedInRtl in_rtl;
-  Suppression *supp0 = SuppressionParse(0,
-    "race:foo\n"
-    " 	race:bar\n"  // NOLINT
-    "race:baz	 \n"  // NOLINT
-    "# a comment\n"
-    "race:quz\n"
-  );  // NOLINT
-  Suppression *supp = supp0;
-  EXPECT_EQ(supp->type, SuppressionRace);
-  EXPECT_EQ(0, strcmp(supp->templ, "quz"));
-  supp = supp->next;
-  EXPECT_EQ(supp->type, SuppressionRace);
-  EXPECT_EQ(0, strcmp(supp->templ, "baz"));
-  supp = supp->next;
-  EXPECT_EQ(supp->type, SuppressionRace);
-  EXPECT_EQ(0, strcmp(supp->templ, "bar"));
-  supp = supp->next;
-  EXPECT_EQ(supp->type, SuppressionRace);
-  EXPECT_EQ(0, strcmp(supp->templ, "foo"));
-  supp = supp->next;
-  EXPECT_EQ((Suppression*)0, supp);
-}
-
-TEST(Suppressions, Parse2) {
-  ScopedInRtl in_rtl;
-  Suppression *supp0 = SuppressionParse(0,
-    "  	# first line comment\n"  // NOLINT
-    " 	race:bar 	\n"  // NOLINT
-    "race:baz* *baz\n"
-    "# a comment\n"
-    "# last line comment\n"
-  );  // NOLINT
-  Suppression *supp = supp0;
-  EXPECT_EQ(supp->type, SuppressionRace);
-  EXPECT_EQ(0, strcmp(supp->templ, "baz* *baz"));
-  supp = supp->next;
-  EXPECT_EQ(supp->type, SuppressionRace);
-  EXPECT_EQ(0, strcmp(supp->templ, "bar"));
-  supp = supp->next;
-  EXPECT_EQ((Suppression*)0, supp);
-}
-
-TEST(Suppressions, Parse3) {
-  ScopedInRtl in_rtl;
-  Suppression *supp0 = SuppressionParse(0,
-    "# last suppression w/o line-feed\n"
-    "race:foo\n"
-    "race:bar"
-  );  // NOLINT
-  Suppression *supp = supp0;
-  EXPECT_EQ(supp->type, SuppressionRace);
-  EXPECT_EQ(0, strcmp(supp->templ, "bar"));
-  supp = supp->next;
-  EXPECT_EQ(supp->type, SuppressionRace);
-  EXPECT_EQ(0, strcmp(supp->templ, "foo"));
-  supp = supp->next;
-  EXPECT_EQ((Suppression*)0, supp);
-}
-
-TEST(Suppressions, ParseType) {
-  ScopedInRtl in_rtl;
-  Suppression *supp0 = SuppressionParse(0,
-    "race:foo\n"
-    "thread:bar\n"
-    "mutex:baz\n"
-    "signal:quz\n"
-  );  // NOLINT
-  Suppression *supp = supp0;
-  EXPECT_EQ(supp->type, SuppressionSignal);
-  EXPECT_EQ(0, strcmp(supp->templ, "quz"));
-  supp = supp->next;
-  EXPECT_EQ(supp->type, SuppressionMutex);
-  EXPECT_EQ(0, strcmp(supp->templ, "baz"));
-  supp = supp->next;
-  EXPECT_EQ(supp->type, SuppressionThread);
-  EXPECT_EQ(0, strcmp(supp->templ, "bar"));
-  supp = supp->next;
-  EXPECT_EQ(supp->type, SuppressionRace);
-  EXPECT_EQ(0, strcmp(supp->templ, "foo"));
-  supp = supp->next;
-  EXPECT_EQ((Suppression*)0, supp);
-}
-
-static bool MyMatch(const char *templ, const char *func) {
-  char tmp[1024];
-  strcpy(tmp, templ);  // NOLINT
-  return SuppressionMatch(tmp, func);
-}
-
-TEST(Suppressions, Match) {
-  EXPECT_TRUE(MyMatch("foobar", "foobar"));
-  EXPECT_TRUE(MyMatch("foobar", "prefix_foobar_postfix"));
-  EXPECT_TRUE(MyMatch("*foobar*", "prefix_foobar_postfix"));
-  EXPECT_TRUE(MyMatch("foo*bar", "foo_middle_bar"));
-  EXPECT_TRUE(MyMatch("foo*bar", "foobar"));
-  EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_bar_another_baz"));
-  EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_barbaz"));
-
-  EXPECT_FALSE(MyMatch("foo", "baz"));
-  EXPECT_FALSE(MyMatch("foobarbaz", "foobar"));
-  EXPECT_FALSE(MyMatch("foobarbaz", "barbaz"));
-  EXPECT_FALSE(MyMatch("foo*bar", "foobaz"));
-  EXPECT_FALSE(MyMatch("foo*bar", "foo_baz"));
-}
-
-}  // namespace __tsan
diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt
index b549153..c8470bc 100644
--- a/lib/ubsan/CMakeLists.txt
+++ b/lib/ubsan/CMakeLists.txt
@@ -3,9 +3,12 @@
 set(UBSAN_SOURCES
   ubsan_diag.cc
   ubsan_handlers.cc
+  ubsan_value.cc
+  )
+
+set(UBSAN_CXX_SOURCES
   ubsan_handlers_cxx.cc
   ubsan_type_hash.cc
-  ubsan_value.cc
   )
 
 include_directories(..)
@@ -21,18 +24,27 @@
   # Build universal binary on APPLE.
   add_compiler_rt_osx_static_runtime(clang_rt.ubsan_osx
     ARCH ${UBSAN_SUPPORTED_ARCH}
-    SOURCES ${UBSAN_SOURCES}
+    SOURCES ${UBSAN_SOURCES} ${UBSAN_CXX_SOURCES}
             $<TARGET_OBJECTS:RTSanitizerCommon.osx>
     CFLAGS ${UBSAN_CFLAGS})
   list(APPEND UBSAN_RUNTIME_LIBRARIES clang_rt.ubsan_osx)
 else()
   # Build separate libraries for each target.
   foreach(arch ${UBSAN_SUPPORTED_ARCH})
+    # Main UBSan runtime.
     add_compiler_rt_static_runtime(clang_rt.ubsan-${arch} ${arch}
       SOURCES ${UBSAN_SOURCES}
-              $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
-      CFLAGS ${UBSAN_CFLAGS})
-    list(APPEND UBSAN_RUNTIME_LIBRARIES clang_rt.ubsan-${arch})
+      CFLAGS ${UBSAN_CFLAGS}
+      SYMS ubsan.syms)
+    # C++-specific parts of UBSan runtime. Requires a C++ ABI library.
+    add_compiler_rt_static_runtime(clang_rt.ubsan_cxx-${arch} ${arch}
+      SOURCES ${UBSAN_CXX_SOURCES}
+      CFLAGS ${UBSAN_CFLAGS}
+      SYMS ubsan.syms)
+    list(APPEND UBSAN_RUNTIME_LIBRARIES
+           clang_rt.san-${arch}
+           clang_rt.ubsan-${arch}
+           clang_rt.ubsan_cxx-${arch})
   endforeach()
 endif()
 
diff --git a/lib/ubsan/Makefile.mk b/lib/ubsan/Makefile.mk
index 5702e0e..d5561f4 100644
--- a/lib/ubsan/Makefile.mk
+++ b/lib/ubsan/Makefile.mk
@@ -11,6 +11,8 @@
 SubDirs :=
 
 Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+CXXSources := ubsan_type_hash.cc ubsan_handlers_cxx.cc
+CSources := $(filter-out $(CXXSources),$(Sources))
 ObjNames := $(Sources:%.cc=%.o)
 
 Implementation := Generic
@@ -20,4 +22,5 @@
 Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
 
 # Define a convenience variable for all the ubsan functions.
-UbsanFunctions := $(Sources:%.cc=%)
+UbsanFunctions := $(CSources:%.cc=%)
+UbsanCXXFunctions := $(CXXSources:%.cc=%)
diff --git a/lib/ubsan/lit_tests/CMakeLists.txt b/lib/ubsan/lit_tests/CMakeLists.txt
index 565c523..7e1a13c 100644
--- a/lib/ubsan/lit_tests/CMakeLists.txt
+++ b/lib/ubsan/lit_tests/CMakeLists.txt
@@ -7,9 +7,8 @@
   # Run UBSan output tests only if we're sure that clang would produce
   # working binaries.
   set(UBSAN_TEST_DEPS
-    clang clang-headers FileCheck count not
-    ${UBSAN_RUNTIME_LIBRARIES}
-    )
+    ${SANITIZER_COMMON_LIT_TEST_DEPS}
+    ${UBSAN_RUNTIME_LIBRARIES})
   set(UBSAN_TEST_PARAMS
     ubsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
     )
diff --git a/lib/ubsan/lit_tests/Float/cast-overflow.cpp b/lib/ubsan/lit_tests/Float/cast-overflow.cpp
index 63410dc..8d9120d 100644
--- a/lib/ubsan/lit_tests/Float/cast-overflow.cpp
+++ b/lib/ubsan/lit_tests/Float/cast-overflow.cpp
@@ -9,7 +9,6 @@
 // RUN: %t 6 2>&1 | FileCheck %s --check-prefix=CHECK-6
 // FIXME: %t 7 2>&1 | FileCheck %s --check-prefix=CHECK-7
 // RUN: %t 8 2>&1 | FileCheck %s --check-prefix=CHECK-8
-// RUN: %t 9 2>&1 | FileCheck %s --check-prefix=CHECK-9
 
 // This test assumes float and double are IEEE-754 single- and double-precision.
 
@@ -36,6 +35,9 @@
   (void)(float)FloatMaxAsUInt128; // ok
 #endif
 
+  float NearlyMinusOne = -0.99999;
+  unsigned Zero = NearlyMinusOne; // ok
+
   // Build a '+Inf'.
   char InfVal[] = { 0x00, 0x00, 0x80, 0x7f };
   float Inf;
@@ -46,6 +48,8 @@
   float NaN;
   memcpy(&NaN, NaNVal, 4);
 
+  double DblInf = (double)Inf; // ok
+
   switch (argv[1][0]) {
     // FIXME: Produce a source location for these checks and test for it here.
 
@@ -59,8 +63,8 @@
     // CHECK-1: runtime error: value -2.14748{{.*}} is outside the range of representable values of type 'int'
     return MinFloatRepresentableAsInt - 0x100;
   case '2':
-    // CHECK-2: runtime error: value -0.001 is outside the range of representable values of type 'unsigned int'
-    return (unsigned)-0.001;
+    // CHECK-2: runtime error: value -1 is outside the range of representable values of type 'unsigned int'
+    return (unsigned)-1.0;
   case '3':
     // CHECK-3: runtime error: value 4.2949{{.*}} is outside the range of representable values of type 'unsigned int'
     return (unsigned)(MaxFloatRepresentableAsUInt + 0x100);
@@ -91,8 +95,5 @@
   case '8':
     // CHECK-8: runtime error: value 1e+39 is outside the range of representable values of type 'float'
     return (float)1e39;
-  case '9':
-    // CHECK-9: runtime error: value {{.*}} is outside the range of representable values of type 'double'
-    return (double)Inf;
   }
 }
diff --git a/lib/ubsan/lit_tests/TypeCheck/vptr.cpp b/lib/ubsan/lit_tests/TypeCheck/vptr.cpp
index 109e7a8..3159f36 100644
--- a/lib/ubsan/lit_tests/TypeCheck/vptr.cpp
+++ b/lib/ubsan/lit_tests/TypeCheck/vptr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-cxx -fsanitize=vptr %s -O3 -o %t
+// RUN: %clang --driver-mode=g++ -fsanitize=vptr %s -O3 -o %t
 // RUN: %t rT && %t mT && %t fT && %t cT
 // RUN: %t rU && %t mU && %t fU && %t cU
 // RUN: %t rS && %t rV && %t oV
diff --git a/lib/ubsan/lit_tests/lit.cfg b/lib/ubsan/lit_tests/lit.cfg
index 9fd3a1a..f3fc646 100644
--- a/lib/ubsan/lit_tests/lit.cfg
+++ b/lib/ubsan/lit_tests/lit.cfg
@@ -2,6 +2,14 @@
 
 import os
 
+def get_required_attr(config, attr_name):
+  attr_value = getattr(config, attr_name, None)
+  if not attr_value:
+    lit.fatal("No attribute %r in test configuration! You may need to run "
+              "tests from your build directory or add this attribute "
+              "to lit.site.cfg " % attr_name)
+  return attr_value
+
 # Setup config name.
 config.name = 'UndefinedBehaviorSanitizer'
 
@@ -30,14 +38,6 @@
   if not llvm_config:
     DisplayNoConfigMessage()
 
-  # Validate that llvm-config points to the same source tree.
-  llvm_src_root = lit.util.capture(["llvm-config", "--src-root"]).strip()
-  ubsan_test_src_root = os.path.join(llvm_src_root, "projects", "compiler-rt",
-                                     "lib", "ubsan", "lit_tests")
-  if (os.path.realpath(ubsan_test_src_root) !=
-      os.path.realpath(config.test_source_root)):
-    DisplayNoConfigMessage()
-
   # Find out the presumed location of generated site config.
   llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip()
   ubsan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt",
@@ -48,13 +48,8 @@
   lit.load_config(config, ubsan_site_cfg)
   raise SystemExit
 
-# Setup attributes common for all compiler-rt projects.
-compiler_rt_lit_cfg = os.path.join(llvm_src_root, "projects", "compiler-rt",
-                                   "lib", "lit.common.cfg")
-if not compiler_rt_lit_cfg or not os.path.exists(compiler_rt_lit_cfg):
-  lit.fatal("Can't find common compiler-rt lit config at: %r"
-            % compiler_rt_lit_cfg)
-lit.load_config(config, compiler_rt_lit_cfg)
+# Define %clang substitution to use in test RUN lines.
+config.substitutions.append( ("%clang ", (" " + config.clang + " ")) )
 
 # Default test suffixes.
 config.suffixes = ['.c', '.cc', '.cpp']
@@ -63,3 +58,5 @@
 # Linux and Darwin only.
 if config.host_os not in ['Linux', 'Darwin']:
   config.unsupported = True
+
+config.pipefail = False
diff --git a/lib/ubsan/lit_tests/lit.site.cfg.in b/lib/ubsan/lit_tests/lit.site.cfg.in
index b1c6ccf..a212393 100644
--- a/lib/ubsan/lit_tests/lit.site.cfg.in
+++ b/lib/ubsan/lit_tests/lit.site.cfg.in
@@ -1,19 +1,8 @@
 ## Autogenerated by LLVM/Clang configuration.
 # Do not edit!
 
-config.clang = "@LLVM_BINARY_DIR@/bin/clang"
-config.host_os = "@HOST_OS@"
-config.llvm_src_root = "@LLVM_SOURCE_DIR@"
-config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
-config.target_triple = "@TARGET_TRIPLE@"
+# Load common config for all compiler-rt lit tests.
+lit.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
 
-# LLVM tools dir can be passed in lit parameters, so try to
-# apply substitution.
-try:
-  config.llvm_tools_dir = config.llvm_tools_dir % lit.params
-except KeyError,e:
-  key, = e.args
-  lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
-
-# Let the main config do the real work.
+# Load tool-specific config that would do the real work.
 lit.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
diff --git a/lib/ubsan/ubsan.syms b/lib/ubsan/ubsan.syms
new file mode 100644
index 0000000..e74de33
--- /dev/null
+++ b/lib/ubsan/ubsan.syms
@@ -0,0 +1 @@
+{ __ubsan_*; };
diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc
index 0727ed7..3f92761 100644
--- a/lib/ubsan/ubsan_diag.cc
+++ b/lib/ubsan/ubsan_diag.cc
@@ -31,7 +31,7 @@
   if (!SymbolizeCode(Loc, &Info, 1) || !Info.module || !*Info.module)
     return Location(Loc);
 
-  if (!Info.function)
+  if (!Info.file)
     return ModuleLocation(Info.module, Info.module_offset);
 
   return SourceLocation(Info.file, Info.line, Info.column);
@@ -237,6 +237,7 @@
 
 Diag::~Diag() {
   __sanitizer::AnsiColorDecorator Decor(PrintsToTty());
+  SpinMutexLock l(&CommonSanitizerReportMutex);
   Printf(Decor.Bold());
 
   renderLocation(Loc);
diff --git a/lib/ubsan/ubsan_type_hash.cc b/lib/ubsan/ubsan_type_hash.cc
index 7a9cd28..b27aefc 100644
--- a/lib/ubsan/ubsan_type_hash.cc
+++ b/lib/ubsan/ubsan_type_hash.cc
@@ -116,7 +116,7 @@
 static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
                                   const abi::__class_type_info *Base,
                                   sptr Offset) {
-  if (Derived == Base)
+  if (Derived->__type_name == Base->__type_name)
     return Offset == 0;
 
   if (const abi::__si_class_type_info *SI =
diff --git a/lib/ubsan/ubsan_value.cc b/lib/ubsan/ubsan_value.cc
index f17c589..5d77350 100644
--- a/lib/ubsan/ubsan_value.cc
+++ b/lib/ubsan/ubsan_value.cc
@@ -13,6 +13,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ubsan_value.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
 
 using namespace __ubsan;
 
@@ -66,16 +68,34 @@
 /// them to be passed in floating-point registers, so this has little cost).
 FloatMax Value::getFloatValue() const {
   CHECK(getType().isFloatTy());
-  switch (getType().getFloatBitWidth()) {
+  if (isInlineFloat()) {
+    switch (getType().getFloatBitWidth()) {
 #if 0
-  // FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion
-  //        from this to 'long double'.
-  case 16: return *reinterpret_cast<__fp16*>(Val);
+      // FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion
+      //        from '__fp16' to 'long double'.
+      case 16: {
+        __fp16 Value;
+        internal_memcpy(&Value, &Val, 4);
+        return Value;
+      }
 #endif
-  case 32: return *reinterpret_cast<float*>(Val);
-  case 64: return *reinterpret_cast<double*>(Val);
-  case 80: return *reinterpret_cast<long double*>(Val);
-  case 128: return *reinterpret_cast<long double*>(Val);
+      case 32: {
+        float Value;
+        internal_memcpy(&Value, &Val, 4);
+        return Value;
+      }
+      case 64: {
+        double Value;
+        internal_memcpy(&Value, &Val, 8);
+        return Value;
+      }
+    }
+  } else {
+    switch (getType().getFloatBitWidth()) {
+    case 64: return *reinterpret_cast<double*>(Val);
+    case 80: return *reinterpret_cast<long double*>(Val);
+    case 128: return *reinterpret_cast<long double*>(Val);
+    }
   }
   UNREACHABLE("unexpected floating point bit width");
 }
diff --git a/lib/ubsan/ubsan_value.h b/lib/ubsan/ubsan_value.h
index e673f7a..54ed5ad 100644
--- a/lib/ubsan/ubsan_value.h
+++ b/lib/ubsan/ubsan_value.h
@@ -108,7 +108,8 @@
     /// integer otherwise.
     TK_Integer = 0x0000,
     /// A floating-point type. Low 16 bits are bit width. The value
-    /// representation is a pointer to the floating-point value.
+    /// representation is that of bitcasting the floating-point value to an
+    /// integer type.
     TK_Float = 0x0001,
     /// Any other type. The value representation is unspecified.
     TK_Unknown = 0xffff
@@ -162,6 +163,14 @@
     return Bits <= InlineBits;
   }
 
+  /// Is \c Val a (zero-extended) integer representation of a float?
+  bool isInlineFloat() const {
+    CHECK(getType().isFloatTy());
+    const unsigned InlineBits = sizeof(ValueHandle) * 8;
+    const unsigned Bits = getType().getFloatBitWidth();
+    return Bits <= InlineBits;
+  }
+
 public:
   Value(const TypeDescriptor &Type, ValueHandle Val) : Type(Type), Val(Val) {}
 
diff --git a/make/AppleBI.mk b/make/AppleBI.mk
index bb78853..d3d4771 100644
--- a/make/AppleBI.mk
+++ b/make/AppleBI.mk
@@ -61,6 +61,7 @@
 	   -Wl,-upward-lunwind \
 	   -Wl,-upward-lsystem_m \
 	   -Wl,-upward-lsystem_c \
+	   -Wl,-upward-lsystem_platform \
 	   -Wl,-ldyld \
 	   -Wl,-lsystem_kernel \
 	   -L$(SDKROOT)/usr/lib/system \
diff --git a/make/platform/clang_darwin.mk b/make/platform/clang_darwin.mk
index 61c5b53..fc599f1 100644
--- a/make/platform/clang_darwin.mk
+++ b/make/platform/clang_darwin.mk
@@ -70,9 +70,6 @@
 UniversalArchs.profile_ios := $(call CheckArches,i386 x86_64 armv7,profile_ios)
 
 # Configurations which define the ASAN support functions.
-Configs += asan_osx
-UniversalArchs.asan_osx := $(call CheckArches,i386 x86_64,asan_osx)
-
 Configs += asan_osx_dynamic
 UniversalArchs.asan_osx_dynamic := $(call CheckArches,i386 x86_64,asan_osx_dynamic)
 
@@ -83,14 +80,12 @@
 # object files. If we are on that platform, strip out all ARM archs. We still
 # build the libraries themselves so that Clang can find them where it expects
 # them, even though they might not have an expected slice.
-ifneq ($(shell which sw_vers),)
-ifneq ($(shell sw_vers -productVersion | grep 10.6),)
+ifneq ($(shell test -x /usr/bin/sw_vers && sw_vers -productVersion | grep 10.6),)
 UniversalArchs.ios := $(filter-out armv7, $(UniversalArchs.ios))
 UniversalArchs.cc_kext := $(filter-out armv7, $(UniversalArchs.cc_kext))
 UniversalArchs.cc_kext_ios5 := $(filter-out armv7, $(UniversalArchs.cc_kext_ios5))
 UniversalArchs.profile_ios := $(filter-out armv7, $(UniversalArchs.profile_ios))
 endif
-endif
 
 # If RC_SUPPORTED_ARCHS is defined, treat it as a list of the architectures we
 # are intended to support and limit what we try to build to that.
@@ -118,9 +113,9 @@
 # supported deployment target -- nothing in the compiler-rt libraries should
 # actually depend on the deployment target.
 OSX_DEPLOYMENT_ARGS := -mmacosx-version-min=10.4
-IOS_DEPLOYMENT_ARGS := -miphoneos-version-min=1.0
-IOS6_DEPLOYMENT_ARGS := -miphoneos-version-min=6.0
-IOSSIM_DEPLOYMENT_ARGS := -miphoneos-version-min=1.0
+IOS_DEPLOYMENT_ARGS := -mios-version-min=1.0
+IOS6_DEPLOYMENT_ARGS := -mios-version-min=6.0
+IOSSIM_DEPLOYMENT_ARGS := -mios-simulator-version-min=1.0
 
 # Use our stub SDK as the sysroot to support more portable building.
 OSX_DEPLOYMENT_ARGS += -isysroot $(ProjSrcRoot)/SDKs/darwin
@@ -131,14 +126,13 @@
 CFLAGS.eprintf		:= $(CFLAGS) $(OSX_DEPLOYMENT_ARGS)
 CFLAGS.10.4		:= $(CFLAGS) $(OSX_DEPLOYMENT_ARGS)
 # FIXME: We can't build ASAN with our stub SDK yet.
-CFLAGS.asan_osx         := $(CFLAGS) -mmacosx-version-min=10.5 -fno-builtin \
-                           -fno-rtti -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
 CFLAGS.asan_osx_dynamic := \
-	$(CFLAGS) -mmacosx-version-min=10.5 -fno-builtin \
+	$(CFLAGS) -mmacosx-version-min=10.6 -fno-builtin \
+	-gline-tables-only \
 	-DMAC_INTERPOSE_FUNCTIONS=1 \
   -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
 
-CFLAGS.ubsan_osx	:= $(CFLAGS) -mmacosx-version-min=10.5 -fno-builtin
+CFLAGS.ubsan_osx	:= $(CFLAGS) -mmacosx-version-min=10.6 -fno-builtin
 
 CFLAGS.ios.i386		:= $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
 CFLAGS.ios.x86_64	:= $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
@@ -186,13 +180,12 @@
 FUNCTIONS.profile_osx := GCDAProfiling
 FUNCTIONS.profile_ios := GCDAProfiling
 
-FUNCTIONS.asan_osx := $(AsanFunctions) $(InterceptionFunctions) \
-                                       $(SanitizerCommonFunctions)
 FUNCTIONS.asan_osx_dynamic := $(AsanFunctions) $(InterceptionFunctions) \
                               $(SanitizerCommonFunctions) \
 	                      $(AsanDynamicFunctions)
 
-FUNCTIONS.ubsan_osx := $(UbsanFunctions) $(SanitizerCommonFunctions)
+FUNCTIONS.ubsan_osx := $(UbsanFunctions) $(UbsanCXXFunctions) \
+                       $(SanitizerCommonFunctions)
 
 CCKEXT_COMMON_FUNCTIONS := \
 	absvdi2 \
diff --git a/make/platform/clang_linux.mk b/make/platform/clang_linux.mk
index d3ddc71..b16e794 100644
--- a/make/platform/clang_linux.mk
+++ b/make/platform/clang_linux.mk
@@ -8,15 +8,13 @@
 
 # We don't currently have any general purpose way to target architectures other
 # than the compiler defaults (because there is no generalized way to invoke
-# cross compilers). For now, we just find the target archicture of the compiler
-# and only define configurations we know that compiler can generate.
+# cross compilers). For now, we just find the target architecture of the
+# compiler and only define configurations we know that compiler can generate.
 CompilerTargetTriple := $(shell \
 	$(CC) -v 2>&1 | grep 'Target:' | cut -d' ' -f2)
-ifneq ($(DEBUGMAKE),)
 ifeq ($(CompilerTargetTriple),)
 $(error "unable to infer compiler target triple for $(CC)")
 endif
-endif
 
 # Only define configs if we detected a linux target.
 ifneq ($(findstring -linux-,$(CompilerTargetTriple)),)
@@ -51,23 +49,27 @@
 
 # Build runtime libraries for i386.
 ifeq ($(call contains,$(SupportedArches),i386),true)
-Configs += full-i386 profile-i386 asan-i386 ubsan-i386
+Configs += full-i386 profile-i386 san-i386 asan-i386 ubsan-i386 ubsan_cxx-i386
 Arch.full-i386 := i386
 Arch.profile-i386 := i386
+Arch.san-i386 := i386
 Arch.asan-i386 := i386
 Arch.ubsan-i386 := i386
+Arch.ubsan_cxx-i386 := i386
 endif
 
 # Build runtime libraries for x86_64.
 ifeq ($(call contains,$(SupportedArches),x86_64),true)
-Configs += full-x86_64 profile-x86_64 asan-x86_64 tsan-x86_64 msan-x86_64 \
-           ubsan-x86_64
+Configs += full-x86_64 profile-x86_64 san-x86_64 asan-x86_64 tsan-x86_64 \
+           msan-x86_64 ubsan-x86_64 ubsan_cxx-x86_64
 Arch.full-x86_64 := x86_64
 Arch.profile-x86_64 := x86_64
+Arch.san-x86_64 := x86_64
 Arch.asan-x86_64 := x86_64
 Arch.tsan-x86_64 := x86_64
 Arch.msan-x86_64 := x86_64
 Arch.ubsan-x86_64 := x86_64
+Arch.ubsan_cxx-x86_64 := x86_64
 endif
 
 ifneq ($(LLVM_ANDROID_TOOLCHAIN_DIR),)
@@ -81,53 +83,60 @@
 ###
 
 CFLAGS := -Wall -Werror -O3 -fomit-frame-pointer
+SANITIZER_CFLAGS := -fPIE -fno-builtin -gline-tables-only
 
 CFLAGS.full-i386 := $(CFLAGS) -m32
 CFLAGS.full-x86_64 := $(CFLAGS) -m64
 CFLAGS.profile-i386 := $(CFLAGS) -m32
 CFLAGS.profile-x86_64 := $(CFLAGS) -m64
-CFLAGS.asan-i386 := $(CFLAGS) -m32 -fPIE -fno-builtin -fno-rtti \
+CFLAGS.san-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS) -fno-rtti
+CFLAGS.san-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti
+CFLAGS.asan-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS) -fno-rtti \
                     -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
-CFLAGS.asan-x86_64 := $(CFLAGS) -m64 -fPIE -fno-builtin -fno-rtti \
+CFLAGS.asan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti \
                     -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
-CFLAGS.tsan-x86_64 := $(CFLAGS) -m64 -fPIE -fno-builtin -fno-rtti
-CFLAGS.msan-x86_64 := $(CFLAGS) -m64 -fPIE -fno-builtin -fno-rtti
-CFLAGS.ubsan-i386 := $(CFLAGS) -m32 -fPIE -fno-builtin
-CFLAGS.ubsan-x86_64 := $(CFLAGS) -m64 -fPIE -fno-builtin
+CFLAGS.tsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti
+CFLAGS.msan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti
+CFLAGS.ubsan-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS) -fno-rtti
+CFLAGS.ubsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti
+CFLAGS.ubsan_cxx-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS)
+CFLAGS.ubsan_cxx-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS)
 
 SHARED_LIBRARY.asan-arm-android := 1
 ANDROID_COMMON_FLAGS := -target arm-linux-androideabi \
 	--sysroot=$(LLVM_ANDROID_TOOLCHAIN_DIR)/sysroot \
 	-B$(LLVM_ANDROID_TOOLCHAIN_DIR)
 CFLAGS.asan-arm-android := $(CFLAGS) -fPIC -fno-builtin \
-	$(ANDROID_COMMON_FLAGS) -mllvm -arm-enable-ehabi
+	$(ANDROID_COMMON_FLAGS) -mllvm -arm-enable-ehabi -fno-rtti
 LDFLAGS.asan-arm-android := $(LDFLAGS) $(ANDROID_COMMON_FLAGS) -ldl \
 	-Wl,-soname=libclang_rt.asan-arm-android.so
 
 # Use our stub SDK as the sysroot to support more portable building. For now we
-# just do this for the non-ASAN modules, because the stub SDK doesn't have
-# enough support to build ASAN.
+# just do this for the core module, because the stub SDK doesn't have
+# enough support to build the sanitizers or profile runtimes.
 CFLAGS.full-i386 += --sysroot=$(ProjSrcRoot)/SDKs/linux
 CFLAGS.full-x86_64 += --sysroot=$(ProjSrcRoot)/SDKs/linux
-CFLAGS.profile-i386 += --sysroot=$(ProjSrcRoot)/SDKs/linux
-CFLAGS.profile-x86_64 += --sysroot=$(ProjSrcRoot)/SDKs/linux
 
 FUNCTIONS.full-i386 := $(CommonFunctions) $(ArchFunctions.i386)
 FUNCTIONS.full-x86_64 := $(CommonFunctions) $(ArchFunctions.x86_64)
 FUNCTIONS.profile-i386 := GCDAProfiling
 FUNCTIONS.profile-x86_64 := GCDAProfiling
+FUNCTIONS.san-i386 := $(SanitizerCommonFunctions)
+FUNCTIONS.san-x86_64 := $(SanitizerCommonFunctions)
 FUNCTIONS.asan-i386 := $(AsanFunctions) $(InterceptionFunctions) \
                                         $(SanitizerCommonFunctions)
 FUNCTIONS.asan-x86_64 := $(AsanFunctions) $(InterceptionFunctions) \
-                                          $(SanitizerCommonFunctions)
+                         $(SanitizerCommonFunctions) $(LsanCommonFunctions)
 FUNCTIONS.asan-arm-android := $(AsanFunctions) $(InterceptionFunctions) \
                                           $(SanitizerCommonFunctions)
 FUNCTIONS.tsan-x86_64 := $(TsanFunctions) $(InterceptionFunctions) \
                                           $(SanitizerCommonFunctions)
 FUNCTIONS.msan-x86_64 := $(MsanFunctions) $(InterceptionFunctions) \
                                           $(SanitizerCommonFunctions)
-FUNCTIONS.ubsan-i386 := $(UbsanFunctions) $(SanitizerCommonFunctions)
-FUNCTIONS.ubsan-x86_64 := $(UbsanFunctions) $(SanitizerCommonFunctions)
+FUNCTIONS.ubsan-i386 := $(UbsanFunctions)
+FUNCTIONS.ubsan-x86_64 := $(UbsanFunctions)
+FUNCTIONS.ubsan_cxx-i386 := $(UbsanCXXFunctions)
+FUNCTIONS.ubsan_cxx-x86_64 := $(UbsanCXXFunctions)
 
 # Always use optimized variants.
 OPTIMIZED := 1
diff --git a/make/platform/darwin_bni.mk b/make/platform/darwin_bni.mk
index d12cfdf..afd0431 100644
--- a/make/platform/darwin_bni.mk
+++ b/make/platform/darwin_bni.mk
@@ -47,7 +47,7 @@
              mulodi4 muloti4 mulsc3 mulvdi3 mulvsi3 negdi2 negvdi2 negvsi2 \
              paritydi2 paritysi2 popcountdi2 popcountsi2 powidf2 \
              powisf2 subvdi3 subvsi3 ucmpdi2 udivdi3 \
-             udivmoddi4 umoddi3 apple_versioning eprintf
+             udivmoddi4 umoddi3 apple_versioning eprintf atomic
 
 FUNCTIONS.i386 := $(FUNCTIONS) \
                 divxc3 fixunsxfdi fixunsxfsi fixxfdi floatdixf \
diff --git a/test/timing/modsi3.c b/test/timing/modsi3.c
new file mode 100644
index 0000000..3275b83
--- /dev/null
+++ b/test/timing/modsi3.c
@@ -0,0 +1,52 @@
+#include "timing.h"
+#include <stdio.h>
+
+#define INPUT_TYPE int32_t
+#define INPUT_SIZE 256
+#define FUNCTION_NAME __modsi3
+
+#ifndef LIBNAME
+#define LIBNAME UNKNOWN
+#endif
+
+#define LIBSTRING		LIBSTRINGX(LIBNAME)
+#define LIBSTRINGX(a)	LIBSTRINGXX(a)
+#define LIBSTRINGXX(a)	#a
+
+INPUT_TYPE FUNCTION_NAME(INPUT_TYPE input1, INPUT_TYPE input2);
+
+int main(int argc, char *argv[]) {
+	INPUT_TYPE input1[INPUT_SIZE];
+	INPUT_TYPE input2[INPUT_SIZE];
+	int i, j;
+	
+	srand(42);
+	
+	// Initialize the input array with data of various sizes.
+	for (i=0; i<INPUT_SIZE; ++i) {
+		input1[i] = rand();
+		input2[i] = rand() + 1;
+	}
+	
+	int64_t fixedInput = INT64_C(0x1234567890ABCDEF);
+	
+	double bestTime = __builtin_inf();
+	void *dummyp;
+	for (j=0; j<1024; ++j) {
+		
+		uint64_t startTime = mach_absolute_time();
+		for (i=0; i<INPUT_SIZE; ++i)
+			FUNCTION_NAME(input1[i], input2[i]);
+		uint64_t endTime = mach_absolute_time();
+		
+		double thisTime = intervalInCycles(startTime, endTime);
+		bestTime = __builtin_fmin(thisTime, bestTime);
+		
+		// Move the stack alignment between trials to eliminate (mostly) aliasing effects
+		dummyp = alloca(1);
+	}
+	
+	printf("%16s: %f cycles.\n", LIBSTRING, bestTime / (double) INPUT_SIZE);
+	
+	return 0;
+}