From 7df59255e1accc8f95b4d90d1a17c60cd0e6e40e Mon Sep 17 00:00:00 2001
From: Kostya Serebryany <kcc@google.com>
Date: Thu, 21 Feb 2013 10:57:10 +0000
Subject: [PATCH] libsanitizer merge from upstream r175733

From-SVN: r196201
---
 gcc/ChangeLog                                 |   5 +
 gcc/config/i386/i386.c                        |   3 +-
 libsanitizer/ChangeLog                        |   6 +
 libsanitizer/MERGE                            |   2 +-
 libsanitizer/asan/asan_flags.h                |   8 +-
 .../asan/asan_intercepted_functions.h         |  59 ++++--
 libsanitizer/asan/asan_interceptors.cc        |  13 +-
 libsanitizer/asan/asan_internal.h             |   6 +-
 libsanitizer/asan/asan_mac.cc                 | 110 ++++++++++-
 libsanitizer/asan/asan_mapping.h              | 112 ++++++++++-
 libsanitizer/asan/asan_report.cc              |   4 +-
 libsanitizer/asan/asan_rtl.cc                 | 175 ++++++++++++++----
 .../asan/dynamic/asan_interceptors_dynamic.cc | 114 ------------
 .../include/sanitizer/asan_interface.h        |   4 +-
 .../include/sanitizer/common_interface_defs.h |   5 +
 libsanitizer/sanitizer_common/Makefile.am     |   1 +
 libsanitizer/sanitizer_common/Makefile.in     |  13 +-
 .../sanitizer_common/sanitizer_common.cc      |   2 +-
 .../sanitizer_common/sanitizer_common.h       |   2 +-
 .../sanitizer_common_interceptors.inc         | 103 ++++++++++-
 .../sanitizer_common/sanitizer_flags.cc       |   3 +-
 .../sanitizer_internal_defs.h                 |   2 +-
 .../sanitizer_common/sanitizer_libc.h         |   6 +-
 .../sanitizer_common/sanitizer_linux.cc       |  36 +++-
 .../sanitizer_common/sanitizer_mac.cc         |   4 +
 .../sanitizer_platform_interceptors.h         |  10 +
 .../sanitizer_platform_limits_posix.cc        |  68 +++++++
 .../sanitizer_platform_limits_posix.h         |  41 ++++
 .../sanitizer_common/sanitizer_posix.cc       |   8 +-
 .../sanitizer_common/sanitizer_stacktrace.cc  |   5 +-
 .../sanitizer_symbolizer_linux.cc             |   2 +-
 .../sanitizer_common/sanitizer_win.cc         |  12 +-
 libsanitizer/tsan/tsan_platform_linux.cc      |   2 +-
 libsanitizer/tsan/tsan_platform_mac.cc        |   2 +-
 libsanitizer/tsan/tsan_platform_windows.cc    |   2 +-
 libsanitizer/tsan/tsan_rtl.h                  |   2 +
 libsanitizer/tsan/tsan_rtl_thread.cc          |  22 +++
 libsanitizer/tsan/tsan_stat.cc                |   8 +
 libsanitizer/tsan/tsan_stat.h                 |   8 +
 libsanitizer/tsan/tsan_suppressions.cc        |   2 +-
 40 files changed, 767 insertions(+), 225 deletions(-)
 delete mode 100644 libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 067a61f7f0b3..ca184f2ecbfa 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2013-02-23  Kostya Serebryany  <kcc@google.com>
+
+	* config/i386/i386.c (ix86_asan_shadow_offset): Use 0x7fff8000 as
+	asan_shadow_offset on x86_64 linux.
+
 2013-02-21  Richard Biener  <rguenther@suse.de>
 
 	PR tree-optimization/56415
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index f9f266a3dc6f..b835c5da2abb 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -5436,7 +5436,8 @@ ix86_legitimate_combined_insn (rtx insn)
 static unsigned HOST_WIDE_INT
 ix86_asan_shadow_offset (void)
 {
-  return TARGET_LP64 ? (HOST_WIDE_INT_1 << 44)
+  return TARGET_LP64 ? (TARGET_MACHO ? (HOST_WIDE_INT_1 << 44)
+				     : HOST_WIDE_INT_C (0x7fff8000))
 		     : (HOST_WIDE_INT_1 << 29);
 }
 
diff --git a/libsanitizer/ChangeLog b/libsanitizer/ChangeLog
index eb6a3456e474..ed8573848531 100644
--- a/libsanitizer/ChangeLog
+++ b/libsanitizer/ChangeLog
@@ -1,3 +1,9 @@
+2013-02-21  Kostya Serebryany  <kcc@google.com>
+
+	* All source files: Merge from upstream r175733.
+	* sanitizer_common/Makefile.am: Added a new file.
+	* sanitizer_common/Makefile.in: Regenerated.
+
 2013-02-14  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR bootstrap/56327
diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
index 02d2bfcf5127..28d1e49ab773 100644
--- a/libsanitizer/MERGE
+++ b/libsanitizer/MERGE
@@ -1,4 +1,4 @@
-175049
+175733
 
 The first line of this file holds the svn revision number of the
 last merge done from the master library sources.
diff --git a/libsanitizer/asan/asan_flags.h b/libsanitizer/asan/asan_flags.h
index b05fdc3acc6c..b880896c7a3a 100644
--- a/libsanitizer/asan/asan_flags.h
+++ b/libsanitizer/asan/asan_flags.h
@@ -15,11 +15,13 @@
 
 #include "sanitizer_common/sanitizer_internal_defs.h"
 
-// ASan flag values can be defined in three ways:
+// ASan flag values can be defined in four ways:
 // 1) initialized with default values at startup.
-// 2) overriden from string returned by user-specified function
+// 2) overriden during compilation of ASan runtime by providing
+//    compile definition ASAN_DEFAULT_OPTIONS.
+// 3) overriden from string returned by user-specified function
 //    __asan_default_options().
-// 3) overriden from env variable ASAN_OPTIONS.
+// 4) overriden from env variable ASAN_OPTIONS.
 
 namespace __asan {
 
diff --git a/libsanitizer/asan/asan_intercepted_functions.h b/libsanitizer/asan/asan_intercepted_functions.h
index 45c913c1894f..ed75c4284397 100644
--- a/libsanitizer/asan/asan_intercepted_functions.h
+++ b/libsanitizer/asan/asan_intercepted_functions.h
@@ -77,9 +77,36 @@ using __sanitizer::uptr;
 # define ASAN_INTERCEPT___CXA_THROW 0
 #endif
 
+#define INTERPOSE_FUNCTION(function) \
+    { reinterpret_cast<const uptr>(WRAP(function)), \
+      reinterpret_cast<const uptr>(function) }
+
+#define INTERPOSE_FUNCTION_2(function, wrapper) \
+    { reinterpret_cast<const uptr>(wrapper), \
+      reinterpret_cast<const uptr>(function) }
+
+struct interpose_substitution {
+  const uptr replacement;
+  const uptr original;
+};
+
+#define INTERPOSER(func) __attribute__((used)) \
+const interpose_substitution substitution_##func[] \
+    __attribute__((section("__DATA, __interpose"))) = { \
+  INTERPOSE_FUNCTION(func), \
+}
+
+#define INTERPOSER_2(func, wrapper) __attribute__((used)) \
+const interpose_substitution substitution_##func[] \
+    __attribute__((section("__DATA, __interpose"))) = { \
+  INTERPOSE_FUNCTION_2(func, wrapper), \
+}
+
+
 #define DECLARE_FUNCTION_AND_WRAPPER(ret_type, func, ...) \
   ret_type func(__VA_ARGS__); \
-  ret_type WRAP(func)(__VA_ARGS__)
+  ret_type WRAP(func)(__VA_ARGS__); \
+  INTERPOSER(func)
 
 // Use extern declarations of intercepted functions on Mac and Windows
 // to avoid including system headers.
@@ -139,7 +166,8 @@ DECLARE_FUNCTION_AND_WRAPPER(char*, strdup, const char *s);
 DECLARE_FUNCTION_AND_WRAPPER(uptr, strnlen, const char *s, uptr maxlen);
 # endif
 # if ASAN_INTERCEPT_INDEX
-DECLARE_FUNCTION_AND_WRAPPER(char*, index, const char *string, int c);
+char* index(const char *string, int c);
+INTERPOSER_2(index, WRAP(strchr));
 # endif
 
 // stdlib.h
@@ -193,6 +221,20 @@ DECLARE_FUNCTION_AND_WRAPPER(int, pthread_create,
                              void *(*start_routine)(void*), void *arg);
 # endif
 
+# if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
+DECLARE_FUNCTION_AND_WRAPPER(void *, localtime, unsigned long *timep);
+DECLARE_FUNCTION_AND_WRAPPER(void *, localtime_r, unsigned long *timep,
+                             void *result);
+DECLARE_FUNCTION_AND_WRAPPER(void *, gmtime, unsigned long *timep);
+DECLARE_FUNCTION_AND_WRAPPER(void *, gmtime_r, unsigned long *timep,
+                             void *result);
+DECLARE_FUNCTION_AND_WRAPPER(char *, ctime, unsigned long *timep);
+DECLARE_FUNCTION_AND_WRAPPER(char *, ctime_r, unsigned long *timep,
+                             char *result);
+DECLARE_FUNCTION_AND_WRAPPER(char *, asctime, void *tm);
+DECLARE_FUNCTION_AND_WRAPPER(char *, asctime_r, void *tm, char *result);
+# endif
+
 // stdio.h
 # if SANITIZER_INTERCEPT_SCANF
 DECLARE_FUNCTION_AND_WRAPPER(int, vscanf, const char *format, va_list ap);
@@ -205,17 +247,6 @@ DECLARE_FUNCTION_AND_WRAPPER(int, fscanf,
                              void* stream, const char *format, ...);
 DECLARE_FUNCTION_AND_WRAPPER(int, sscanf,  // NOLINT
                              const char *str, const char *format, ...);
-DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_vscanf, const char *format,
-                             va_list ap);
-DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_vsscanf, const char *str,
-                             const char *format, va_list ap);
-DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_vfscanf, void *stream,
-                             const char *format, va_list ap);
-DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_scanf, const char *format, ...);
-DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_fscanf,
-                             void* stream, const char *format, ...);
-DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_sscanf,  // NOLINT
-                             const char *str, const char *format, ...);
 # endif
 
 # if defined(__APPLE__)
@@ -278,9 +309,11 @@ DECLARE_FUNCTION_AND_WRAPPER(void *, valloc, size_t size);
 DECLARE_FUNCTION_AND_WRAPPER(size_t, malloc_good_size, size_t size);
 DECLARE_FUNCTION_AND_WRAPPER(int, posix_memalign,
                              void **memptr, size_t alignment, size_t size);
+#if 0
 DECLARE_FUNCTION_AND_WRAPPER(void, _malloc_fork_prepare, void);
 DECLARE_FUNCTION_AND_WRAPPER(void, _malloc_fork_parent, void);
 DECLARE_FUNCTION_AND_WRAPPER(void, _malloc_fork_child, void);
+#endif
 
 
 
diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc
index f4c56830d8ae..064fc6261b02 100644
--- a/libsanitizer/asan/asan_interceptors.cc
+++ b/libsanitizer/asan/asan_interceptors.cc
@@ -24,6 +24,16 @@
 
 namespace __asan {
 
+// Return true if we can quickly decide that the region is unpoisoned.
+static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
+  if (size == 0) return true;
+  if (size <= 32)
+    return !AddressIsPoisoned(beg) &&
+           !AddressIsPoisoned(beg + size - 1) &&
+           !AddressIsPoisoned(beg + size / 2);
+  return false;
+}
+
 // We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
 // and ASAN_WRITE_RANGE as macro instead of function so
 // that no extra frames are created, and stack trace contains
@@ -32,7 +42,8 @@ namespace __asan {
 #define ACCESS_MEMORY_RANGE(offset, size, isWrite) do {                 \
     uptr __offset = (uptr)(offset);                                     \
     uptr __size = (uptr)(size);                                         \
-    if (__asan_region_is_poisoned(__offset, __size)) {                  \
+    if (!QuickCheckForUnpoisonedRegion(__offset, __size) &&             \
+        __asan_region_is_poisoned(__offset, __size)) {                  \
       GET_CURRENT_PC_BP_SP;                                             \
       __asan_report_error(pc, bp, sp, __offset, isWrite, __size);       \
     }                                                                   \
diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h
index 0fe620e2e4c5..1ccbf1086478 100644
--- a/libsanitizer/asan/asan_internal.h
+++ b/libsanitizer/asan/asan_internal.h
@@ -52,7 +52,7 @@
 
 #define ASAN_POSIX (ASAN_LINUX || ASAN_MAC)
 
-#if __has_feature(address_sanitizer)
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
 # error "The AddressSanitizer run-time should not be"
         " instrumented by AddressSanitizer"
 #endif
@@ -89,6 +89,10 @@
 # endif
 #endif
 
+#ifndef ASAN_USE_PREINIT_ARRAY
+# define ASAN_USE_PREINIT_ARRAY (ASAN_LINUX && !ASAN_ANDROID)
+#endif
+
 // All internal functions in asan reside inside the __asan namespace
 // to avoid namespace collisions with the user programs.
 // Seperate namespace also makes it simpler to distinguish the asan run-time
diff --git a/libsanitizer/asan/asan_mac.cc b/libsanitizer/asan/asan_mac.cc
index c5fc7de10c03..dd2657df1e25 100644
--- a/libsanitizer/asan/asan_mac.cc
+++ b/libsanitizer/asan/asan_mac.cc
@@ -86,6 +86,39 @@ extern "C"
 void __asan_init();
 
 static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
+LowLevelAllocator allocator_for_env;
+
+// Change the value of the env var |name|, leaking the original value.
+// If |name_value| is NULL, the variable is deleted from the environment,
+// otherwise the corresponding "NAME=value" string is replaced with
+// |name_value|.
+void LeakyResetEnv(const char *name, const char *name_value) {
+  char ***env_ptr = _NSGetEnviron();
+  CHECK(env_ptr);
+  char **environ = *env_ptr;
+  CHECK(environ);
+  uptr name_len = internal_strlen(name);
+  while (*environ != 0) {
+    uptr len = internal_strlen(*environ);
+    if (len > name_len) {
+      const char *p = *environ;
+      if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
+        // Match.
+        if (name_value) {
+          // Replace the old value with the new one.
+          *environ = const_cast<char*>(name_value);
+        } else {
+          // Shift the subsequent pointers back.
+          char **del = environ;
+          do {
+            del[0] = del[1];
+          } while (*del++);
+        }
+      }
+    }
+    environ++;
+  }
+}
 
 void MaybeReexec() {
   if (!flags()->allow_reexec) return;
@@ -94,7 +127,11 @@ void MaybeReexec() {
   // ourselves.
   Dl_info info;
   CHECK(dladdr((void*)((uptr)__asan_init), &info));
-  const char *dyld_insert_libraries = GetEnv(kDyldInsertLibraries);
+  char *dyld_insert_libraries =
+      const_cast<char*>(GetEnv(kDyldInsertLibraries));
+  uptr old_env_len = dyld_insert_libraries ?
+      internal_strlen(dyld_insert_libraries) : 0;
+  uptr fname_len = internal_strlen(info.dli_fname);
   if (!dyld_insert_libraries ||
       !REAL(strstr)(dyld_insert_libraries, info.dli_fname)) {
     // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
@@ -102,16 +139,79 @@ void MaybeReexec() {
     char program_name[1024];
     uint32_t buf_size = sizeof(program_name);
     _NSGetExecutablePath(program_name, &buf_size);
-    // Ok to use setenv() since the wrappers don't depend on the value of
-    // asan_inited.
-    setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
+    char *new_env = const_cast<char*>(info.dli_fname);
+    if (dyld_insert_libraries) {
+      // Append the runtime dylib name to the existing value of
+      // DYLD_INSERT_LIBRARIES.
+      new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2);
+      internal_strncpy(new_env, dyld_insert_libraries, old_env_len);
+      new_env[old_env_len] = ':';
+      // Copy fname_len and add a trailing zero.
+      internal_strncpy(new_env + old_env_len + 1, info.dli_fname,
+                       fname_len + 1);
+      // Ok to use setenv() since the wrappers don't depend on the value of
+      // asan_inited.
+      setenv(kDyldInsertLibraries, new_env, /*overwrite*/1);
+    } else {
+      // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
+      setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
+    }
     if (flags()->verbosity >= 1) {
       Report("exec()-ing the program with\n");
-      Report("%s=%s\n", kDyldInsertLibraries, info.dli_fname);
+      Report("%s=%s\n", kDyldInsertLibraries, new_env);
       Report("to enable ASan wrappers.\n");
       Report("Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
     }
     execv(program_name, *_NSGetArgv());
+  } else {
+    // DYLD_INSERT_LIBRARIES is set and contains the runtime library.
+    if (old_env_len == fname_len) {
+      // It's just the runtime library name - fine to unset the variable.
+      LeakyResetEnv(kDyldInsertLibraries, NULL);
+    } else {
+      uptr env_name_len = internal_strlen(kDyldInsertLibraries);
+      // Allocate memory to hold the previous env var name, its value, the '='
+      // sign and the '\0' char.
+      char *new_env = (char*)allocator_for_env.Allocate(
+          old_env_len + 2 + env_name_len);
+      CHECK(new_env);
+      internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
+      internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
+      new_env[env_name_len] = '=';
+      char *new_env_pos = new_env + env_name_len + 1;
+
+      // Iterate over colon-separated pieces of |dyld_insert_libraries|.
+      char *piece_start = dyld_insert_libraries;
+      char *piece_end = NULL;
+      char *old_env_end = dyld_insert_libraries + old_env_len;
+      do {
+        if (piece_start[0] == ':') piece_start++;
+        piece_end =  REAL(strchr)(piece_start, ':');
+        if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
+        if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
+        uptr piece_len = piece_end - piece_start;
+
+        // If the current piece isn't the runtime library name,
+        // append it to new_env.
+        if ((piece_len != fname_len) ||
+            (internal_strncmp(piece_start, info.dli_fname, fname_len) != 0)) {
+          if (new_env_pos != new_env + env_name_len + 1) {
+            new_env_pos[0] = ':';
+            new_env_pos++;
+          }
+          internal_strncpy(new_env_pos, piece_start, piece_len);
+        }
+        // Move on to the next piece.
+        new_env_pos += piece_len;
+        piece_start = piece_end;
+      } while (piece_start < old_env_end);
+
+      // Can't use setenv() here, because it requires the allocator to be
+      // initialized.
+      // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
+      // a separate function called after InitializeAllocator().
+      LeakyResetEnv(kDyldInsertLibraries, new_env);
+    }
   }
 }
 
diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
index 48b24545b99f..df952363893e 100644
--- a/libsanitizer/asan/asan_mapping.h
+++ b/libsanitizer/asan/asan_mapping.h
@@ -1,7 +1,5 @@
 //===-- asan_mapping.h ------------------------------------------*- C++ -*-===//
 //
-//                     The LLVM Compiler Infrastructure
-//
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
@@ -18,6 +16,37 @@
 
 // The full explanation of the memory mapping could be found here:
 // http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
+//
+// Typical shadow mapping on Linux/x86_64 with SHADOW_OFFSET == 0x00007fff8000:
+// || `[0x10007fff8000, 0x7fffffffffff]` || HighMem    ||
+// || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
+// || `[0x00008fff7000, 0x02008fff6fff]` || ShadowGap  ||
+// || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow  ||
+// || `[0x000000000000, 0x00007fff7fff]` || LowMem     ||
+//
+// When SHADOW_OFFSET is zero (-pie):
+// || `[0x100000000000, 0x7fffffffffff]` || HighMem    ||
+// || `[0x020000000000, 0x0fffffffffff]` || HighShadow ||
+// || `[0x000000040000, 0x01ffffffffff]` || ShadowGap  ||
+//
+// Special case when something is already mapped between
+// 0x003000000000 and 0x004000000000 (e.g. when prelink is installed):
+// || `[0x10007fff8000, 0x7fffffffffff]` || HighMem    ||
+// || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
+// || `[0x004000000000, 0x02008fff6fff]` || ShadowGap3 ||
+// || `[0x003000000000, 0x003fffffffff]` || MidMem     ||
+// || `[0x00087fff8000, 0x002fffffffff]` || ShadowGap2 ||
+// || `[0x00067fff8000, 0x00087fff7fff]` || MidShadow  ||
+// || `[0x00008fff7000, 0x00067fff7fff]` || ShadowGap  ||
+// || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow  ||
+// || `[0x000000000000, 0x00007fff7fff]` || LowMem     ||
+//
+// Default Linux/i386 mapping:
+// || `[0x40000000, 0xffffffff]` || HighMem    ||
+// || `[0x28000000, 0x3fffffff]` || HighShadow ||
+// || `[0x24000000, 0x27ffffff]` || ShadowGap  ||
+// || `[0x20000000, 0x23ffffff]` || LowShadow  ||
+// || `[0x00000000, 0x1fffffff]` || LowMem     ||
 
 #if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
 extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale;
@@ -36,7 +65,11 @@ extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
 #   if defined(__powerpc64__)
 #    define SHADOW_OFFSET (1ULL << 41)
 #   else
-#    define SHADOW_OFFSET (1ULL << 44)
+#    if ASAN_MAC
+#     define SHADOW_OFFSET (1ULL << 44)
+#    else
+#     define SHADOW_OFFSET 0x7fff8000ULL
+#    endif
 #   endif
 #  endif
 # endif
@@ -57,49 +90,105 @@ extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
 #define kHighShadowBeg  MEM_TO_SHADOW(kHighMemBeg)
 #define kHighShadowEnd  MEM_TO_SHADOW(kHighMemEnd)
 
+# define kMidShadowBeg MEM_TO_SHADOW(kMidMemBeg)
+# define kMidShadowEnd MEM_TO_SHADOW(kMidMemEnd)
+
 // With the zero shadow base we can not actually map pages starting from 0.
 // This constant is somewhat arbitrary.
 #define kZeroBaseShadowStart (1 << 18)
 
 #define kShadowGapBeg   (kLowShadowEnd ? kLowShadowEnd + 1 \
                                        : kZeroBaseShadowStart)
-#define kShadowGapEnd   (kHighShadowBeg - 1)
+#define kShadowGapEnd   ((kMidMemBeg ? kMidShadowBeg : kHighShadowBeg) - 1)
+
+#define kShadowGap2Beg (kMidMemBeg ? kMidShadowEnd + 1 : 0)
+#define kShadowGap2End (kMidMemBeg ? kMidMemBeg - 1 : 0)
+
+#define kShadowGap3Beg (kMidMemBeg ? kMidMemEnd + 1 : 0)
+#define kShadowGap3End (kMidMemBeg ? kHighShadowBeg - 1 : 0)
+
+#define DO_ASAN_MAPPING_PROFILE 0  // Set to 1 to profile the functions below.
+
+#if DO_ASAN_MAPPING_PROFILE
+# define PROFILE_ASAN_MAPPING() AsanMappingProfile[__LINE__]++;
+#else
+# define PROFILE_ASAN_MAPPING()
+#endif
+
+// If 1, all shadow boundaries are constants.
+// Don't set to 1 other than for testing.
+#define ASAN_FIXED_MAPPING 0
 
 namespace __asan {
 
+extern uptr AsanMappingProfile[];
+
+#if ASAN_FIXED_MAPPING
+// Fixed mapping for 64-bit Linux. Mostly used for performance comparison
+// with non-fixed mapping. As of r175253 (Feb 2013) the performance
+// difference between fixed and non-fixed mapping is below the noise level.
+static uptr kHighMemEnd = 0x7fffffffffffULL;
+static uptr kMidMemBeg =    0x3000000000ULL;
+static uptr kMidMemEnd =    0x3fffffffffULL;
+#else
 SANITIZER_INTERFACE_ATTRIBUTE
-extern uptr kHighMemEnd;  // Initialized in __asan_init.
+extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;  // Initialized in __asan_init.
+#endif
 
 static inline bool AddrIsInLowMem(uptr a) {
+  PROFILE_ASAN_MAPPING();
   return a < kLowMemEnd;
 }
 
 static inline bool AddrIsInLowShadow(uptr a) {
+  PROFILE_ASAN_MAPPING();
   return a >= kLowShadowBeg && a <= kLowShadowEnd;
 }
 
 static inline bool AddrIsInHighMem(uptr a) {
+  PROFILE_ASAN_MAPPING();
   return a >= kHighMemBeg && a <= kHighMemEnd;
 }
 
+static inline bool AddrIsInMidMem(uptr a) {
+  PROFILE_ASAN_MAPPING();
+  return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd;
+}
+
 static inline bool AddrIsInMem(uptr a) {
-  return AddrIsInLowMem(a) || AddrIsInHighMem(a);
+  PROFILE_ASAN_MAPPING();
+  return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a);
 }
 
 static inline uptr MemToShadow(uptr p) {
+  PROFILE_ASAN_MAPPING();
   CHECK(AddrIsInMem(p));
   return MEM_TO_SHADOW(p);
 }
 
 static inline bool AddrIsInHighShadow(uptr a) {
-  return a >= kHighShadowBeg && a <=  kHighMemEnd;
+  PROFILE_ASAN_MAPPING();
+  return a >= kHighShadowBeg && a <= kHighMemEnd;
+}
+
+static inline bool AddrIsInMidShadow(uptr a) {
+  PROFILE_ASAN_MAPPING();
+  return kMidMemBeg && a >= kMidShadowBeg && a <= kMidMemEnd;
 }
 
 static inline bool AddrIsInShadow(uptr a) {
-  return AddrIsInLowShadow(a) || AddrIsInHighShadow(a);
+  PROFILE_ASAN_MAPPING();
+  return AddrIsInLowShadow(a) || AddrIsInMidShadow(a) || AddrIsInHighShadow(a);
 }
 
 static inline bool AddrIsInShadowGap(uptr a) {
+  PROFILE_ASAN_MAPPING();
+  if (kMidMemBeg) {
+    if (a <= kShadowGapEnd)
+      return SHADOW_OFFSET == 0 || a >= kShadowGapBeg;
+    return (a >= kShadowGap2Beg && a <= kShadowGap2End) ||
+           (a >= kShadowGap3Beg && a <= kShadowGap3End);
+  }
   // In zero-based shadow mode we treat addresses near zero as addresses
   // in shadow gap as well.
   if (SHADOW_OFFSET == 0)
@@ -108,12 +197,14 @@ static inline bool AddrIsInShadowGap(uptr a) {
 }
 
 static inline bool AddrIsAlignedByGranularity(uptr a) {
+  PROFILE_ASAN_MAPPING();
   return (a & (SHADOW_GRANULARITY - 1)) == 0;
 }
 
 static inline bool AddressIsPoisoned(uptr a) {
+  PROFILE_ASAN_MAPPING();
   const uptr kAccessSize = 1;
-  u8 *shadow_address = (u8*)MemToShadow(a);
+  u8 *shadow_address = (u8*)MEM_TO_SHADOW(a);
   s8 shadow_value = *shadow_address;
   if (shadow_value) {
     u8 last_accessed_byte = (a & (SHADOW_GRANULARITY - 1))
@@ -123,6 +214,9 @@ static inline bool AddressIsPoisoned(uptr a) {
   return false;
 }
 
+// Must be after all calls to PROFILE_ASAN_MAPPING().
+static const uptr kAsanMappingProfileSize = __LINE__;
+
 }  // namespace __asan
 
 #endif  // ASAN_MAPPING_H
diff --git a/libsanitizer/asan/asan_report.cc b/libsanitizer/asan/asan_report.cc
index 663e8f3b7488..13e94c421b5d 100644
--- a/libsanitizer/asan/asan_report.cc
+++ b/libsanitizer/asan/asan_report.cc
@@ -433,9 +433,9 @@ class ScopedInErrorReport {
         // an error report will finish doing it.
         SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
       }
-      // If we're still not dead for some reason, use raw Exit() instead of
+      // If we're still not dead for some reason, use raw _exit() instead of
       // Die() to bypass any additional checks.
-      Exit(flags()->exitcode);
+      internal__exit(flags()->exitcode);
     }
     ASAN_ON_ERROR();
     reporting_thread_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc
index 175d37788c29..e22fcd34fb12 100644
--- a/libsanitizer/asan/asan_rtl.cc
+++ b/libsanitizer/asan/asan_rtl.cc
@@ -25,6 +25,8 @@
 
 namespace __asan {
 
+uptr AsanMappingProfile[kAsanMappingProfileSize];
+
 static void AsanDie() {
   static atomic_uint32_t num_calls;
   if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
@@ -35,13 +37,19 @@ static void AsanDie() {
     Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying);
     SleepForSeconds(flags()->sleep_before_dying);
   }
-  if (flags()->unmap_shadow_on_exit)
-    UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
+  if (flags()->unmap_shadow_on_exit) {
+    if (kMidMemBeg) {
+      UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg);
+      UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd);
+    } else {
+      UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
+    }
+  }
   if (death_callback)
     death_callback();
   if (flags()->abort_on_error)
     Abort();
-  Exit(flags()->exitcode);
+  internal__exit(flags()->exitcode);
 }
 
 static void AsanCheckFailed(const char *file, int line, const char *cond,
@@ -66,6 +74,17 @@ static const char *MaybeCallAsanDefaultOptions() {
   return (&__asan_default_options) ? __asan_default_options() : "";
 }
 
+static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() {
+#ifdef ASAN_DEFAULT_OPTIONS
+// Stringize the macro value.
+# define ASAN_STRINGIZE(x) #x
+# define ASAN_STRINGIZE_OPTIONS(options) ASAN_STRINGIZE(options)
+  return ASAN_STRINGIZE_OPTIONS(ASAN_DEFAULT_OPTIONS);
+#else
+  return "";
+#endif
+}
+
 static void ParseFlagsFromString(Flags *f, const char *str) {
   ParseFlag(str, &f->quarantine_size, "quarantine_size");
   ParseFlag(str, &f->symbolize, "symbolize");
@@ -146,6 +165,9 @@ void InitializeFlags(Flags *f, const char *env) {
   f->alloc_dealloc_mismatch = true;
   f->use_stack_depot = true;  // Only affects allocator2.
 
+  // Override from compile definition.
+  ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton());
+
   // Override from user-specified string.
   ParseFlagsFromString(f, MaybeCallAsanDefaultOptions());
   if (flags()->verbosity) {
@@ -161,7 +183,10 @@ void InitializeFlags(Flags *f, const char *env) {
 int asan_inited;
 bool asan_init_is_running;
 void (*death_callback)(void);
-uptr kHighMemEnd;
+
+#if !ASAN_FIXED_MAPPING
+uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;
+#endif
 
 // -------------------------- Misc ---------------- {{{1
 void ShowStatsAndAbort() {
@@ -209,6 +234,17 @@ ASAN_REPORT_ERROR(store, true, 4)
 ASAN_REPORT_ERROR(store, true, 8)
 ASAN_REPORT_ERROR(store, true, 16)
 
+#define ASAN_REPORT_ERROR_N(type, is_write)                    \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE                        \
+void __asan_report_ ## type ## _n(uptr addr, uptr size);       \
+void __asan_report_ ## type ## _n(uptr addr, uptr size) {      \
+  GET_CALLER_PC_BP_SP;                                         \
+  __asan_report_error(pc, bp, sp, addr, is_write, size);       \
+}
+
+ASAN_REPORT_ERROR_N(load, false)
+ASAN_REPORT_ERROR_N(store, true)
+
 // Force the linker to keep the symbols for various ASan interface functions.
 // We want to keep those in the executable in order to let the instrumented
 // dynamic libraries access the symbol even if it is not used by the executable
@@ -259,9 +295,15 @@ static NOINLINE void force_interface_symbols() {
 static void asan_atexit() {
   Printf("AddressSanitizer exit stats:\n");
   __asan_print_accumulated_stats();
+  // Print AsanMappingProfile.
+  for (uptr i = 0; i < kAsanMappingProfileSize; i++) {
+    if (AsanMappingProfile[i] == 0) continue;
+    Printf("asan_mapping.h:%zd -- %zd\n", i, AsanMappingProfile[i]);
+  }
 }
 
 static void InitializeHighMemEnd() {
+#if !ASAN_FIXED_MAPPING
 #if SANITIZER_WORDSIZE == 64
 # if defined(__powerpc64__)
   // FIXME:
@@ -277,6 +319,58 @@ static void InitializeHighMemEnd() {
 #else  // SANITIZER_WORDSIZE == 32
   kHighMemEnd = (1ULL << 32) - 1;  // 0xffffffff;
 #endif  // SANITIZER_WORDSIZE
+#endif  // !ASAN_FIXED_MAPPING
+}
+
+static void ProtectGap(uptr a, uptr size) {
+  CHECK_EQ(a, (uptr)Mprotect(a, size));
+}
+
+static void PrintAddressSpaceLayout() {
+  Printf("|| `[%p, %p]` || HighMem    ||\n",
+         (void*)kHighMemBeg, (void*)kHighMemEnd);
+  Printf("|| `[%p, %p]` || HighShadow ||\n",
+         (void*)kHighShadowBeg, (void*)kHighShadowEnd);
+  if (kMidMemBeg) {
+    Printf("|| `[%p, %p]` || ShadowGap3 ||\n",
+           (void*)kShadowGap3Beg, (void*)kShadowGap3End);
+    Printf("|| `[%p, %p]` || MidMem     ||\n",
+           (void*)kMidMemBeg, (void*)kMidMemEnd);
+    Printf("|| `[%p, %p]` || ShadowGap2 ||\n",
+           (void*)kShadowGap2Beg, (void*)kShadowGap2End);
+    Printf("|| `[%p, %p]` || MidShadow  ||\n",
+           (void*)kMidShadowBeg, (void*)kMidShadowEnd);
+  }
+  Printf("|| `[%p, %p]` || ShadowGap  ||\n",
+         (void*)kShadowGapBeg, (void*)kShadowGapEnd);
+  if (kLowShadowBeg) {
+    Printf("|| `[%p, %p]` || LowShadow  ||\n",
+           (void*)kLowShadowBeg, (void*)kLowShadowEnd);
+    Printf("|| `[%p, %p]` || LowMem     ||\n",
+           (void*)kLowMemBeg, (void*)kLowMemEnd);
+  }
+  Printf("MemToShadow(shadow): %p %p %p %p",
+         (void*)MEM_TO_SHADOW(kLowShadowBeg),
+         (void*)MEM_TO_SHADOW(kLowShadowEnd),
+         (void*)MEM_TO_SHADOW(kHighShadowBeg),
+         (void*)MEM_TO_SHADOW(kHighShadowEnd));
+  if (kMidMemBeg) {
+    Printf(" %p %p",
+           (void*)MEM_TO_SHADOW(kMidShadowBeg),
+           (void*)MEM_TO_SHADOW(kMidShadowEnd));
+  }
+  Printf("\n");
+  Printf("red_zone=%zu\n", (uptr)flags()->redzone);
+  Printf("malloc_context_size=%zu\n", (uptr)flags()->malloc_context_size);
+
+  Printf("SHADOW_SCALE: %zx\n", (uptr)SHADOW_SCALE);
+  Printf("SHADOW_GRANULARITY: %zx\n", (uptr)SHADOW_GRANULARITY);
+  Printf("SHADOW_OFFSET: %zx\n", (uptr)SHADOW_OFFSET);
+  CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7);
+  if (kMidMemBeg)
+    CHECK(kMidShadowBeg > kLowShadowEnd &&
+          kMidMemBeg > kMidShadowEnd &&
+          kHighShadowBeg > kMidMemEnd);
 }
 
 }  // namespace __asan
@@ -352,49 +446,48 @@ void __asan_init() {
   ReplaceSystemMalloc();
   ReplaceOperatorsNewAndDelete();
 
-  if (flags()->verbosity) {
-    Printf("|| `[%p, %p]` || HighMem    ||\n",
-           (void*)kHighMemBeg, (void*)kHighMemEnd);
-    Printf("|| `[%p, %p]` || HighShadow ||\n",
-           (void*)kHighShadowBeg, (void*)kHighShadowEnd);
-    Printf("|| `[%p, %p]` || ShadowGap  ||\n",
-           (void*)kShadowGapBeg, (void*)kShadowGapEnd);
-    Printf("|| `[%p, %p]` || LowShadow  ||\n",
-           (void*)kLowShadowBeg, (void*)kLowShadowEnd);
-    Printf("|| `[%p, %p]` || LowMem     ||\n",
-           (void*)kLowMemBeg, (void*)kLowMemEnd);
-    Printf("MemToShadow(shadow): %p %p %p %p\n",
-           (void*)MEM_TO_SHADOW(kLowShadowBeg),
-           (void*)MEM_TO_SHADOW(kLowShadowEnd),
-           (void*)MEM_TO_SHADOW(kHighShadowBeg),
-           (void*)MEM_TO_SHADOW(kHighShadowEnd));
-    Printf("red_zone=%zu\n", (uptr)flags()->redzone);
-    Printf("malloc_context_size=%zu\n", (uptr)flags()->malloc_context_size);
-
-    Printf("SHADOW_SCALE: %zx\n", (uptr)SHADOW_SCALE);
-    Printf("SHADOW_GRANULARITY: %zx\n", (uptr)SHADOW_GRANULARITY);
-    Printf("SHADOW_OFFSET: %zx\n", (uptr)SHADOW_OFFSET);
-    CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7);
+  uptr shadow_start = kLowShadowBeg;
+  if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
+  uptr shadow_end = kHighShadowEnd;
+  bool full_shadow_is_available =
+      MemoryRangeIsAvailable(shadow_start, shadow_end);
+
+#if ASAN_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
+  if (!full_shadow_is_available) {
+    kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
+    kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x3fffffffffULL : 0;
   }
+#endif
+
+  if (flags()->verbosity)
+    PrintAddressSpaceLayout();
 
   if (flags()->disable_core) {
     DisableCoreDumper();
   }
 
-  uptr shadow_start = kLowShadowBeg;
-  if (kLowShadowBeg > 0) shadow_start -= GetMmapGranularity();
-  uptr shadow_end = kHighShadowEnd;
-  if (MemoryRangeIsAvailable(shadow_start, shadow_end)) {
-    if (kLowShadowBeg != kLowShadowEnd) {
-      // mmap the low shadow plus at least one page.
-      ReserveShadowMemoryRange(kLowShadowBeg - GetMmapGranularity(),
-                               kLowShadowEnd);
-    }
+  if (full_shadow_is_available) {
+    // mmap the low shadow plus at least one page at the left.
+    if (kLowShadowBeg)
+      ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
+    // mmap the high shadow.
+    ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
+    // protect the gap.
+    ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
+  } else if (kMidMemBeg &&
+      MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
+      MemoryRangeIsAvailable(kMidMemEnd + 1, shadow_end)) {
+    CHECK(kLowShadowBeg != kLowShadowEnd);
+    // mmap the low shadow plus at least one page at the left.
+    ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
+    // mmap the mid shadow.
+    ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd);
     // mmap the high shadow.
     ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
-    // protect the gap
-    void *prot = Mprotect(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
-    CHECK(prot == (void*)kShadowGapBeg);
+    // protect the gaps.
+    ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
+    ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
+    ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
   } else {
     Report("Shadow memory range interleaves with an existing memory mapping. "
            "ASan cannot proceed correctly. ABORTING.\n");
@@ -427,12 +520,12 @@ void __asan_init() {
   }
 }
 
-#if defined(ASAN_USE_PREINIT_ARRAY)
+#if ASAN_USE_PREINIT_ARRAY
   // 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?
   __attribute__((section(".preinit_array")))
-    typeof(__asan_init) *__asan_preinit =__asan_init;
+  void (*__asan_preinit)(void) =__asan_init;
 #elif defined(_WIN32) && defined(_DLL)
   // On Windows, when using dynamic CRT (/MD), we can put a pointer
   // to __asan_init into the global list of C initializers.
diff --git a/libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc b/libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc
deleted file mode 100644
index 727edf2b43b9..000000000000
--- a/libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-//===-- asan_interceptors_dynamic.cc --------------------------------------===//
-//
-// 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.
-//
-// __DATA,__interpose section of the dynamic runtime library for Mac OS.
-//===----------------------------------------------------------------------===//
-
-#if defined(__APPLE__)
-
-#include "../asan_interceptors.h"
-#include "../asan_intercepted_functions.h"
-
-namespace __asan {
-
-#define INTERPOSE_FUNCTION(function) \
-    { reinterpret_cast<const uptr>(WRAP(function)), \
-      reinterpret_cast<const uptr>(function) }
-
-#define INTERPOSE_FUNCTION_2(function, wrapper) \
-    { reinterpret_cast<const uptr>(wrapper), \
-      reinterpret_cast<const uptr>(function) }
-
-struct interpose_substitution {
-  const uptr replacement;
-  const uptr original;
-};
-
-__attribute__((used))
-const interpose_substitution substitutions[]
-    __attribute__((section("__DATA, __interpose"))) = {
-  INTERPOSE_FUNCTION(strlen),
-  INTERPOSE_FUNCTION(memcmp),
-  INTERPOSE_FUNCTION(memcpy),
-  INTERPOSE_FUNCTION(memmove),
-  INTERPOSE_FUNCTION(memset),
-  INTERPOSE_FUNCTION(strchr),
-  INTERPOSE_FUNCTION(strcat),
-  INTERPOSE_FUNCTION(strncat),
-  INTERPOSE_FUNCTION(strcpy),
-  INTERPOSE_FUNCTION(strncpy),
-  INTERPOSE_FUNCTION(pthread_create),
-  INTERPOSE_FUNCTION(longjmp),
-#if ASAN_INTERCEPT__LONGJMP
-  INTERPOSE_FUNCTION(_longjmp),
-#endif
-#if ASAN_INTERCEPT_SIGLONGJMP
-  INTERPOSE_FUNCTION(siglongjmp),
-#endif
-#if ASAN_INTERCEPT_STRDUP
-  INTERPOSE_FUNCTION(strdup),
-#endif
-#if ASAN_INTERCEPT_STRNLEN
-  INTERPOSE_FUNCTION(strnlen),
-#endif
-#if ASAN_INTERCEPT_INDEX
-  INTERPOSE_FUNCTION_2(index, WRAP(strchr)),
-#endif
-  INTERPOSE_FUNCTION(strcmp),
-  INTERPOSE_FUNCTION(strncmp),
-#if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
-  INTERPOSE_FUNCTION(strcasecmp),
-  INTERPOSE_FUNCTION(strncasecmp),
-#endif
-  INTERPOSE_FUNCTION(atoi),
-  INTERPOSE_FUNCTION(atol),
-  INTERPOSE_FUNCTION(strtol),
-#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
-  INTERPOSE_FUNCTION(atoll),
-  INTERPOSE_FUNCTION(strtoll),
-#endif
-#if ASAN_INTERCEPT_MLOCKX
-  INTERPOSE_FUNCTION(mlock),
-  INTERPOSE_FUNCTION(munlock),
-  INTERPOSE_FUNCTION(mlockall),
-  INTERPOSE_FUNCTION(munlockall),
-#endif
-  INTERPOSE_FUNCTION(dispatch_async_f),
-  INTERPOSE_FUNCTION(dispatch_sync_f),
-  INTERPOSE_FUNCTION(dispatch_after_f),
-  INTERPOSE_FUNCTION(dispatch_barrier_async_f),
-  INTERPOSE_FUNCTION(dispatch_group_async_f),
-#ifndef MISSING_BLOCKS_SUPPORT
-  INTERPOSE_FUNCTION(dispatch_group_async),
-  INTERPOSE_FUNCTION(dispatch_async),
-  INTERPOSE_FUNCTION(dispatch_after),
-  INTERPOSE_FUNCTION(dispatch_source_set_event_handler),
-  INTERPOSE_FUNCTION(dispatch_source_set_cancel_handler),
-#endif
-  INTERPOSE_FUNCTION(signal),
-  INTERPOSE_FUNCTION(sigaction),
-
-  INTERPOSE_FUNCTION(malloc_create_zone),
-  INTERPOSE_FUNCTION(malloc_default_zone),
-  INTERPOSE_FUNCTION(malloc_default_purgeable_zone),
-  INTERPOSE_FUNCTION(malloc_make_purgeable),
-  INTERPOSE_FUNCTION(malloc_make_nonpurgeable),
-  INTERPOSE_FUNCTION(malloc_set_zone_name),
-  INTERPOSE_FUNCTION(malloc),
-  INTERPOSE_FUNCTION(free),
-  INTERPOSE_FUNCTION(realloc),
-  INTERPOSE_FUNCTION(calloc),
-  INTERPOSE_FUNCTION(valloc),
-  INTERPOSE_FUNCTION(malloc_good_size),
-  INTERPOSE_FUNCTION(posix_memalign),
-};
-
-}  // namespace __asan
-
-#endif  // __APPLE__
diff --git a/libsanitizer/include/sanitizer/asan_interface.h b/libsanitizer/include/sanitizer/asan_interface.h
index 18696a681eda..0016339e4864 100644
--- a/libsanitizer/include/sanitizer/asan_interface.h
+++ b/libsanitizer/include/sanitizer/asan_interface.h
@@ -35,8 +35,8 @@ extern "C" {
   // (un)poison memory in the same memory region simultaneously.
   void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
 
-  // User code should use macro instead of functions.
-#if __has_feature(address_sanitizer)
+// User code should use macros instead of functions.
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
 #define ASAN_POISON_MEMORY_REGION(addr, size) \
   __asan_poison_memory_region((addr), (size))
 #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
index b61b8a1a6365..c218b5b56541 100644
--- a/libsanitizer/include/sanitizer/common_interface_defs.h
+++ b/libsanitizer/include/sanitizer/common_interface_defs.h
@@ -14,6 +14,11 @@
 #include <stddef.h>
 #include <stdint.h>
 
+// GCC does not understand __has_feature.
+#if !defined(__has_feature)
+# define __has_feature(x) 0
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/libsanitizer/sanitizer_common/Makefile.am b/libsanitizer/sanitizer_common/Makefile.am
index 79585e48ed2b..c53a3c6bfc5a 100644
--- a/libsanitizer/sanitizer_common/Makefile.am
+++ b/libsanitizer/sanitizer_common/Makefile.am
@@ -17,6 +17,7 @@ sanitizer_common_files = \
         sanitizer_libc.cc \
         sanitizer_linux.cc \
         sanitizer_mac.cc \
+	sanitizer_platform_limits_posix.cc \
         sanitizer_posix.cc \
         sanitizer_printf.cc \
         sanitizer_stackdepot.cc \
diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in
index 7876acdf4d0f..8e2924327655 100644
--- a/libsanitizer/sanitizer_common/Makefile.in
+++ b/libsanitizer/sanitizer_common/Makefile.in
@@ -57,11 +57,12 @@ LTLIBRARIES = $(noinst_LTLIBRARIES)
 libsanitizer_common_la_LIBADD =
 am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
 	sanitizer_flags.lo sanitizer_libc.lo sanitizer_linux.lo \
-	sanitizer_mac.lo sanitizer_posix.lo sanitizer_printf.lo \
-	sanitizer_stackdepot.lo sanitizer_stacktrace.lo \
-	sanitizer_symbolizer.lo sanitizer_symbolizer_itanium.lo \
-	sanitizer_symbolizer_linux.lo sanitizer_symbolizer_mac.lo \
-	sanitizer_symbolizer_win.lo sanitizer_win.lo
+	sanitizer_mac.lo sanitizer_platform_limits_posix.lo \
+	sanitizer_posix.lo sanitizer_printf.lo sanitizer_stackdepot.lo \
+	sanitizer_stacktrace.lo sanitizer_symbolizer.lo \
+	sanitizer_symbolizer_itanium.lo sanitizer_symbolizer_linux.lo \
+	sanitizer_symbolizer_mac.lo sanitizer_symbolizer_win.lo \
+	sanitizer_win.lo
 am_libsanitizer_common_la_OBJECTS = $(am__objects_1)
 libsanitizer_common_la_OBJECTS = $(am_libsanitizer_common_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@
@@ -230,6 +231,7 @@ sanitizer_common_files = \
         sanitizer_libc.cc \
         sanitizer_linux.cc \
         sanitizer_mac.cc \
+	sanitizer_platform_limits_posix.cc \
         sanitizer_posix.cc \
         sanitizer_printf.cc \
         sanitizer_stackdepot.cc \
@@ -340,6 +342,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_libc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_mac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_posix.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_posix.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_printf.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stackdepot.Plo@am__quote@
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cc b/libsanitizer/sanitizer_common/sanitizer_common.cc
index 4447c346eba0..f8d2d0e3fe5c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_common.cc
@@ -43,7 +43,7 @@ void NORETURN Die() {
   if (DieCallback) {
     DieCallback();
   }
-  Exit(1);
+  internal__exit(1);
 }
 
 static CheckFailedCallbackType CheckFailedCallback;
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
index 109966ba3608..302dc7427692 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.h
+++ b/libsanitizer/sanitizer_common/sanitizer_common.h
@@ -124,6 +124,7 @@ void DumpProcessMap();
 bool FileExists(const char *filename);
 const char *GetEnv(const char *name);
 const char *GetPwd();
+u32 GetUid();
 void ReExec();
 bool StackSizeIsUnlimited();
 void SetStackSizeLimitInBytes(uptr limit);
@@ -137,7 +138,6 @@ void SortArray(uptr *array, uptr size);
 
 // Exit
 void NORETURN Abort();
-void NORETURN Exit(int exitcode);
 void NORETURN Die();
 void NORETURN SANITIZER_INTERFACE_ATTRIBUTE
 CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2);
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
index 4ba7b8fee9f6..af27603ebdde 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
@@ -124,8 +124,8 @@ INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count,
 #endif
 
 #if SANITIZER_INTERCEPT_PRCTL
-INTERCEPTOR(int, prctl, int option, unsigned long arg2,
-            unsigned long arg3,                       // NOLINT
+INTERCEPTOR(int, prctl, int option,
+            unsigned long arg2, unsigned long arg3,   // NOLINT
             unsigned long arg4, unsigned long arg5) { // NOLINT
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5);
@@ -144,6 +144,100 @@ INTERCEPTOR(int, prctl, int option, unsigned long arg2,
 #define INIT_PRCTL
 #endif // SANITIZER_INTERCEPT_PRCTL
 
+#if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
+INTERCEPTOR(void *, localtime, unsigned long *timep) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, localtime, timep);
+  void *res = REAL(localtime)(timep);
+  if (res) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+  }
+  return res;
+}
+INTERCEPTOR(void *, localtime_r, unsigned long *timep, void *result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, localtime_r, timep, result);
+  void *res = REAL(localtime_r)(timep, result);
+  if (res) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+  }
+  return res;
+}
+INTERCEPTOR(void *, gmtime, unsigned long *timep) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, gmtime, timep);
+  void *res = REAL(gmtime)(timep);
+  if (res) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+  }
+  return res;
+}
+INTERCEPTOR(void *, gmtime_r, unsigned long *timep, void *result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, gmtime_r, timep, result);
+  void *res = REAL(gmtime_r)(timep, result);
+  if (res) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+  }
+  return res;
+}
+INTERCEPTOR(char *, ctime, unsigned long *timep) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, ctime, timep);
+  char *res = REAL(ctime)(timep);
+  if (res) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  }
+  return res;
+}
+INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, ctime_r, timep, result);
+  char *res = REAL(ctime_r)(timep, result);
+  if (res) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  }
+  return res;
+}
+INTERCEPTOR(char *, asctime, void *tm) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm);
+  char *res = REAL(asctime)(tm);
+  if (res) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  }
+  return res;
+}
+INTERCEPTOR(char *, asctime_r, void *tm, char *result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result);
+  char *res = REAL(asctime_r)(tm, result);
+  if (res) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  }
+  return res;
+}
+#define INIT_LOCALTIME_AND_FRIENDS               \
+  INTERCEPT_FUNCTION(localtime);                 \
+  INTERCEPT_FUNCTION(localtime_r);               \
+  INTERCEPT_FUNCTION(gmtime);                    \
+  INTERCEPT_FUNCTION(gmtime_r);                  \
+  INTERCEPT_FUNCTION(ctime);                     \
+  INTERCEPT_FUNCTION(ctime_r);                   \
+  INTERCEPT_FUNCTION(asctime);                   \
+  INTERCEPT_FUNCTION(asctime_r);
+#else
+#define INIT_LOCALTIME_AND_FRIENDS
+#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
+
 #if SANITIZER_INTERCEPT_SCANF
 
 #include "sanitizer_common_interceptors_scanf.inc"
@@ -170,6 +264,7 @@ VSCANF_INTERCEPTOR_IMPL(vsscanf, true, str, format, ap)
 INTERCEPTOR(int, vfscanf, void *stream, const char *format, va_list ap)
 VSCANF_INTERCEPTOR_IMPL(vfscanf, true, stream, format, ap)
 
+#if SANITIZER_INTERCEPT_ISOC99_SCANF
 INTERCEPTOR(int, __isoc99_vscanf, const char *format, va_list ap)
 VSCANF_INTERCEPTOR_IMPL(__isoc99_vscanf, false, format, ap)
 
@@ -179,6 +274,7 @@ VSCANF_INTERCEPTOR_IMPL(__isoc99_vsscanf, false, str, format, ap)
 
 INTERCEPTOR(int, __isoc99_vfscanf, void *stream, const char *format, va_list ap)
 VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
+#endif  // SANITIZER_INTERCEPT_ISOC99_SCANF
 
 #define SCANF_INTERCEPTOR_IMPL(name, vname, ...)                               \
   {                                                                            \
@@ -200,6 +296,7 @@ SCANF_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
 INTERCEPTOR(int, sscanf, const char *str, const char *format, ...)
 SCANF_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
 
+#if SANITIZER_INTERCEPT_ISOC99_SCANF
 INTERCEPTOR(int, __isoc99_scanf, const char *format, ...)
 SCANF_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
 
@@ -208,6 +305,7 @@ SCANF_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format)
 
 INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...)
 SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
+#endif
 
 #define INIT_SCANF                                                             \
   INTERCEPT_FUNCTION(scanf);                                                   \
@@ -235,4 +333,5 @@ SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
   INIT_WRITE;                                                                  \
   INIT_PWRITE;                                                                 \
   INIT_PWRITE64;                                                               \
+  INIT_LOCALTIME_AND_FRIENDS;                                                  \
   INIT_SCANF;
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cc b/libsanitizer/sanitizer_common/sanitizer_flags.cc
index 837738ceb81c..2152c7bdff4d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.cc
@@ -36,7 +36,8 @@ static bool GetFlagValue(const char *env, const char *name,
       pos += 1;
       end = internal_strchr(pos, '\'');
     } else {
-      end = internal_strchr(pos, ' ');
+      // Read until the next space or colon.
+      end = pos + internal_strcspn(pos, " :");
     }
     if (end == 0)
       end = pos + internal_strlen(pos);
diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
index 1a25b70c23ec..577c9a9c17fc 100644
--- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
+++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
@@ -29,7 +29,7 @@
 # define SANITIZER_SUPPORTS_WEAK_HOOKS 0
 #endif
 
-// __has_feature
+// GCC does not understand __has_feature
 #if !defined(__has_feature)
 # define __has_feature(x) 0
 #endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.h b/libsanitizer/sanitizer_common/sanitizer_libc.h
index 7a9774406fa4..16239413356f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libc.h
+++ b/libsanitizer/sanitizer_common/sanitizer_libc.h
@@ -43,6 +43,7 @@ char *internal_strrchr(const char *s, int c);
 char *internal_strstr(const char *haystack, const char *needle);
 // Works only for base=10 and doesn't set errno.
 s64 internal_simple_strtoll(const char *nptr, char **endptr, int base);
+int internal_snprintf(char *buffer, uptr length, const char *format, ...);
 
 // Return true if all bytes in [mem, mem+size) are zero.
 // Optimized for the case when the result is true.
@@ -68,14 +69,15 @@ fd_t 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_readlink(const char *path, char *buf, uptr bufsize);
-int internal_snprintf(char *buffer, uptr length, const char *format, ...);
+void NORETURN internal__exit(int exitcode);
 
 // Threading
 int internal_sched_yield();
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cc b/libsanitizer/sanitizer_common/sanitizer_linux.cc
index 3d3aa0b00bdc..06e5a0a64410 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.cc
@@ -138,6 +138,11 @@ int internal_sched_yield() {
   return syscall(__NR_sched_yield);
 }
 
+void internal__exit(int exitcode) {
+  syscall(__NR_exit_group, exitcode);
+  Die();  // Unreachable.
+}
+
 // ----------------- sanitizer_common.h
 bool FileExists(const char *filename) {
 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
@@ -232,6 +237,21 @@ const char *GetEnv(const char *name) {
   return 0;  // Not found.
 }
 
+#ifdef __GLIBC__
+
+extern "C" {
+  extern void *__libc_stack_end;
+}
+
+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__
+
 static void ReadNullSepFileToArray(const char *path, char ***arr,
                                    int arr_size) {
   char *buff;
@@ -251,12 +271,20 @@ static void ReadNullSepFileToArray(const char *path, char ***arr,
   (*arr)[count] = 0;
 }
 
+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);
+}
+
+#endif  // __GLIBC__
+
 void ReExec() {
-  static const int kMaxArgv = 100, kMaxEnvp = 1000;
   char **argv, **envp;
-  ReadNullSepFileToArray("/proc/self/cmdline", &argv, kMaxArgv);
-  ReadNullSepFileToArray("/proc/self/environ", &envp, kMaxEnvp);
-  execve(argv[0], argv, envp);
+  GetArgsAndEnv(&argv, &envp);
+  execve("/proc/self/exe", argv, envp);
+  Printf("execve failed, errno %d\n", errno);
+  Die();
 }
 
 void PrepareForSandboxing() {
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cc b/libsanitizer/sanitizer_common/sanitizer_mac.cc
index 309b5a94005a..d7885bb35096 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.cc
@@ -104,6 +104,10 @@ int internal_sched_yield() {
   return sched_yield();
 }
 
+void internal__exit(int exitcode) {
+  _exit(exitcode);
+}
+
 // ----------------- sanitizer_common.h
 bool FileExists(const char *filename) {
   struct stat st;
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
index 2c60253c5330..9b40c0cc523b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
@@ -14,6 +14,7 @@
 
 #if !defined(_WIN32)
 # define SI_NOT_WINDOWS 1
+# include "sanitizer_platform_limits_posix.h"
 #else
 # define SI_NOT_WINDOWS 0
 #endif
@@ -24,6 +25,12 @@
 # define SI_LINUX_NOT_ANDROID 0
 #endif
 
+#if defined(__linux__)
+# define SI_LINUX 1
+#else
+# define SI_LINUX 0
+#endif
+
 # define SANITIZER_INTERCEPT_READ   SI_NOT_WINDOWS
 # define SANITIZER_INTERCEPT_PREAD  SI_NOT_WINDOWS
 # define SANITIZER_INTERCEPT_WRITE  SI_NOT_WINDOWS
@@ -33,4 +40,7 @@
 # define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID
 # define SANITIZER_INTERCEPT_PRCTL   SI_LINUX_NOT_ANDROID
 
+# define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_NOT_WINDOWS
+
 # define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
new file mode 100644
index 000000000000..c4be1aa42da0
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -0,0 +1,68 @@
+//===-- sanitizer_platform_limits_posix.cc --------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer common code.
+//
+// Sizes and layouts of platform-specific POSIX data structures.
+//===----------------------------------------------------------------------===//
+
+#if defined(__linux__) || defined(__APPLE__)
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_posix.h"
+
+#include <dirent.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <time.h>
+
+#if defined(__linux__)
+#include <sys/vfs.h>
+#include <sys/epoll.h>
+#endif // __linux__
+
+namespace __sanitizer {
+  unsigned struct_utsname_sz = sizeof(struct utsname);
+  unsigned struct_stat_sz = sizeof(struct stat);
+  unsigned struct_stat64_sz = sizeof(struct stat64);
+  unsigned struct_rusage_sz = sizeof(struct rusage);
+  unsigned struct_tm_sz = sizeof(struct tm);
+
+#if defined(__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__
+
+#if defined(__linux__) && !defined(__ANDROID__)
+  unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
+  unsigned struct_statfs64_sz = sizeof(struct statfs64);
+#endif // __linux__ && !__ANDROID__
+
+  void* __sanitizer_get_msghdr_iov_iov_base(void* msg, int idx) {
+    return ((struct msghdr *)msg)->msg_iov[idx].iov_base;
+  }
+
+  uptr __sanitizer_get_msghdr_iov_iov_len(void* msg, int idx) {
+    return ((struct msghdr *)msg)->msg_iov[idx].iov_len;
+  }
+
+  uptr __sanitizer_get_msghdr_iovlen(void* msg) {
+    return ((struct msghdr *)msg)->msg_iovlen;
+  }
+
+  uptr __sanitizer_get_socklen_t(void* socklen_ptr) {
+    return *(socklen_t*)socklen_ptr;
+  }
+}  // namespace __sanitizer
+
+#endif  // __linux__ || __APPLE__
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
new file mode 100644
index 000000000000..dd53da94be6b
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -0,0 +1,41 @@
+//===-- sanitizer_platform_limits_posix.h ---------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer common code.
+//
+// Sizes and layouts of platform-specific POSIX data structures.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H
+#define SANITIZER_PLATFORM_LIMITS_POSIX_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;
+
+#if defined(__linux__)
+  extern unsigned struct_rlimit_sz;
+  extern unsigned struct_dirent_sz;
+  extern unsigned struct_statfs_sz;
+  extern unsigned struct_epoll_event_sz;
+#endif // __linux__
+
+#if defined(__linux__) && !defined(__ANDROID__)
+  extern unsigned struct_rlimit64_sz;
+  extern unsigned struct_statfs64_sz;
+#endif // __linux__ && !__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);
+}  // namespace __sanitizer
+
+#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cc b/libsanitizer/sanitizer_common/sanitizer_posix.cc
index 48c5ebaef3e4..1c6ff0a2ebbe 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.cc
@@ -42,6 +42,10 @@ int GetPid() {
   return getpid();
 }
 
+u32 GetUid() {
+  return getuid();
+}
+
 uptr GetThreadSelf() {
   return (uptr)pthread_self();
 }
@@ -203,10 +207,6 @@ void SleepForMillis(int millis) {
   usleep(millis * 1000);
 }
 
-void Exit(int exitcode) {
-  _exit(exitcode);
-}
-
 void Abort() {
   abort();
 }
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
index 259da0082e3e..e14ea447264a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
@@ -129,8 +129,9 @@ void StackTrace::FastUnwindStack(uptr pc, uptr bp,
   CHECK(size == 0 && trace[0] == pc);
   size = 1;
   uhwptr *frame = (uhwptr *)bp;
-  uhwptr *prev_frame = frame;
-  while (frame >= prev_frame &&
+  uhwptr *prev_frame = frame - 1;
+  // 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 &&
          size < max_size) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc
index bb1c40f96136..01f1e4588da7 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc
@@ -97,7 +97,7 @@ bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
     for (int fd = getdtablesize(); fd > 2; fd--)
       internal_close(fd);
     execl(path_to_symbolizer, path_to_symbolizer, (char*)0);
-    Exit(1);
+    internal__exit(1);
   }
 
   // Continue execution in parent process.
diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_win.cc
index 3d5cde11cf81..695265594b3c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_win.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_win.cc
@@ -129,6 +129,10 @@ const char *GetPwd() {
   UNIMPLEMENTED();
 }
 
+u32 GetUid() {
+  UNIMPLEMENTED();
+}
+
 void DumpProcessMap() {
   UNIMPLEMENTED();
 }
@@ -161,10 +165,6 @@ void SleepForMillis(int millis) {
   Sleep(millis);
 }
 
-void Exit(int exitcode) {
-  _exit(exitcode);
-}
-
 void Abort() {
   abort();
   _exit(-1);  // abort is not NORETURN on Windows.
@@ -251,6 +251,10 @@ int internal_sched_yield() {
   return 0;
 }
 
+void internal__exit(int exitcode) {
+  _exit(exitcode);
+}
+
 // ---------------------- BlockingMutex ---------------- {{{1
 const uptr LOCK_UNINITIALIZED = 0;
 const uptr LOCK_READY = (uptr)-1;
diff --git a/libsanitizer/tsan/tsan_platform_linux.cc b/libsanitizer/tsan/tsan_platform_linux.cc
index def91559d5ea..f7b05f2bf8ff 100644
--- a/libsanitizer/tsan/tsan_platform_linux.cc
+++ b/libsanitizer/tsan/tsan_platform_linux.cc
@@ -241,7 +241,7 @@ const char *InitializePlatform() {
   g_tls_size = (uptr)InitTlsSize();
   InitDataSeg();
 #endif
-  return getenv(kTsanOptionsEnv);
+  return GetEnv(kTsanOptionsEnv);
 }
 
 void FinalizePlatform() {
diff --git a/libsanitizer/tsan/tsan_platform_mac.cc b/libsanitizer/tsan/tsan_platform_mac.cc
index 808d99c0207f..b247468c8294 100644
--- a/libsanitizer/tsan/tsan_platform_mac.cc
+++ b/libsanitizer/tsan/tsan_platform_mac.cc
@@ -80,7 +80,7 @@ const char *InitializePlatform() {
     setrlimit(RLIMIT_CORE, (rlimit*)&lim);
   }
 
-  return getenv(kTsanOptionsEnv);
+  return GetEnv(kTsanOptionsEnv);
 }
 
 void FinalizePlatform() {
diff --git a/libsanitizer/tsan/tsan_platform_windows.cc b/libsanitizer/tsan/tsan_platform_windows.cc
index 74b9020d0774..376dc08688be 100644
--- a/libsanitizer/tsan/tsan_platform_windows.cc
+++ b/libsanitizer/tsan/tsan_platform_windows.cc
@@ -32,7 +32,7 @@ void FlushShadowMemory() {
 }
 
 const char *InitializePlatform() {
-  return getenv(kTsanOptionsEnv);
+  return GetEnv(kTsanOptionsEnv);
 }
 
 void FinalizePlatform() {
diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
index 717f45997052..e939921049a7 100644
--- a/libsanitizer/tsan/tsan_rtl.h
+++ b/libsanitizer/tsan/tsan_rtl.h
@@ -590,6 +590,8 @@ void MemoryAccessImpl(ThreadState *thr, uptr addr,
     u64 *shadow_mem, Shadow cur);
 void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
     uptr size, bool is_write);
+void MemoryAccessRangeStep(ThreadState *thr, uptr pc, uptr addr,
+    uptr size, uptr step, bool is_write);
 
 const int kSizeLog1 = 0;
 const int kSizeLog2 = 1;
diff --git a/libsanitizer/tsan/tsan_rtl_thread.cc b/libsanitizer/tsan/tsan_rtl_thread.cc
index 9c89417ad680..e30916dc6272 100644
--- a/libsanitizer/tsan/tsan_rtl_thread.cc
+++ b/libsanitizer/tsan/tsan_rtl_thread.cc
@@ -420,4 +420,26 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
         shadow_mem, cur);
   }
 }
+
+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/libsanitizer/tsan/tsan_stat.cc b/libsanitizer/tsan/tsan_stat.cc
index cd88d2df9281..fbec4225d9cb 100644
--- a/libsanitizer/tsan/tsan_stat.cc
+++ b/libsanitizer/tsan/tsan_stat.cc
@@ -263,6 +263,14 @@ void StatOutput(u64 *stat) {
   name[StatInt___isoc99_fscanf]          = "  fscanf                          ";
   name[StatInt_on_exit]                  = "  on_exit                         ";
   name[StatInt___cxa_atexit]             = "  __cxa_atexit                    ";
+  name[StatInt_localtime]                = "  localtime                       ";
+  name[StatInt_localtime_r]              = "  localtime_r                     ";
+  name[StatInt_gmtime]                   = "  gmtime                          ";
+  name[StatInt_gmtime_r]                 = "  gmtime_r                        ";
+  name[StatInt_ctime]                    = "  ctime                           ";
+  name[StatInt_ctime_r]                  = "  ctime_r                         ";
+  name[StatInt_asctime]                  = "  asctime                         ";
+  name[StatInt_asctime_r]                = "  asctime_r                       ";
 
   name[StatAnnotation]                   = "Dynamic annotations               ";
   name[StatAnnotateHappensBefore]        = "  HappensBefore                   ";
diff --git a/libsanitizer/tsan/tsan_stat.h b/libsanitizer/tsan/tsan_stat.h
index 1d6c54cdd4f7..8b08a024be26 100644
--- a/libsanitizer/tsan/tsan_stat.h
+++ b/libsanitizer/tsan/tsan_stat.h
@@ -262,6 +262,14 @@ enum StatType {
   StatInt___isoc99_fscanf,
   StatInt_on_exit,
   StatInt___cxa_atexit,
+  StatInt_localtime,
+  StatInt_localtime_r,
+  StatInt_gmtime,
+  StatInt_gmtime_r,
+  StatInt_ctime,
+  StatInt_ctime_r,
+  StatInt_asctime,
+  StatInt_asctime_r,
 
   // Dynamic annotations.
   StatAnnotation,
diff --git a/libsanitizer/tsan/tsan_suppressions.cc b/libsanitizer/tsan/tsan_suppressions.cc
index b6c54db2c513..8ee8de7c2788 100644
--- a/libsanitizer/tsan/tsan_suppressions.cc
+++ b/libsanitizer/tsan/tsan_suppressions.cc
@@ -138,7 +138,7 @@ void InitializeSuppressions() {
   g_suppressions = SuppressionParse(0, supp);
 #ifndef TSAN_GO
   supp = __tsan_default_suppressions();
-  g_suppressions = SuppressionParse(0, supp);
+  g_suppressions = SuppressionParse(g_suppressions, supp);
 #endif
 }
 
-- 
GitLab