public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* libsanitizer merge from upstream r175042
@ 2013-02-13  9:20 Konstantin Serebryany
  2013-02-13  9:51 ` Jakub Jelinek
  2013-02-13 18:29 ` H.J. Lu
  0 siblings, 2 replies; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-13  9:20 UTC (permalink / raw)
  To: GCC Patches, Jakub Jelinek, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

[-- Attachment #1: Type: text/plain, Size: 807 bytes --]

Hi,

The attached patch is the libsanitizer merge from upstream r175042.

Lots of changes. Among other things:
 - x86_64 linux: change the shadow offset to 0x7fff8000 (~5% speedup)
 - the new asan allocator is enabled on Mac (was enabled on Linux before).
 - tsan finds races between atomic and plain accesses
 - better scanf interceptor, enabled by default
 - don't include linux/futex.h (fixes PR56128)
 - simple tests seem to work (again?) on PowerPC64 with 44-bit address
space (46 AS not tested)

Patch for libsanitizer is automatically generated by libsanitizer/merge.sh
Tested with
rm -rf */{*/,}libsanitizer \
  && make -j 50 \
  && make -C gcc check-g{cc,++}
RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} asan.exp'

Our internal LLVM bots (Linux, Mac and Android) are green.

Ok to commit?

--kcc

[-- Attachment #2: libsanitizer-r175042.patch --]
[-- Type: application/octet-stream, Size: 219062 bytes --]

Index: libsanitizer/sanitizer_common/sanitizer_stacktrace.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_stacktrace.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_stacktrace.h	(working copy)
@@ -55,6 +55,10 @@
                               u32 *compressed, uptr size);
 };
 
+
+const char *StripPathPrefix(const char *filepath,
+                            const char *strip_file_prefix);
+
 }  // namespace __sanitizer
 
 // Use this macro if you want to print stack trace with the caller
Index: libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h	(working copy)
@@ -33,4 +33,4 @@
 # define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID
 # define SANITIZER_INTERCEPT_PRCTL   SI_LINUX_NOT_ANDROID
 
-# define SANITIZER_INTERCEPT_SCANF 0
+# define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
Index: libsanitizer/sanitizer_common/sanitizer_common.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_common.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_common.h	(working copy)
@@ -17,6 +17,7 @@
 #include "sanitizer_internal_defs.h"
 
 namespace __sanitizer {
+struct StackTrace;
 
 // Constants.
 const uptr kWordSize = SANITIZER_WORDSIZE / 8;
@@ -28,6 +29,8 @@
 const uptr kCacheLineSize = 64;
 #endif
 
+extern const char *SanitizerToolName;  // Can be changed by the tool.
+
 uptr GetPageSize();
 uptr GetPageSizeCached();
 uptr GetMmapGranularity();
@@ -103,6 +106,7 @@
 void Report(const char *format, ...);
 void SetPrintfAndReportCallback(void (*callback)(const char *));
 
+fd_t 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',
@@ -152,20 +156,79 @@
                                        u64, u64);
 void SetCheckFailedCallback(CheckFailedCallbackType callback);
 
+// Construct a one-line string like
+//  SanitizerToolName: error_type file:line function
+// and call __sanitizer_report_error_summary on it.
+void ReportErrorSummary(const char *error_type, const char *file,
+                        int line, const char *function);
+
 // Math
+#if defined(_WIN32) && !defined(__clang__)
+extern "C" {
+unsigned char _BitScanForward(unsigned long *index, unsigned long mask);  // NOLINT
+unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);  // NOLINT
+#if defined(_WIN64)
+unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask);  // NOLINT
+unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask);  // NOLINT
+#endif
+}
+#endif
+
+INLINE uptr MostSignificantSetBitIndex(uptr x) {
+  CHECK(x != 0);
+  unsigned long up;  // NOLINT
+#if !defined(_WIN32) || defined(__clang__)
+  up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x);
+#elif defined(_WIN64)
+  _BitScanReverse64(&up, x);
+#else
+  _BitScanReverse(&up, x);
+#endif
+  return up;
+}
+
 INLINE bool IsPowerOfTwo(uptr x) {
   return (x & (x - 1)) == 0;
 }
+
+INLINE uptr RoundUpToPowerOfTwo(uptr size) {
+  CHECK(size);
+  if (IsPowerOfTwo(size)) return size;
+
+  uptr up = MostSignificantSetBitIndex(size);
+  CHECK(size < (1ULL << (up + 1)));
+  CHECK(size > (1ULL << up));
+  return 1UL << (up + 1);
+}
+
 INLINE uptr RoundUpTo(uptr size, uptr boundary) {
   CHECK(IsPowerOfTwo(boundary));
   return (size + boundary - 1) & ~(boundary - 1);
 }
+
 INLINE uptr RoundDownTo(uptr x, uptr boundary) {
   return x & ~(boundary - 1);
 }
+
 INLINE bool IsAligned(uptr a, uptr alignment) {
   return (a & (alignment - 1)) == 0;
 }
+
+INLINE uptr Log2(uptr x) {
+  CHECK(IsPowerOfTwo(x));
+#if !defined(_WIN32) || defined(__clang__)
+  return __builtin_ctzl(x);
+#elif defined(_WIN64)
+  unsigned long ret;  // NOLINT
+  _BitScanForward64(&ret, x);
+  return ret;
+#else
+  unsigned long ret;  // NOLINT
+  _BitScanForward(&ret, x);
+  return ret;
+#endif
+}
+
 // Don't use std::min, std::max or std::swap, to minimize dependency
 // on libstdc++.
 template<class T> T Min(T a, T b) { return a < b ? a : b; }
Index: libsanitizer/sanitizer_common/sanitizer_win.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_win.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_win.cc	(working copy)
@@ -95,6 +95,11 @@
                       MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
 }
 
+void FlushUnneededShadowMemory(uptr addr, uptr size) {
+  // This is almost useless on 32-bits.
+  // FIXME: add madvice-analog when we move to 64-bits.
+}
+
 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
   // FIXME: shall we do anything here on Windows?
   return true;
@@ -189,10 +194,18 @@
   return _isatty(fd);
 }
 
-fd_t internal_open(const char *filename, bool write) {
+fd_t internal_open(const char *filename, int flags) {
   UNIMPLEMENTED();
 }
 
+fd_t internal_open(const char *filename, int flags, u32 mode) {
+  UNIMPLEMENTED();
+}
+
+fd_t OpenFile(const char *filename, bool write) {
+  UNIMPLEMENTED();
+}
+
 uptr internal_read(fd_t fd, void *buf, uptr count) {
   UNIMPLEMENTED();
 }
@@ -209,6 +222,18 @@
   return ret;
 }
 
+int internal_stat(const char *path, void *buf) {
+  UNIMPLEMENTED();
+}
+
+int internal_lstat(const char *path, void *buf) {
+  UNIMPLEMENTED();
+}
+
+int internal_fstat(fd_t fd, void *buf) {
+  UNIMPLEMENTED();
+}
+
 uptr internal_filesize(fd_t fd) {
   UNIMPLEMENTED();
 }
@@ -227,10 +252,8 @@
 }
 
 // ---------------------- BlockingMutex ---------------- {{{1
-enum LockState {
-  LOCK_UNINITIALIZED = 0,
-  LOCK_READY = -1,
-};
+const uptr LOCK_UNINITIALIZED = 0;
+const uptr LOCK_READY = (uptr)-1;
 
 BlockingMutex::BlockingMutex(LinkerInitialized li) {
   // FIXME: see comments in BlockingMutex::Lock() for the details.
@@ -252,12 +275,12 @@
     // locks while we're starting in one thread to avoid double-init races.
   }
   EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
-  CHECK(owner_ == LOCK_READY);
+  CHECK_EQ(owner_, LOCK_READY);
   owner_ = GetThreadSelf();
 }
 
 void BlockingMutex::Unlock() {
-  CHECK(owner_ == GetThreadSelf());
+  CHECK_EQ(owner_, GetThreadSelf());
   owner_ = LOCK_READY;
   LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
 }
Index: libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_symbolizer.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_symbolizer.cc	(working copy)
@@ -174,6 +174,53 @@
 
 static LowLevelAllocator symbolizer_allocator;  // Linker initialized.
 
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
+                                char *Buffer, int MaxLength);
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
+                                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) {
+      void *mem = symbolizer_allocator.Allocate(sizeof(InternalSymbolizer));
+      return new(mem) InternalSymbolizer();
+    }
+    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;
+    if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize))
+      return buffer_;
+    return 0;
+  }
+
+ private:
+  InternalSymbolizer() { }
+
+  static const int kBufferSize = 16 * 1024;
+  char buffer_[kBufferSize];
+};
+#else  // SANITIZER_SUPPORTS_WEAK_HOOKS
+
+class InternalSymbolizer {
+ public:
+  static InternalSymbolizer *get() { return 0; }
+  char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+    return 0;
+  }
+};
+
+#endif  // SANITIZER_SUPPORTS_WEAK_HOOKS
+
 class Symbolizer {
  public:
   uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
@@ -266,8 +313,23 @@
     return true;
   }
 
+  bool IsSymbolizerAvailable() {
+    if (internal_symbolizer_ == 0)
+      internal_symbolizer_ = InternalSymbolizer::get();
+    return internal_symbolizer_ || external_symbolizer_;
+  }
+
  private:
   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+    // First, try to use internal symbolizer.
+    if (internal_symbolizer_ == 0) {
+      internal_symbolizer_ = InternalSymbolizer::get();
+    }
+    if (internal_symbolizer_) {
+      return internal_symbolizer_->SendCommand(is_data, module_name,
+                                               module_offset);
+    }
+    // Otherwise, fall back to external symbolizer.
     if (external_symbolizer_ == 0) {
       ReportExternalSymbolizerError(
           "WARNING: Trying to symbolize code, but external "
@@ -322,6 +384,7 @@
   uptr n_modules_;
 
   ExternalSymbolizer *external_symbolizer_;  // Leaked.
+  InternalSymbolizer *internal_symbolizer_;  // Leaked.
 };
 
 static Symbolizer symbolizer;  // Linker initialized.
@@ -338,4 +401,8 @@
   return symbolizer.InitializeExternalSymbolizer(path_to_symbolizer);
 }
 
+bool IsSymbolizerAvailable() {
+  return symbolizer.IsSymbolizerAvailable();
+}
+
 }  // namespace __sanitizer
Index: libsanitizer/sanitizer_common/sanitizer_linux.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_linux.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_linux.cc	(working copy)
@@ -28,12 +28,15 @@
 #include <sys/syscall.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <sys/prctl.h>
 #include <unistd.h>
 #include <unwind.h>
 #include <errno.h>
-#include <sys/prctl.h>
-#include <linux/futex.h>
 
+// <linux/futex.h> is broken on some linux distributions.
+const int FUTEX_WAIT = 0;
+const int FUTEX_WAKE = 1;
+
 // Are we using 32-bit or 64-bit syscalls?
 // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
 // but it still needs to use 64-bit syscalls.
@@ -63,8 +66,16 @@
   return syscall(__NR_close, fd);
 }
 
-fd_t internal_open(const char *filename, bool write) {
-  return syscall(__NR_open, filename,
+fd_t internal_open(const char *filename, int flags) {
+  return syscall(__NR_open, filename, flags);
+}
+
+fd_t internal_open(const char *filename, int flags, u32 mode) {
+  return syscall(__NR_open, filename, flags, mode);
+}
+
+fd_t OpenFile(const char *filename, bool write) {
+  return internal_open(filename,
       write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
 }
 
@@ -80,16 +91,38 @@
   return res;
 }
 
+int internal_stat(const char *path, void *buf) {
+#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
+  return syscall(__NR_stat, path, buf);
+#else
+  return syscall(__NR_stat64, path, buf);
+#endif
+}
+
+int internal_lstat(const char *path, void *buf) {
+#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
+  return syscall(__NR_lstat, path, buf);
+#else
+  return syscall(__NR_lstat64, path, buf);
+#endif
+}
+
+int internal_fstat(fd_t fd, void *buf) {
+#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
+  return syscall(__NR_fstat, fd, buf);
+#else
+  return syscall(__NR_fstat64, fd, buf);
+#endif
+}
+
 uptr internal_filesize(fd_t fd) {
 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
   struct stat st;
-  if (syscall(__NR_fstat, fd, &st))
-    return -1;
 #else
   struct stat64 st;
-  if (syscall(__NR_fstat64, fd, &st))
+#endif
+  if (internal_fstat(fd, &st))
     return -1;
-#endif
   return (uptr)st.st_size;
 }
 
Index: libsanitizer/sanitizer_common/sanitizer_mac.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_mac.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_mac.cc	(working copy)
@@ -11,6 +11,12 @@
 //===----------------------------------------------------------------------===//
 
 #ifdef __APPLE__
+// 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
+#define _DARWIN_USE_64_BIT_INODE 1
+#endif
+#include <stdio.h>
 
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
@@ -46,11 +52,19 @@
   return close(fd);
 }
 
-fd_t internal_open(const char *filename, bool write) {
-  return open(filename,
-              write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
+fd_t internal_open(const char *filename, int flags) {
+  return open(filename, flags);
 }
 
+fd_t internal_open(const char *filename, int flags, u32 mode) {
+  return open(filename, flags, mode);
+}
+
+fd_t OpenFile(const char *filename, bool write) {
+  return internal_open(filename,
+      write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
+}
+
 uptr internal_read(fd_t fd, void *buf, uptr count) {
   return read(fd, buf, count);
 }
@@ -59,9 +73,21 @@
   return write(fd, buf, count);
 }
 
+int internal_stat(const char *path, void *buf) {
+  return stat(path, (struct stat *)buf);
+}
+
+int internal_lstat(const char *path, void *buf) {
+  return lstat(path, (struct stat *)buf);
+}
+
+int internal_fstat(fd_t fd, void *buf) {
+  return fstat(fd, (struct stat *)buf);
+}
+
 uptr internal_filesize(fd_t fd) {
   struct stat st;
-  if (fstat(fd, &st))
+  if (internal_fstat(fd, &st))
     return -1;
   return (uptr)st.st_size;
 }
Index: libsanitizer/sanitizer_common/sanitizer_symbolizer.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_symbolizer.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_symbolizer.h	(working copy)
@@ -67,6 +67,8 @@
 uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames);
 bool SymbolizeData(uptr address, DataInfo *info);
 
+bool IsSymbolizerAvailable();
+
 // Attempts to demangle the provided C++ mangled name.
 const char *Demangle(const char *Name);
 
Index: libsanitizer/sanitizer_common/sanitizer_internal_defs.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_internal_defs.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_internal_defs.h	(working copy)
@@ -11,7 +11,85 @@
 #ifndef SANITIZER_DEFS_H
 #define SANITIZER_DEFS_H
 
-#include "sanitizer/common_interface_defs.h"
+#if defined(_WIN32)
+// FIXME find out what we need on Windows. __declspec(dllexport) ?
+# define SANITIZER_INTERFACE_ATTRIBUTE
+# define SANITIZER_WEAK_ATTRIBUTE
+#elif defined(SANITIZER_GO)
+# define SANITIZER_INTERFACE_ATTRIBUTE
+# define SANITIZER_WEAK_ATTRIBUTE
+#else
+# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
+# define SANITIZER_WEAK_ATTRIBUTE  __attribute__((weak))
+#endif
+
+#ifdef __linux__
+# define SANITIZER_SUPPORTS_WEAK_HOOKS 1
+#else
+# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
+#endif
+
+// __has_feature
+#if !defined(__has_feature)
+# define __has_feature(x) 0
+#endif
+
+// For portability reasons we do not include stddef.h, stdint.h or any other
+// system header, but we do need some basic types that are not defined
+// in a portable way by the language itself.
+namespace __sanitizer {
+
+#if defined(_WIN64)
+// 64-bit Windows uses LLP64 data model.
+typedef unsigned long long uptr;  // NOLINT
+typedef signed   long long sptr;  // NOLINT
+#else
+typedef unsigned long uptr;  // NOLINT
+typedef signed   long sptr;  // NOLINT
+#endif  // defined(_WIN64)
+#if defined(__x86_64__)
+// Since x32 uses ILP32 data model in 64-bit hardware mode,  we must use
+// 64-bit pointer to unwind stack frame.
+typedef unsigned long long uhwptr;  // NOLINT
+#else
+typedef uptr uhwptr;   // NOLINT
+#endif
+typedef unsigned char u8;
+typedef unsigned short u16;  // NOLINT
+typedef unsigned int u32;
+typedef unsigned long long u64;  // NOLINT
+typedef signed   char s8;
+typedef signed   short s16;  // NOLINT
+typedef signed   int s32;
+typedef signed   long long s64;  // NOLINT
+typedef int fd_t;
+
+}  // namespace __sanitizer
+
+extern "C" {
+  // Tell the tools to write their reports to "path.<pid>" instead of stderr.
+  void __sanitizer_set_report_path(const char *path)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // Tell the tools to write their reports to given file descriptor instead of
+  // stderr.
+  void __sanitizer_set_report_fd(int fd)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // Notify the tools that the sandbox is going to be turned on. The reserved
+  // parameter will be used in the future to hold a structure with functions
+  // that the tools may call to bypass the sandbox.
+  void __sanitizer_sandbox_on_notify(void *reserved)
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // This function is called by the tool when it has just finished reporting
+  // an error. 'error_summary' is a one-line string that summarizes
+  // the error message. This function can be overridden by the client.
+  void __sanitizer_report_error_summary(const char *error_summary)
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+}  // extern "C"
+
+
 using namespace __sanitizer;  // NOLINT
 // ----------- ATTENTION -------------
 // This header should NOT include any other headers to avoid portability issues.
Index: libsanitizer/sanitizer_common/sanitizer_allocator.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_allocator.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_allocator.cc	(working copy)
@@ -73,4 +73,10 @@
   low_level_alloc_callback = callback;
 }
 
+bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) {
+  if (!size) return false;
+  uptr max = (uptr)-1L;
+  return (max / size) < n;
+}
+
 }  // namespace __sanitizer
Index: libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_stacktrace.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_stacktrace.cc	(working copy)
@@ -15,8 +15,9 @@
 #include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
-static const char *StripPathPrefix(const char *filepath,
-                                   const char *strip_file_prefix) {
+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);
   return filepath;
Index: libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc	(working copy)
@@ -6,139 +6,302 @@
 //===----------------------------------------------------------------------===//
 //
 // Scanf implementation for use in *Sanitizer interceptors.
+// Follows http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html
+// with a few common GNU extensions.
 //
 //===----------------------------------------------------------------------===//
 #include <stdarg.h>
 
-#ifdef _WIN32
-#define va_copy(dst, src) ((dst) = (src))
-#endif  // _WIN32
-
-struct ScanfSpec {
-  char c;
-  unsigned size;
+struct ScanfDirective {
+  int argIdx; // argument index, or -1 of not specified ("%n$")
+  int fieldWidth;
+  bool suppressed; // suppress assignment ("*")
+  bool allocate;   // allocate space ("m")
+  char lengthModifier[2];
+  char convSpecifier;
+  bool maybeGnuMalloc;
 };
 
-// One-letter specs.
-static const ScanfSpec scanf_specs[] = {
-  {'p', sizeof(void *)},
-  {'e', sizeof(float)},
-  {'E', sizeof(float)},
-  {'a', sizeof(float)},
-  {'f', sizeof(float)},
-  {'g', sizeof(float)},
-  {'d', sizeof(int)},
-  {'i', sizeof(int)},
-  {'o', sizeof(int)},
-  {'u', sizeof(int)},
-  {'x', sizeof(int)},
-  {'X', sizeof(int)},
-  {'n', sizeof(int)},
-  {'t', sizeof(PTRDIFF_T)},
-  {'z', sizeof(SIZE_T)},
-  {'j', sizeof(INTMAX_T)},
-  {'h', sizeof(short)}
-};
+static const char *parse_number(const char *p, int *out) {
+  *out = internal_atoll(p);
+  while (*p >= '0' && *p <= '9')
+    ++p;
+  return p;
+}
 
-static const unsigned scanf_specs_cnt =
-  sizeof(scanf_specs) / sizeof(scanf_specs[0]);
-
-// %ll?, %L?, %q? specs
-static const ScanfSpec scanf_llspecs[] = {
-  {'e', sizeof(long double)},
-  {'f', sizeof(long double)},
-  {'g', sizeof(long double)},
-  {'d', sizeof(long long)},
-  {'i', sizeof(long long)},
-  {'o', sizeof(long long)},
-  {'u', sizeof(long long)},
-  {'x', sizeof(long long)}
-};
-
-static const unsigned scanf_llspecs_cnt =
-  sizeof(scanf_llspecs) / sizeof(scanf_llspecs[0]);
-
-// %l? specs
-static const ScanfSpec scanf_lspecs[] = {
-  {'e', sizeof(double)},
-  {'f', sizeof(double)},
-  {'g', sizeof(double)},
-  {'d', sizeof(long)},
-  {'i', sizeof(long)},
-  {'o', sizeof(long)},
-  {'u', sizeof(long)},
-  {'x', sizeof(long)},
-  {'X', sizeof(long)},
-};
-
-static const unsigned scanf_lspecs_cnt =
-  sizeof(scanf_lspecs) / sizeof(scanf_lspecs[0]);
-
-static unsigned match_spec(const struct ScanfSpec *spec, unsigned n, char c) {
-  for (unsigned i = 0; i < n; ++i)
-    if (spec[i].c == c)
-      return spec[i].size;
-  return 0;
+static bool char_is_one_of(char c, const char *s) {
+  return !!internal_strchr(s, c);
 }
 
-static void scanf_common(void *ctx, const char *format, va_list ap_const) {
-  va_list aq;
-  va_copy(aq, ap_const);
+// Parse scanf format string. If a valid directive in encountered, it is
+// returned in dir. This function returns the pointer to the first
+// unprocessed character, or 0 in case of error.
+// In case of the end-of-string, a pointer to the closing \0 is returned.
+static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
+                                    ScanfDirective *dir) {
+  internal_memset(dir, 0, sizeof(*dir));
+  dir->argIdx = -1;
 
-  const char *p = format;
-  unsigned size;
-
   while (*p) {
     if (*p != '%') {
       ++p;
       continue;
     }
     ++p;
-    if (*p == '*' || *p == '%' || *p == 0) {
+    // %%
+    if (*p == '%') {
       ++p;
       continue;
     }
-    if (*p == '0' || (*p >= '1' && *p <= '9')) {
-      size = internal_atoll(p);
-      // +1 for the \0 at the end
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size + 1);
+    if (*p == '\0') {
+      return 0;
+    }
+    // %n$
+    if (*p >= '0' && *p <= '9') {
+      int number;
+      const char *q = parse_number(p, &number);
+      if (*q == '$') {
+        dir->argIdx = number;
+        p = q + 1;
+      }
+      // Otherwise, do not change p. This will be re-parsed later as the field
+      // width.
+    }
+    // *
+    if (*p == '*') {
+      dir->suppressed = true;
       ++p;
-      continue;
     }
-
-    if (*p == 'L' || *p == 'q') {
+    // Field width.
+    if (*p >= '0' && *p <= '9') {
+      p = parse_number(p, &dir->fieldWidth);
+      if (dir->fieldWidth <= 0)
+        return 0;
+    }
+    // m
+    if (*p == 'm') {
+      dir->allocate = true;
       ++p;
-      size = match_spec(scanf_llspecs, scanf_llspecs_cnt, *p);
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
-      continue;
     }
-
-    if (*p == 'l') {
+    // Length modifier.
+    if (char_is_one_of(*p, "jztLq")) {
+      dir->lengthModifier[0] = *p;
       ++p;
+    } else if (*p == 'h') {
+      dir->lengthModifier[0] = 'h';
+      ++p;
+      if (*p == 'h') {
+        dir->lengthModifier[1] = 'h';
+        ++p;
+      }
+    } else if (*p == 'l') {
+      dir->lengthModifier[0] = 'l';
+      ++p;
       if (*p == 'l') {
+        dir->lengthModifier[1] = 'l';
         ++p;
-        size = match_spec(scanf_llspecs, scanf_llspecs_cnt, *p);
-        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
-        continue;
-      } else {
-        size = match_spec(scanf_lspecs, scanf_lspecs_cnt, *p);
-        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
-        continue;
       }
     }
+    // Conversion specifier.
+    dir->convSpecifier = *p++;
+    // Consume %[...] expression.
+    if (dir->convSpecifier == '[') {
+      if (*p == '^')
+        ++p;
+      if (*p == ']')
+        ++p;
+      while (*p && *p != ']')
+        ++p;
+      if (*p == 0)
+        return 0; // unexpected end of string
+                  // Consume the closing ']'.
+      ++p;
+    }
+    // This is unfortunately ambiguous between old GNU extension
+    // of %as, %aS and %a[...] and newer POSIX %a followed by
+    // letters s, S or [.
+    if (allowGnuMalloc && dir->convSpecifier == 'a' &&
+        !dir->lengthModifier[0]) {
+      if (*p == 's' || *p == 'S') {
+        dir->maybeGnuMalloc = true;
+        ++p;
+      } else if (*p == '[') {
+        // Watch for %a[h-j%d], if % appears in the
+        // [...] range, then we need to give up, we don't know
+        // if scanf will parse it as POSIX %a [h-j %d ] or
+        // GNU allocation of string with range dh-j plus %.
+        const char *q = p + 1;
+        if (*q == '^')
+          ++q;
+        if (*q == ']')
+          ++q;
+        while (*q && *q != ']' && *q != '%')
+          ++q;
+        if (*q == 0 || *q == '%')
+          return 0;
+        p = q + 1; // Consume the closing ']'.
+        dir->maybeGnuMalloc = true;
+      }
+    }
+    break;
+  }
+  return p;
+}
 
-    if (*p == 'h' && *(p + 1) == 'h') {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), sizeof(char));
-      p += 2;
-      continue;
+// Returns true if the character is an integer conversion specifier.
+static bool scanf_is_integer_conv(char c) {
+  return char_is_one_of(c, "diouxXn");
+}
+
+// Returns true if the character is an floating point conversion specifier.
+static bool scanf_is_float_conv(char c) {
+  return char_is_one_of(c, "aAeEfFgG");
+}
+
+// Returns string output character size for string-like conversions,
+// or 0 if the conversion is invalid.
+static int scanf_get_char_size(ScanfDirective *dir) {
+  if (char_is_one_of(dir->convSpecifier, "CS")) {
+    // wchar_t
+    return 0;
+  }
+
+  if (char_is_one_of(dir->convSpecifier, "cs[")) {
+    if (dir->lengthModifier[0] == 'l')
+      // wchar_t
+      return 0;
+    else if (dir->lengthModifier[0] == 0)
+      return sizeof(char);
+    else
+      return 0;
+  }
+
+  return 0;
+}
+
+enum ScanfStoreSize {
+  // Store size not known in advance; can be calculated as strlen() of the
+  // destination buffer.
+  SSS_STRLEN = -1,
+  // Invalid conversion specifier.
+  SSS_INVALID = 0
+};
+
+// Returns the store size of a scanf directive (if >0), or a value of
+// ScanfStoreSize.
+static int scanf_get_store_size(ScanfDirective *dir) {
+  if (dir->allocate) {
+    if (!char_is_one_of(dir->convSpecifier, "cCsS["))
+      return SSS_INVALID;
+    return sizeof(char *);
+  }
+
+  if (dir->maybeGnuMalloc) {
+    if (dir->convSpecifier != 'a' || dir->lengthModifier[0])
+      return SSS_INVALID;
+    // This is ambiguous, so check the smaller size of char * (if it is
+    // a GNU extension of %as, %aS or %a[...]) and float (if it is
+    // POSIX %a followed by s, S or [ letters).
+    return sizeof(char *) < sizeof(float) ? sizeof(char *) : sizeof(float);
+  }
+
+  if (scanf_is_integer_conv(dir->convSpecifier)) {
+    switch (dir->lengthModifier[0]) {
+    case 'h':
+      return dir->lengthModifier[1] == 'h' ? sizeof(char) : sizeof(short);
+    case 'l':
+      return dir->lengthModifier[1] == 'l' ? sizeof(long long) : sizeof(long);
+    case 'L':
+      return sizeof(long long);
+    case 'j':
+      return sizeof(INTMAX_T);
+    case 'z':
+      return sizeof(SIZE_T);
+    case 't':
+      return sizeof(PTRDIFF_T);
+    case 0:
+      return sizeof(int);
+    default:
+      return SSS_INVALID;
     }
+  }
 
-    size = match_spec(scanf_specs, scanf_specs_cnt, *p);
-    if (size) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
-      ++p;
+  if (scanf_is_float_conv(dir->convSpecifier)) {
+    switch (dir->lengthModifier[0]) {
+    case 'L':
+    case 'q':
+      return sizeof(long double);
+    case 'l':
+      return dir->lengthModifier[1] == 'l' ? sizeof(long double)
+                                           : sizeof(double);
+    case 0:
+      return sizeof(float);
+    default:
+      return SSS_INVALID;
+    }
+  }
+
+  if (char_is_one_of(dir->convSpecifier, "sS[")) {
+    unsigned charSize = scanf_get_char_size(dir);
+    if (charSize == 0)
+      return SSS_INVALID;
+    if (dir->fieldWidth == 0)
+      return SSS_STRLEN;
+    return (dir->fieldWidth + 1) * charSize;
+  }
+
+  if (char_is_one_of(dir->convSpecifier, "cC")) {
+    unsigned charSize = scanf_get_char_size(dir);
+    if (charSize == 0)
+      return SSS_INVALID;
+    if (dir->fieldWidth == 0)
+      return charSize;
+    return dir->fieldWidth * charSize;
+  }
+
+  if (dir->convSpecifier == 'p') {
+    if (dir->lengthModifier[1] != 0)
+      return SSS_INVALID;
+    return sizeof(void *);
+  }
+
+  return SSS_INVALID;
+}
+
+// Common part of *scanf interceptors.
+// Process format string and va_list, and report all store ranges.
+// Stops when "consuming" n_inputs input items.
+static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
+                         const char *format, va_list aq) {
+  CHECK_GT(n_inputs, 0);
+  const char *p = format;
+
+  while (*p && n_inputs) {
+    ScanfDirective dir;
+    p = scanf_parse_next(p, allowGnuMalloc, &dir);
+    if (!p)
+      break;
+    if (dir.convSpecifier == 0) {
+      // This can only happen at the end of the format string.
+      CHECK_EQ(*p, 0);
+      break;
+    }
+    // Here the directive is valid. Do what it says.
+    if (dir.argIdx != -1) {
+      // Unsupported.
+      break;
+    }
+    if (dir.suppressed)
       continue;
+    int size = scanf_get_store_size(&dir);
+    if (size == SSS_INVALID)
+      break;
+    void *argp = va_arg(aq, void *);
+    if (dir.convSpecifier != 'n')
+      --n_inputs;
+    if (size == SSS_STRLEN) {
+      size = internal_strlen((const char *)argp) + 1;
     }
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
   }
-  va_end(aq);
 }
Index: libsanitizer/sanitizer_common/sanitizer_common.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_common.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_common.cc	(working copy)
@@ -14,6 +14,8 @@
 
 namespace __sanitizer {
 
+const char *SanitizerToolName = "SanitizerTool";
+
 uptr GetPageSizeCached() {
   static uptr PageSize;
   if (!PageSize)
@@ -64,7 +66,7 @@
   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 = internal_open(report_path_full.data(), true);
+  fd_t fd = OpenFile(report_path_full.data(), true);
   if (fd == kInvalidFd) {
     report_fd = kStderrFd;
     log_to_file = false;
@@ -103,7 +105,7 @@
   *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 = internal_open(file_name, /*write*/ false);
+    fd_t fd = OpenFile(file_name, /*write*/ false);
     if (fd == kInvalidFd) return 0;
     UnmapOrDie(*buff, *buff_size);
     *buff = (char*)MmapOrDie(size, __FUNCTION__);
@@ -188,6 +190,16 @@
   return (void*)res;
 }
 
+void ReportErrorSummary(const char *error_type, const char *file,
+                        int line, const char *function) {
+  const int kMaxSize = 1024;  // We don't want a summary too long.
+  InternalScopedBuffer<char> buff(kMaxSize);
+  internal_snprintf(buff.data(), kMaxSize, "%s: %s %s:%d %s",
+                    SanitizerToolName, error_type,
+                    file ? file : "??", line, function ? function : "??");
+  __sanitizer_report_error_summary(buff.data());
+}
+
 }  // namespace __sanitizer
 
 using namespace __sanitizer;  // NOLINT
@@ -220,4 +232,8 @@
   (void)reserved;
   PrepareForSandboxing();
 }
+
+void __sanitizer_report_error_summary(const char *error_summary) {
+  Printf("SUMMARY: %s\n", error_summary);
+}
 }  // extern "C"
Index: libsanitizer/sanitizer_common/sanitizer_lfstack.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_lfstack.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_lfstack.h	(working copy)
@@ -66,6 +66,6 @@
 
   atomic_uint64_t head_;
 };
-}
+}  // namespace __sanitizer
 
 #endif  // #ifndef SANITIZER_LFSTACK_H
Index: libsanitizer/sanitizer_common/sanitizer_posix.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_posix.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_posix.cc	(working copy)
@@ -56,12 +56,12 @@
     if (recursion_count) {
       // The Report() and CHECK calls below may call mmap recursively and fail.
       // If we went into recursion, just die.
-      RawWrite("AddressSanitizer is unable to mmap\n");
+      RawWrite("ERROR: Failed to mmap\n");
       Die();
     }
     recursion_count++;
-    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s: %s\n",
-           size, size, mem_type, strerror(errno));
+    Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %s\n",
+           SanitizerToolName, size, size, mem_type, strerror(errno));
     DumpProcessMap();
     CHECK("unable to mmap" && 0);
   }
@@ -72,8 +72,8 @@
   if (!addr || !size) return;
   int res = internal_munmap(addr, size);
   if (res != 0) {
-    Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
-           size, size, addr);
+    Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
+           SanitizerToolName, size, size, addr);
     CHECK("unable to unmap" && 0);
   }
 }
@@ -86,8 +86,9 @@
       MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
       -1, 0);
   if (p == (void*)-1)
-    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
-           size, size, fixed_addr, errno);
+    Report("ERROR: "
+           "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
+           SanitizerToolName, size, size, fixed_addr, errno);
   return p;
 }
 
@@ -99,8 +100,9 @@
       MAP_PRIVATE | MAP_ANON | MAP_FIXED,
       -1, 0);
   if (p == (void*)-1) {
-    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
-           size, size, fixed_addr, errno);
+    Report("ERROR:"
+           " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
+           SanitizerToolName, size, size, fixed_addr, errno);
     CHECK("unable to mmap" && 0);
   }
   return p;
@@ -118,7 +120,7 @@
 }
 
 void *MapFileToMemory(const char *file_name, uptr *buff_size) {
-  fd_t fd = internal_open(file_name, false);
+  fd_t fd = OpenFile(file_name, false);
   CHECK_NE(fd, kInvalidFd);
   uptr fsize = internal_filesize(fd);
   CHECK_NE(fsize, (uptr)-1);
@@ -187,7 +189,7 @@
   rlim.rlim_cur = limit;
   rlim.rlim_max = limit;
   if (setrlimit(RLIMIT_STACK, &rlim)) {
-    Report("setrlimit() failed %d\n", errno);
+    Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
     Die();
   }
   CHECK(!StackSizeIsUnlimited());
Index: libsanitizer/sanitizer_common/sanitizer_stackdepot.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_stackdepot.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_stackdepot.h	(working copy)
@@ -11,7 +11,7 @@
 #ifndef SANITIZER_STACKDEPOT_H
 #define SANITIZER_STACKDEPOT_H
 
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_internal_defs.h"
 
 namespace __sanitizer {
 
Index: libsanitizer/sanitizer_common/sanitizer_libc.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_libc.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_libc.cc	(working copy)
@@ -204,7 +204,7 @@
 }
 
 bool mem_is_zero(const char *beg, uptr size) {
-  CHECK_LE(size, 1UL << FIRST_32_SECOND_64(30, 40));  // Sanity check.
+  CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40));  // Sanity check.
   const char *end = beg + size;
   uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr));
   uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr));
Index: libsanitizer/sanitizer_common/sanitizer_quarantine.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_quarantine.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_quarantine.h	(working copy)
@@ -157,7 +157,7 @@
     atomic_store(&size_, Size() + add, memory_order_relaxed);
   }
 
-  QuarantineBatch *NOINLINE AllocBatch(Callback cb) {
+  NOINLINE QuarantineBatch* AllocBatch(Callback cb) {
     QuarantineBatch *b = (QuarantineBatch *)cb.Allocate(sizeof(*b));
     b->count = 0;
     b->size = 0;
@@ -165,6 +165,6 @@
     return b;
   }
 };
-}
+}  // namespace __sanitizer
 
 #endif  // #ifndef SANITIZER_QUARANTINE_H
Index: libsanitizer/sanitizer_common/sanitizer_libc.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_libc.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_libc.h	(working copy)
@@ -9,14 +9,13 @@
 // run-time libraries.
 // These tools can not use some of the libc functions directly because those
 // functions are intercepted. Instead, we implement a tiny subset of libc here.
-// NOTE: This file may be included into user code.
 //===----------------------------------------------------------------------===//
 #ifndef SANITIZER_LIBC_H
 #define SANITIZER_LIBC_H
 
 // ----------- ATTENTION -------------
 // This header should NOT include any other headers from sanitizer runtime.
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_internal_defs.h"
 
 namespace __sanitizer {
 
@@ -56,17 +55,24 @@
 int internal_munmap(void *addr, uptr length);
 
 // I/O
-typedef int fd_t;
 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);
 int internal_isatty(fd_t fd);
-fd_t internal_open(const char *filename, bool write);
+
+// 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_read(fd_t fd, void *buf, uptr count);
 uptr internal_write(fd_t fd, const void *buf, uptr count);
 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, ...);
Index: libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc	(working copy)
@@ -22,9 +22,13 @@
 
 #include <stdarg.h>
 
+#ifdef _WIN32
+#define va_copy(dst, src) ((dst) = (src))
+#endif // _WIN32
+
 #if SANITIZER_INTERCEPT_READ
 INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
-  void* ctx;
+  void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, count);
   SSIZE_T res = REAL(read)(fd, ptr, count);
   if (res > 0)
@@ -33,14 +37,14 @@
     COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
 }
-# define INIT_READ INTERCEPT_FUNCTION(read)
+#define INIT_READ INTERCEPT_FUNCTION(read)
 #else
-# define INIT_READ
+#define INIT_READ
 #endif
 
 #if SANITIZER_INTERCEPT_PREAD
 INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
-  void* ctx;
+  void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, offset);
   SSIZE_T res = REAL(pread)(fd, ptr, count, offset);
   if (res > 0)
@@ -49,14 +53,14 @@
     COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
 }
-# define INIT_PREAD INTERCEPT_FUNCTION(pread)
+#define INIT_PREAD INTERCEPT_FUNCTION(pread)
 #else
-# define INIT_PREAD
+#define INIT_PREAD
 #endif
 
 #if SANITIZER_INTERCEPT_PREAD64
 INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
-  void* ctx;
+  void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, offset);
   SSIZE_T res = REAL(pread64)(fd, ptr, count, offset);
   if (res > 0)
@@ -65,14 +69,14 @@
     COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
 }
-# define INIT_PREAD64 INTERCEPT_FUNCTION(pread64)
+#define INIT_PREAD64 INTERCEPT_FUNCTION(pread64)
 #else
-# define INIT_PREAD64
+#define INIT_PREAD64
 #endif
 
 #if SANITIZER_INTERCEPT_WRITE
 INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
-  void* ctx;
+  void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count);
   if (fd >= 0)
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
@@ -81,142 +85,154 @@
     COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
   return res;
 }
-# define INIT_WRITE INTERCEPT_FUNCTION(write)
+#define INIT_WRITE INTERCEPT_FUNCTION(write)
 #else
-# define INIT_WRITE
+#define INIT_WRITE
 #endif
 
 #if SANITIZER_INTERCEPT_PWRITE
-INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count) {
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count);
+INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count, offset);
   if (fd >= 0)
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
-  SSIZE_T res = REAL(pwrite)(fd, ptr, count);
+  SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset);
   if (res > 0)
     COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
   return res;
 }
-# define INIT_PWRITE INTERCEPT_FUNCTION(pwrite)
+#define INIT_PWRITE INTERCEPT_FUNCTION(pwrite)
 #else
-# define INIT_PWRITE
+#define INIT_PWRITE
 #endif
 
 #if SANITIZER_INTERCEPT_PWRITE64
-INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count) {
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count);
+INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count,
+            OFF64_T offset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count, offset);
   if (fd >= 0)
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
-  SSIZE_T res = REAL(pwrite64)(fd, ptr, count);
+  SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset);
   if (res > 0)
     COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
   return res;
 }
-# define INIT_PWRITE64 INTERCEPT_FUNCTION(pwrite64)
+#define INIT_PWRITE64 INTERCEPT_FUNCTION(pwrite64)
 #else
-# define INIT_PWRITE64
+#define INIT_PWRITE64
 #endif
 
 #if SANITIZER_INTERCEPT_PRCTL
-INTERCEPTOR(int, prctl, int option,
-            unsigned long arg2, unsigned long arg3,  // NOLINT
-            unsigned long arg4, unsigned long arg5) {  // NOLINT
-  void* ctx;
+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);
   static const int PR_SET_NAME = 15;
   int res = REAL(prctl(option, arg2, arg3, arg4, arg5));
   if (option == PR_SET_NAME) {
     char buff[16];
-    internal_strncpy(buff, (char*)arg2, 15);
+    internal_strncpy(buff, (char *)arg2, 15);
     buff[15] = 0;
     COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, buff);
   }
   return res;
 }
-# define INIT_PRCTL INTERCEPT_FUNCTION(prctl)
+#define INIT_PRCTL INTERCEPT_FUNCTION(prctl)
 #else
-# define INIT_PRCTL
-#endif  // SANITIZER_INTERCEPT_PRCTL
+#define INIT_PRCTL
+#endif // SANITIZER_INTERCEPT_PRCTL
 
-
 #if SANITIZER_INTERCEPT_SCANF
 
 #include "sanitizer_common_interceptors_scanf.inc"
 
-INTERCEPTOR(int, vscanf, const char *format, va_list ap) {  // NOLINT
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, vscanf, format, ap);
-  scanf_common(ctx, format, ap);
-  int res = REAL(vscanf)(format, ap);  // NOLINT
-  return res;
-}
+#define VSCANF_INTERCEPTOR_IMPL(vname, allowGnuMalloc, ...)                    \
+  {                                                                            \
+    void *ctx;                                                                 \
+    COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__);                         \
+    va_list aq;                                                                \
+    va_copy(aq, ap);                                                           \
+    int res = REAL(vname)(__VA_ARGS__);                                        \
+    if (res > 0)                                                               \
+      scanf_common(ctx, res, allowGnuMalloc, format, aq);                      \
+    va_end(aq);                                                                \
+    return res;                                                                \
+  }
 
-INTERCEPTOR(int, vsscanf, const char *str, const char *format,  // NOLINT
-    va_list ap) {
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, vsscanf, str, format, ap);
-  scanf_common(ctx, format, ap);
-  int res = REAL(vsscanf)(str, format, ap);  // NOLINT
-  // FIXME: read of str
-  return res;
-}
+INTERCEPTOR(int, vscanf, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vscanf, true, format, ap)
 
-INTERCEPTOR(int, vfscanf, void *stream, const char *format,  // NOLINT
-    va_list ap) {
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, vfscanf, stream, format, ap);
-  scanf_common(ctx, format, ap);
-  int res = REAL(vfscanf)(stream, format, ap);  // NOLINT
-  return res;
-}
+INTERCEPTOR(int, vsscanf, const char *str, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vsscanf, true, str, format, ap)
 
-INTERCEPTOR(int, scanf, const char *format, ...) {  // NOLINT
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, scanf, format);
-  va_list ap;
-  va_start(ap, format);
-  int res = vscanf(format, ap);  // NOLINT
-  va_end(ap);
-  return res;
-}
+INTERCEPTOR(int, vfscanf, void *stream, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vfscanf, true, stream, format, ap)
 
-INTERCEPTOR(int, fscanf, void* stream, const char *format, ...) {  // NOLINT
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, fscanf, stream, format);
-  va_list ap;
-  va_start(ap, format);
-  int res = vfscanf(stream, format, ap);  // NOLINT
-  va_end(ap);
-  return res;
-}
+INTERCEPTOR(int, __isoc99_vscanf, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vscanf, false, format, ap)
 
-INTERCEPTOR(int, sscanf, const char *str, const char *format, ...) {  // NOLINT
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, sscanf, str, format);  // NOLINT
-  va_list ap;
-  va_start(ap, format);
-  int res = vsscanf(str, format, ap);  // NOLINT
-  va_end(ap);
-  return res;
-}
+INTERCEPTOR(int, __isoc99_vsscanf, const char *str, const char *format,
+            va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vsscanf, false, str, format, ap)
 
-#define INIT_SCANF \
-  INTERCEPT_FUNCTION(scanf);                    \
-  INTERCEPT_FUNCTION(sscanf);  /* NOLINT */     \
-  INTERCEPT_FUNCTION(fscanf);                   \
-  INTERCEPT_FUNCTION(vscanf);                   \
-  INTERCEPT_FUNCTION(vsscanf);                  \
-  INTERCEPT_FUNCTION(vfscanf)
+INTERCEPTOR(int, __isoc99_vfscanf, void *stream, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
 
+#define SCANF_INTERCEPTOR_IMPL(name, vname, ...)                               \
+  {                                                                            \
+    void *ctx;                                                                 \
+    COMMON_INTERCEPTOR_ENTER(ctx, name, __VA_ARGS__);                          \
+    va_list ap;                                                                \
+    va_start(ap, format);                                                      \
+    int res = vname(__VA_ARGS__, ap);                                          \
+    va_end(ap);                                                                \
+    return res;                                                                \
+  }
+
+INTERCEPTOR(int, scanf, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(scanf, vscanf, format)
+
+INTERCEPTOR(int, fscanf, void *stream, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
+
+INTERCEPTOR(int, sscanf, const char *str, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
+
+INTERCEPTOR(int, __isoc99_scanf, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
+
+INTERCEPTOR(int, __isoc99_fscanf, void *stream, const char *format, ...)
+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)
+
+#define INIT_SCANF                                                             \
+  INTERCEPT_FUNCTION(scanf);                                                   \
+  INTERCEPT_FUNCTION(sscanf);                                                  \
+  INTERCEPT_FUNCTION(fscanf);                                                  \
+  INTERCEPT_FUNCTION(vscanf);                                                  \
+  INTERCEPT_FUNCTION(vsscanf);                                                 \
+  INTERCEPT_FUNCTION(vfscanf);                                                 \
+  INTERCEPT_FUNCTION(__isoc99_scanf);                                          \
+  INTERCEPT_FUNCTION(__isoc99_sscanf);                                         \
+  INTERCEPT_FUNCTION(__isoc99_fscanf);                                         \
+  INTERCEPT_FUNCTION(__isoc99_vscanf);                                         \
+  INTERCEPT_FUNCTION(__isoc99_vsscanf);                                        \
+  INTERCEPT_FUNCTION(__isoc99_vfscanf);
+
 #else
 #define INIT_SCANF
 #endif
 
-#define SANITIZER_COMMON_INTERCEPTORS_INIT \
-  INIT_READ;                               \
-  INIT_PREAD;                              \
-  INIT_PREAD64;                            \
-  INIT_PRCTL;                              \
-  INIT_WRITE;                              \
+#define SANITIZER_COMMON_INTERCEPTORS_INIT                                     \
+  INIT_READ;                                                                   \
+  INIT_PREAD;                                                                  \
+  INIT_PREAD64;                                                                \
+  INIT_PRCTL;                                                                  \
+  INIT_WRITE;                                                                  \
+  INIT_PWRITE;                                                                 \
+  INIT_PWRITE64;                                                               \
   INIT_SCANF;
Index: libsanitizer/sanitizer_common/sanitizer_allocator.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_allocator.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_allocator.h	(working copy)
@@ -23,9 +23,9 @@
 
 // SizeClassMap maps allocation sizes into size classes and back.
 // Class 0 corresponds to size 0.
-// Classes 1 - 16 correspond to sizes 8 - 128 (size = class_id * 8).
-// Next 8 classes: 128 + i * 16 (i = 1 to 8).
+// Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
 // Next 8 classes: 256 + i * 32 (i = 1 to 8).
+// Next 8 classes: 512 + i * 64 (i = 1 to 8).
 // ...
 // Next 8 classes: 2^k + i * 2^(k-3) (i = 1 to 8).
 // Last class corresponds to kMaxSize = 1 << kMaxSizeLog.
@@ -40,33 +40,48 @@
 //  - (1 << kMaxBytesCachedLog) is the maximal number of bytes per size class.
 //
 // Part of output of SizeClassMap::Print():
-//    c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
-//    c01 => s: 8 diff: +8 00% l 3 cached: 256 2048; id 1
-//    c02 => s: 16 diff: +8 100% l 4 cached: 256 4096; id 2
-//    ...
-//    c07 => s: 56 diff: +8 16% l 5 cached: 256 14336; id 7
+// c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
+// c01 => s: 16 diff: +16 00% l 4 cached: 256 4096; id 1
+// c02 => s: 32 diff: +16 100% l 5 cached: 256 8192; id 2
+// c03 => s: 48 diff: +16 50% l 5 cached: 256 12288; id 3
+// c04 => s: 64 diff: +16 33% l 6 cached: 256 16384; id 4
+// c05 => s: 80 diff: +16 25% l 6 cached: 256 20480; id 5
+// c06 => s: 96 diff: +16 20% l 6 cached: 256 24576; id 6
+// c07 => s: 112 diff: +16 16% l 6 cached: 256 28672; id 7
 //
-//    c08 => s: 64 diff: +8 14% l 6 cached: 256 16384; id 8
-//    ...
-//    c15 => s: 120 diff: +8 07% l 6 cached: 256 30720; id 15
+// c08 => s: 128 diff: +16 14% l 7 cached: 256 32768; id 8
+// c09 => s: 144 diff: +16 12% l 7 cached: 256 36864; id 9
+// c10 => s: 160 diff: +16 11% l 7 cached: 256 40960; id 10
+// c11 => s: 176 diff: +16 10% l 7 cached: 256 45056; id 11
+// c12 => s: 192 diff: +16 09% l 7 cached: 256 49152; id 12
+// c13 => s: 208 diff: +16 08% l 7 cached: 256 53248; id 13
+// c14 => s: 224 diff: +16 07% l 7 cached: 256 57344; id 14
+// c15 => s: 240 diff: +16 07% l 7 cached: 256 61440; id 15
 //
-//    c16 => s: 128 diff: +8 06% l 7 cached: 256 32768; id 16
-//    c17 => s: 144 diff: +16 12% l 7 cached: 227 32688; id 17
-//    ...
-//    c23 => s: 240 diff: +16 07% l 7 cached: 136 32640; id 23
+// c16 => s: 256 diff: +16 06% l 8 cached: 256 65536; id 16
+// c17 => s: 288 diff: +32 12% l 8 cached: 227 65376; id 17
+// c18 => s: 320 diff: +32 11% l 8 cached: 204 65280; id 18
+// c19 => s: 352 diff: +32 10% l 8 cached: 186 65472; id 19
+// c20 => s: 384 diff: +32 09% l 8 cached: 170 65280; id 20
+// c21 => s: 416 diff: +32 08% l 8 cached: 157 65312; id 21
+// c22 => s: 448 diff: +32 07% l 8 cached: 146 65408; id 22
+// c23 => s: 480 diff: +32 07% l 8 cached: 136 65280; id 23
 //
-//    c24 => s: 256 diff: +16 06% l 8 cached: 128 32768; id 24
-//    c25 => s: 288 diff: +32 12% l 8 cached: 113 32544; id 25
-//    ...
-//    c31 => s: 480 diff: +32 07% l 8 cached: 68 32640; id 31
+// c24 => s: 512 diff: +32 06% l 9 cached: 128 65536; id 24
+// c25 => s: 576 diff: +64 12% l 9 cached: 113 65088; id 25
+// c26 => s: 640 diff: +64 11% l 9 cached: 102 65280; id 26
+// c27 => s: 704 diff: +64 10% l 9 cached: 93 65472; id 27
+// c28 => s: 768 diff: +64 09% l 9 cached: 85 65280; id 28
+// c29 => s: 832 diff: +64 08% l 9 cached: 78 64896; id 29
+// c30 => s: 896 diff: +64 07% l 9 cached: 73 65408; id 30
+// c31 => s: 960 diff: +64 07% l 9 cached: 68 65280; id 31
 //
-//    c32 => s: 512 diff: +32 06% l 9 cached: 64 32768; id 32
+// c32 => s: 1024 diff: +64 06% l 10 cached: 64 65536; id 32
 
-
 template <uptr kMaxSizeLog, uptr kMaxNumCachedT, uptr kMaxBytesCachedLog,
           uptr kMinBatchClassT>
 class SizeClassMap {
-  static const uptr kMinSizeLog = 3;
+  static const uptr kMinSizeLog = 4;
   static const uptr kMidSizeLog = kMinSizeLog + 4;
   static const uptr kMinSize = 1 << kMinSizeLog;
   static const uptr kMidSize = 1 << kMidSizeLog;
@@ -104,7 +119,7 @@
     if (size <= kMidSize)
       return (size + kMinSize - 1) >> kMinSizeLog;
     if (size > kMaxSize) return 0;
-    uptr l = SANITIZER_WORDSIZE - 1 - __builtin_clzl(size);
+    uptr l = MostSignificantSetBitIndex(size);
     uptr hbits = (size >> (l - S)) & M;
     uptr lbits = size & ((1 << (l - S)) - 1);
     uptr l1 = l - kMidSizeLog;
@@ -114,7 +129,7 @@
   static uptr MaxCached(uptr class_id) {
     if (class_id == 0) return 0;
     uptr n = (1UL << kMaxBytesCachedLog) / Size(class_id);
-    return Max(1UL, Min(kMaxNumCached, n));
+    return Max<uptr>(1, Min(kMaxNumCached, n));
   }
 
   static void Print() {
@@ -126,7 +141,7 @@
         Printf("\n");
       uptr d = s - prev_s;
       uptr p = prev_s ? (d * 100 / prev_s) : 0;
-      uptr l = SANITIZER_WORDSIZE - 1 - __builtin_clzl(s);
+      uptr l = MostSignificantSetBitIndex(s);
       uptr cached = MaxCached(i) * s;
       Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd "
              "cached: %zd %zd; id %zd\n",
@@ -172,12 +187,92 @@
   }
 };
 
-typedef SizeClassMap<17, 256, 16, FIRST_32_SECOND_64(33, 36)>
+typedef SizeClassMap<17, 256, 16, FIRST_32_SECOND_64(25, 28)>
     DefaultSizeClassMap;
-typedef SizeClassMap<17, 64, 14, FIRST_32_SECOND_64(25, 28)>
+typedef SizeClassMap<17, 64, 14, FIRST_32_SECOND_64(17, 20)>
     CompactSizeClassMap;
 template<class SizeClassAllocator> struct SizeClassAllocatorLocalCache;
 
+// Memory allocator statistics
+enum AllocatorStat {
+  AllocatorStatMalloced,
+  AllocatorStatFreed,
+  AllocatorStatMmapped,
+  AllocatorStatUnmapped,
+  AllocatorStatCount
+};
+
+typedef u64 AllocatorStatCounters[AllocatorStatCount];
+
+// Per-thread stats, live in per-thread cache.
+class AllocatorStats {
+ public:
+  void Init() {
+    internal_memset(this, 0, sizeof(*this));
+  }
+
+  void Add(AllocatorStat i, u64 v) {
+    v += atomic_load(&stats_[i], memory_order_relaxed);
+    atomic_store(&stats_[i], v, memory_order_relaxed);
+  }
+
+  void Set(AllocatorStat i, u64 v) {
+    atomic_store(&stats_[i], v, memory_order_relaxed);
+  }
+
+  u64 Get(AllocatorStat i) const {
+    return atomic_load(&stats_[i], memory_order_relaxed);
+  }
+
+ private:
+  friend class AllocatorGlobalStats;
+  AllocatorStats *next_;
+  AllocatorStats *prev_;
+  atomic_uint64_t stats_[AllocatorStatCount];
+};
+
+// Global stats, used for aggregation and querying.
+class AllocatorGlobalStats : public AllocatorStats {
+ public:
+  void Init() {
+    internal_memset(this, 0, sizeof(*this));
+    next_ = this;
+    prev_ = this;
+  }
+
+  void Register(AllocatorStats *s) {
+    SpinMutexLock l(&mu_);
+    s->next_ = next_;
+    s->prev_ = this;
+    next_->prev_ = s;
+    next_ = s;
+  }
+
+  void Unregister(AllocatorStats *s) {
+    SpinMutexLock l(&mu_);
+    s->prev_->next_ = s->next_;
+    s->next_->prev_ = s->prev_;
+    for (int i = 0; i < AllocatorStatCount; i++)
+      Add(AllocatorStat(i), s->Get(AllocatorStat(i)));
+  }
+
+  void Get(AllocatorStatCounters s) const {
+    internal_memset(s, 0, AllocatorStatCount * sizeof(u64));
+    SpinMutexLock l(&mu_);
+    const AllocatorStats *stats = this;
+    for (;;) {
+      for (int i = 0; i < AllocatorStatCount; i++)
+        s[i] += stats->Get(AllocatorStat(i));
+      stats = stats->next_;
+      if (stats == this)
+        break;
+    }
+  }
+
+ private:
+  mutable SpinMutex mu_;
+};
+
 // Allocators call these callbacks on mmap/munmap.
 struct NoOpMapUnmapCallback {
   void OnMap(uptr p, uptr size) const { }
@@ -231,17 +326,18 @@
       alignment <= SizeClassMap::kMaxSize;
   }
 
-  Batch *NOINLINE AllocateBatch(AllocatorCache *c, uptr class_id) {
+  NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
+                                uptr class_id) {
     CHECK_LT(class_id, kNumClasses);
     RegionInfo *region = GetRegionInfo(class_id);
     Batch *b = region->free_list.Pop();
     if (b == 0)
-      b = PopulateFreeList(c, class_id, region);
+      b = PopulateFreeList(stat, c, class_id, region);
     region->n_allocated += b->count;
     return b;
   }
 
-  void NOINLINE DeallocateBatch(uptr class_id, Batch *b) {
+  NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
     RegionInfo *region = GetRegionInfo(class_id);
     region->free_list.Push(b);
     region->n_freed += b->count;
@@ -320,6 +416,20 @@
     }
   }
 
+  // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+  // introspection API.
+  void ForceLock() {
+    for (uptr i = 0; i < kNumClasses; i++) {
+      GetRegionInfo(i)->mutex.Lock();
+    }
+  }
+
+  void ForceUnlock() {
+    for (int i = (int)kNumClasses - 1; i >= 0; i--) {
+      GetRegionInfo(i)->mutex.Unlock();
+    }
+  }
+
   typedef SizeClassMap SizeClassMapT;
   static const uptr kNumClasses = SizeClassMap::kNumClasses;
   static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
@@ -334,7 +444,7 @@
   // or with one element if its size is greater.
   static const uptr kPopulateSize = 1 << 14;
   // Call mmap for user memory with at least this size.
-  static const uptr kUserMapSize = 1 << 15;
+  static const uptr kUserMapSize = 1 << 16;
   // Call mmap for metadata memory with at least this size.
   static const uptr kMetaMapSize = 1 << 16;
 
@@ -368,8 +478,8 @@
     return offset / (u32)size;
   }
 
-  Batch *NOINLINE PopulateFreeList(AllocatorCache *c, uptr class_id,
-                                   RegionInfo *region) {
+  NOINLINE Batch* PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+                                   uptr class_id, RegionInfo *region) {
     BlockingMutexLock l(&region->mutex);
     Batch *b = region->free_list.Pop();
     if (b)
@@ -386,6 +496,7 @@
         map_size += kUserMapSize;
       CHECK_GE(region->mapped_user + map_size, end_idx);
       MapWithCallback(region_beg + region->mapped_user, map_size);
+      stat->Add(AllocatorStatMmapped, map_size);
       region->mapped_user += map_size;
     }
     uptr total_count = (region->mapped_user - beg_idx - size)
@@ -467,6 +578,7 @@
     MapUnmapCallback().OnMap((uptr)res, size);
     return res;
   }
+
   void UnmapWithCallback(uptr beg, uptr size) {
     MapUnmapCallback().OnUnmap(beg, size);
     UnmapOrDie(reinterpret_cast<void *>(beg), size);
@@ -488,19 +600,20 @@
     return reinterpret_cast<void*>(meta);
   }
 
-  Batch *NOINLINE AllocateBatch(AllocatorCache *c, uptr class_id) {
+  NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
+                                uptr class_id) {
     CHECK_LT(class_id, kNumClasses);
     SizeClassInfo *sci = GetSizeClassInfo(class_id);
     SpinMutexLock l(&sci->mutex);
     if (sci->free_list.empty())
-      PopulateFreeList(c, sci, class_id);
+      PopulateFreeList(stat, c, sci, class_id);
     CHECK(!sci->free_list.empty());
     Batch *b = sci->free_list.front();
     sci->free_list.pop_front();
     return b;
   }
 
-  void NOINLINE DeallocateBatch(uptr class_id, Batch *b) {
+  NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
     CHECK_LT(class_id, kNumClasses);
     SizeClassInfo *sci = GetSizeClassInfo(class_id);
     SpinMutexLock l(&sci->mutex);
@@ -549,6 +662,20 @@
     UnmapWithCallback(reinterpret_cast<uptr>(state_), sizeof(State));
   }
 
+  // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+  // introspection API.
+  void ForceLock() {
+    for (uptr i = 0; i < kNumClasses; i++) {
+      GetSizeClassInfo(i)->mutex.Lock();
+    }
+  }
+
+  void ForceUnlock() {
+    for (int i = kNumClasses - 1; i >= 0; i--) {
+      GetSizeClassInfo(i)->mutex.Unlock();
+    }
+  }
+
   void PrintStats() {
   }
 
@@ -577,11 +704,12 @@
     return mem & ~(kRegionSize - 1);
   }
 
-  uptr AllocateRegion(uptr class_id) {
+  uptr AllocateRegion(AllocatorStats *stat, uptr class_id) {
     CHECK_LT(class_id, kNumClasses);
     uptr res = reinterpret_cast<uptr>(MmapAlignedOrDie(kRegionSize, kRegionSize,
                                       "SizeClassAllocator32"));
     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;
@@ -593,9 +721,10 @@
     return &state_->size_class_info_array[class_id];
   }
 
-  void PopulateFreeList(AllocatorCache *c, SizeClassInfo *sci, uptr class_id) {
+  void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+                        SizeClassInfo *sci, uptr class_id) {
     uptr size = SizeClassMap::Size(class_id);
-    uptr reg = AllocateRegion(class_id);
+    uptr reg = AllocateRegion(stat, class_id);
     uptr n_chunks = kRegionSize / (size + kMetadataSize);
     uptr max_count = SizeClassMap::MaxCached(class_id);
     Batch *b = 0;
@@ -632,14 +761,22 @@
   typedef SizeClassAllocator Allocator;
   static const uptr kNumClasses = SizeClassAllocator::kNumClasses;
 
-  // Don't need to call Init if the object is a global (i.e. zero-initialized).
-  void Init() {
-    internal_memset(this, 0, sizeof(*this));
+  void Init(AllocatorGlobalStats *s) {
+    stats_.Init();
+    if (s)
+      s->Register(&stats_);
   }
 
+  void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) {
+    Drain(allocator);
+    if (s)
+      s->Unregister(&stats_);
+  }
+
   void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
     CHECK_NE(class_id, 0UL);
     CHECK_LT(class_id, kNumClasses);
+    stats_.Add(AllocatorStatMalloced, SizeClassMap::Size(class_id));
     PerClass *c = &per_class_[class_id];
     if (UNLIKELY(c->count == 0))
       Refill(allocator, class_id);
@@ -651,6 +788,7 @@
   void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) {
     CHECK_NE(class_id, 0UL);
     CHECK_LT(class_id, kNumClasses);
+    stats_.Add(AllocatorStatFreed, SizeClassMap::Size(class_id));
     PerClass *c = &per_class_[class_id];
     if (UNLIKELY(c->count == c->max_count))
       Drain(allocator, class_id);
@@ -674,6 +812,7 @@
     void *batch[2 * SizeClassMap::kMaxNumCached];
   };
   PerClass per_class_[kNumClasses];
+  AllocatorStats stats_;
 
   void InitCache() {
     if (per_class_[0].max_count)
@@ -684,10 +823,11 @@
     }
   }
 
-  void NOINLINE Refill(SizeClassAllocator *allocator, uptr class_id) {
+  NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) {
     InitCache();
     PerClass *c = &per_class_[class_id];
-    Batch *b = allocator->AllocateBatch(this, class_id);
+    Batch *b = allocator->AllocateBatch(&stats_, this, class_id);
+    CHECK_GT(b->count, 0);
     for (uptr i = 0; i < b->count; i++)
       c->batch[i] = b->batch[i];
     c->count = b->count;
@@ -695,7 +835,7 @@
       Deallocate(allocator, SizeClassMap::ClassID(sizeof(Batch)), b);
   }
 
-  void NOINLINE Drain(SizeClassAllocator *allocator, uptr class_id) {
+  NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) {
     InitCache();
     PerClass *c = &per_class_[class_id];
     Batch *b;
@@ -710,7 +850,7 @@
     }
     b->count = cnt;
     c->count -= cnt;
-    allocator->DeallocateBatch(class_id, b);
+    allocator->DeallocateBatch(&stats_, class_id, b);
   }
 };
 
@@ -725,7 +865,7 @@
     page_size_ = GetPageSizeCached();
   }
 
-  void *Allocate(uptr size, uptr alignment) {
+  void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) {
     CHECK(IsPowerOfTwo(alignment));
     uptr map_size = RoundUpMapSize(size);
     if (alignment > page_size_)
@@ -744,7 +884,7 @@
     h->size = size;
     h->map_beg = map_beg;
     h->map_size = map_size;
-    uptr size_log = SANITIZER_WORDSIZE - __builtin_clzl(map_size) - 1;
+    uptr size_log = MostSignificantSetBitIndex(map_size);
     CHECK_LT(size_log, ARRAY_SIZE(stats.by_size_log));
     {
       SpinMutexLock l(&mutex_);
@@ -756,11 +896,13 @@
       stats.currently_allocated += map_size;
       stats.max_allocated = Max(stats.max_allocated, stats.currently_allocated);
       stats.by_size_log[size_log]++;
+      stat->Add(AllocatorStatMalloced, map_size);
+      stat->Add(AllocatorStatMmapped, map_size);
     }
     return reinterpret_cast<void*>(res);
   }
 
-  void Deallocate(void *p) {
+  void Deallocate(AllocatorStats *stat, void *p) {
     Header *h = GetHeader(p);
     {
       SpinMutexLock l(&mutex_);
@@ -772,6 +914,8 @@
       n_chunks_--;
       stats.n_frees++;
       stats.currently_allocated -= h->map_size;
+      stat->Add(AllocatorStatFreed, h->map_size);
+      stat->Add(AllocatorStatUnmapped, h->map_size);
     }
     MapUnmapCallback().OnUnmap(h->map_beg, h->map_size);
     UnmapOrDie(reinterpret_cast<void*>(h->map_beg), h->map_size);
@@ -838,6 +982,16 @@
     Printf("\n");
   }
 
+  // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+  // introspection API.
+  void ForceLock() {
+    mutex_.Lock();
+  }
+
+  void ForceUnlock() {
+    mutex_.Unlock();
+  }
+
  private:
   static const int kMaxNumChunks = 1 << FIRST_32_SECOND_64(15, 18);
   struct Header {
@@ -884,6 +1038,7 @@
   void Init() {
     primary_.Init();
     secondary_.Init();
+    stats_.Init();
   }
 
   void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
@@ -899,7 +1054,7 @@
     if (primary_.CanAllocate(size, alignment))
       res = cache->Allocate(&primary_, primary_.ClassID(size));
     else
-      res = secondary_.Allocate(size, alignment);
+      res = secondary_.Allocate(&stats_, size, alignment);
     if (alignment > 8)
       CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
     if (cleared && res)
@@ -912,7 +1067,7 @@
     if (primary_.PointerIsMine(p))
       cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
     else
-      secondary_.Deallocate(p);
+      secondary_.Deallocate(&stats_, p);
   }
 
   void *Reallocate(AllocatorCache *cache, void *p, uptr new_size,
@@ -967,20 +1122,48 @@
 
   void TestOnlyUnmap() { primary_.TestOnlyUnmap(); }
 
+  void InitCache(AllocatorCache *cache) {
+    cache->Init(&stats_);
+  }
+
+  void DestroyCache(AllocatorCache *cache) {
+    cache->Destroy(&primary_, &stats_);
+  }
+
   void SwallowCache(AllocatorCache *cache) {
     cache->Drain(&primary_);
   }
 
+  void GetStats(AllocatorStatCounters s) const {
+    stats_.Get(s);
+  }
+
   void PrintStats() {
     primary_.PrintStats();
     secondary_.PrintStats();
   }
 
+  // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+  // introspection API.
+  void ForceLock() {
+    primary_.ForceLock();
+    secondary_.ForceLock();
+  }
+
+  void ForceUnlock() {
+    secondary_.ForceUnlock();
+    primary_.ForceUnlock();
+  }
+
  private:
   PrimaryAllocator primary_;
   SecondaryAllocator secondary_;
+  AllocatorGlobalStats stats_;
 };
 
+// Returns true if calloc(size, n) should return 0 due to overflow in size*n.
+bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n);
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_ALLOCATOR_H
Index: libsanitizer/asan/asan_intercepted_functions.h
===================================================================
--- libsanitizer/asan/asan_intercepted_functions.h	(revision 195997)
+++ libsanitizer/asan/asan_intercepted_functions.h	(working copy)
@@ -17,6 +17,7 @@
 #include "sanitizer_common/sanitizer_platform_interceptors.h"
 
 #include <stdarg.h>
+#include <stddef.h>
 
 using __sanitizer::uptr;
 
@@ -64,9 +65,7 @@
 # define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
 #endif
 
-// On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it
-// there.
-#if !defined(_WIN32) && (!defined(__APPLE__) || MAC_INTERPOSE_FUNCTIONS)
+#if !defined(_WIN32)
 # define ASAN_INTERCEPT_SIGLONGJMP 1
 #else
 # define ASAN_INTERCEPT_SIGLONGJMP 0
@@ -169,7 +168,8 @@
 DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, write, int fd, void *ptr, SIZE_T count);
 # endif
 # if SANITIZER_INTERCEPT_PWRITE
-DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count);
+DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pwrite,
+                             int fd, void *ptr, SIZE_T count, OFF_T offset);
 # endif
 
 # if ASAN_INTERCEPT_MLOCKX
@@ -193,6 +193,8 @@
                              void *(*start_routine)(void*), void *arg);
 # endif
 
+// stdio.h
+# if SANITIZER_INTERCEPT_SCANF
 DECLARE_FUNCTION_AND_WRAPPER(int, vscanf, const char *format, va_list ap);
 DECLARE_FUNCTION_AND_WRAPPER(int, vsscanf, const char *str, const char *format,
                              va_list ap);
@@ -203,6 +205,18 @@
                              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__)
 typedef void* pthread_workqueue_t;
@@ -231,7 +245,7 @@
                              dispatch_group_t group, dispatch_queue_t dq,
                              void *ctxt, dispatch_function_t func);
 
-#  if MAC_INTERPOSE_FUNCTIONS && !defined(MISSING_BLOCKS_SUPPORT)
+#  if !defined(MISSING_BLOCKS_SUPPORT)
 DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_group_async,
                              dispatch_group_t dg,
                              dispatch_queue_t dq, void (^work)(void));
@@ -243,7 +257,7 @@
                              dispatch_source_t ds, void (^work)(void));
 DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_source_set_cancel_handler,
                              dispatch_source_t ds, void (^work)(void));
-#  endif  // MAC_INTERPOSE_FUNCTIONS
+#  endif  // MISSING_BLOCKS_SUPPORT
 
 typedef void malloc_zone_t;
 typedef size_t vm_size_t;
Index: libsanitizer/asan/asan_rtl.cc
===================================================================
--- libsanitizer/asan/asan_rtl.cc	(revision 195997)
+++ libsanitizer/asan/asan_rtl.cc	(working copy)
@@ -18,7 +18,6 @@
 #include "asan_stats.h"
 #include "asan_thread.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_libc.h"
@@ -83,7 +82,6 @@
 
   ParseFlag(str, &f->replace_str, "replace_str");
   ParseFlag(str, &f->replace_intrin, "replace_intrin");
-  ParseFlag(str, &f->replace_cfallocator, "replace_cfallocator");
   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");
@@ -95,6 +93,8 @@
   ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size");
   ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit");
   ParseFlag(str, &f->abort_on_error, "abort_on_error");
+  ParseFlag(str, &f->print_stats, "print_stats");
+  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");
@@ -121,7 +121,6 @@
   f->malloc_context_size = kDeafultMallocContextSize;
   f->replace_str = true;
   f->replace_intrin = true;
-  f->replace_cfallocator = true;
   f->mac_ignore_invalid_free = false;
   f->use_fake_stack = true;
   f->max_malloc_fill_size = 0;
@@ -133,6 +132,8 @@
   f->check_malloc_usable_size = true;
   f->unmap_shadow_on_exit = false;
   f->abort_on_error = false;
+  f->print_stats = false;
+  f->print_legend = true;
   f->atexit = false;
   f->disable_core = (SANITIZER_WORDSIZE == 64);
   f->strip_path_prefix = "";
@@ -142,9 +143,7 @@
   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->alloc_dealloc_mismatch = true;
   f->use_stack_depot = true;  // Only affects allocator2.
 
   // Override from user-specified string.
@@ -162,6 +161,7 @@
 int asan_inited;
 bool asan_init_is_running;
 void (*death_callback)(void);
+uptr kHighMemEnd;
 
 // -------------------------- Misc ---------------- {{{1
 void ShowStatsAndAbort() {
@@ -261,6 +261,24 @@
   __asan_print_accumulated_stats();
 }
 
+static void InitializeHighMemEnd() {
+#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
+}
+
 }  // namespace __asan
 
 // ---------------------- Interface ---------------- {{{1
@@ -295,8 +313,10 @@
 
 void __asan_init() {
   if (asan_inited) return;
+  SanitizerToolName = "AddressSanitizer";
   CHECK(!asan_init_is_running && "ASan init calls itself!");
   asan_init_is_running = true;
+  InitializeHighMemEnd();
 
   // Make sure we are not statically linked.
   AsanDoesNotSupportStaticLinkage();
@@ -400,6 +420,8 @@
   asanThreadRegistry().GetMain()->ThreadStart();
   force_interface_symbols();  // no-op.
 
+  InitializeAllocator();
+
   if (flags()->verbosity) {
     Report("AddressSanitizer Init done\n");
   }
Index: libsanitizer/asan/asan_poisoning.cc
===================================================================
--- libsanitizer/asan/asan_poisoning.cc	(revision 195997)
+++ libsanitizer/asan/asan_poisoning.cc	(working copy)
@@ -13,7 +13,6 @@
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_mapping.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
 namespace __asan {
Index: libsanitizer/asan/asan_new_delete.cc
===================================================================
--- libsanitizer/asan/asan_new_delete.cc	(revision 195997)
+++ libsanitizer/asan/asan_new_delete.cc	(working copy)
@@ -25,9 +25,9 @@
 
 using namespace __asan;  // NOLINT
 
-// On Mac and Android new() goes through malloc interceptors.
+// On Android new() goes through malloc interceptors.
 // See also https://code.google.com/p/address-sanitizer/issues/detail?id=131.
-#if !ASAN_ANDROID && !ASAN_MAC
+#if !ASAN_ANDROID
 
 // Fake std::nothrow_t to avoid including <new>.
 namespace std {
Index: libsanitizer/asan/asan_report.h
===================================================================
--- libsanitizer/asan/asan_report.h	(revision 195997)
+++ libsanitizer/asan/asan_report.h	(working copy)
@@ -13,15 +13,15 @@
 #include "asan_allocator.h"
 #include "asan_internal.h"
 #include "asan_thread.h"
-#include "sanitizer/asan_interface.h"
 
 namespace __asan {
 
 // The following functions prints address description depending
 // on the memory type (shadow/heap/stack/global).
 void DescribeHeapAddress(uptr addr, uptr access_size);
-bool DescribeAddressIfGlobal(uptr addr);
-bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g);
+bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
+bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
+                                     const __asan_global &g);
 bool DescribeAddressIfShadow(uptr addr);
 bool DescribeAddressIfStack(uptr addr, uptr access_size);
 // Determines memory type on its own.
Index: libsanitizer/asan/asan_internal.h
===================================================================
--- libsanitizer/asan/asan_internal.h	(revision 195997)
+++ libsanitizer/asan/asan_internal.h	(working copy)
@@ -13,6 +13,7 @@
 #define ASAN_INTERNAL_H
 
 #include "asan_flags.h"
+#include "asan_interface_internal.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
Index: libsanitizer/asan/asan_globals.cc
===================================================================
--- libsanitizer/asan/asan_globals.cc	(revision 195997)
+++ libsanitizer/asan/asan_globals.cc	(working copy)
@@ -16,7 +16,6 @@
 #include "asan_stack.h"
 #include "asan_stats.h"
 #include "asan_thread.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_mutex.h"
 
 namespace __asan {
@@ -34,26 +33,20 @@
 static ListOfGlobals *list_of_dynamic_init_globals;
 
 void PoisonRedZones(const Global &g)  {
-  uptr shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE;
-  CHECK(shadow_rz_size == 1 || shadow_rz_size == 2 || shadow_rz_size == 4);
-  // full right redzone
-  uptr g_aligned_size = kGlobalAndStackRedzone *
-      ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone);
-  PoisonShadow(g.beg + g_aligned_size,
-               kGlobalAndStackRedzone, kAsanGlobalRedzoneMagic);
-  if ((g.size % kGlobalAndStackRedzone) != 0) {
+  uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
+  PoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
+               kAsanGlobalRedzoneMagic);
+  if (g.size != aligned_size) {
     // partial right redzone
-    u64 g_aligned_down_size = kGlobalAndStackRedzone *
-        (g.size / kGlobalAndStackRedzone);
-    CHECK(g_aligned_down_size == g_aligned_size - kGlobalAndStackRedzone);
-    PoisonShadowPartialRightRedzone(g.beg + g_aligned_down_size,
-                                    g.size % kGlobalAndStackRedzone,
-                                    kGlobalAndStackRedzone,
-                                    kAsanGlobalRedzoneMagic);
+    PoisonShadowPartialRightRedzone(
+        g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
+        g.size % SHADOW_GRANULARITY,
+        SHADOW_GRANULARITY,
+        kAsanGlobalRedzoneMagic);
   }
 }
 
-bool DescribeAddressIfGlobal(uptr addr) {
+bool DescribeAddressIfGlobal(uptr addr, uptr size) {
   if (!flags()->report_globals) return false;
   BlockingMutexLock lock(&mu_for_globals);
   bool res = false;
@@ -62,7 +55,7 @@
     if (flags()->report_globals >= 2)
       Report("Search Global: beg=%p size=%zu name=%s\n",
              (void*)g.beg, g.size, (char*)g.name);
-    res |= DescribeAddressRelativeToGlobal(addr, g);
+    res |= DescribeAddressRelativeToGlobal(addr, size, g);
   }
   return res;
 }
Index: libsanitizer/asan/asan_interceptors.h
===================================================================
--- libsanitizer/asan/asan_interceptors.h	(revision 195997)
+++ libsanitizer/asan/asan_interceptors.h	(working copy)
@@ -30,9 +30,6 @@
 namespace __asan {
 
 void InitializeAsanInterceptors();
-#if defined(__APPLE__)
-void InitializeMacInterceptors();
-#endif  // __APPLE__
 
 }  // namespace __asan
 
Index: libsanitizer/asan/asan_malloc_linux.cc
===================================================================
--- libsanitizer/asan/asan_malloc_linux.cc	(revision 195997)
+++ libsanitizer/asan/asan_malloc_linux.cc	(working copy)
@@ -18,7 +18,6 @@
 #include "asan_internal.h"
 #include "asan_stack.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
 
 #if ASAN_ANDROID
 DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
Index: libsanitizer/asan/asan_mapping.h
===================================================================
--- libsanitizer/asan/asan_mapping.h	(revision 195997)
+++ libsanitizer/asan/asan_mapping.h	(working copy)
@@ -34,27 +34,16 @@
 #   if defined(__powerpc64__)
 #    define SHADOW_OFFSET (1ULL << 41)
 #   else
-#    define SHADOW_OFFSET (1ULL << 44)
+#    define SHADOW_OFFSET 0x7fff8000ULL
 #   endif
 #  endif
 # endif
 #endif  // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
 
 #define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
-#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) | (SHADOW_OFFSET))
+#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
 #define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
 
-#if SANITIZER_WORDSIZE == 64
-# if defined(__powerpc64__)
-  static const uptr kHighMemEnd = 0x00000fffffffffffUL;
-# else
-  static const uptr kHighMemEnd = 0x00007fffffffffffUL;
-# endif
-#else  // SANITIZER_WORDSIZE == 32
-  static const uptr kHighMemEnd = 0xffffffff;
-#endif  // SANITIZER_WORDSIZE
-
-
 #define kLowMemBeg      0
 #define kLowMemEnd      (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
 
@@ -74,11 +63,11 @@
                                        : kZeroBaseShadowStart)
 #define kShadowGapEnd   (kHighShadowBeg - 1)
 
-#define kGlobalAndStackRedzone \
-      (SHADOW_GRANULARITY < 32 ? 32 : SHADOW_GRANULARITY)
-
 namespace __asan {
 
+SANITIZER_INTERFACE_ATTRIBUTE
+extern uptr kHighMemEnd;  // Initialized in __asan_init.
+
 static inline bool AddrIsInLowMem(uptr a) {
   return a < kLowMemEnd;
 }
Index: libsanitizer/asan/asan_mac.cc
===================================================================
--- libsanitizer/asan/asan_mac.cc	(revision 195997)
+++ libsanitizer/asan/asan_mac.cc	(working copy)
@@ -89,10 +89,9 @@
 
 void MaybeReexec() {
   if (!flags()->allow_reexec) return;
-#if MAC_INTERPOSE_FUNCTIONS
-  // If the program is linked with the dynamic ASan runtime library, make sure
-  // the library is preloaded so that the wrappers work. If it is not, set
-  // DYLD_INSERT_LIBRARIES and re-exec ourselves.
+  // Make sure the dynamic ASan runtime library is preloaded so that the
+  // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec
+  // ourselves.
   Dl_info info;
   CHECK(dladdr((void*)((uptr)__asan_init), &info));
   const char *dyld_insert_libraries = GetEnv(kDyldInsertLibraries);
@@ -114,8 +113,6 @@
     }
     execv(program_name, *_NSGetArgv());
   }
-#endif  // MAC_INTERPOSE_FUNCTIONS
-  // If we're not using the dynamic runtime, do nothing.
 }
 
 // No-op. Mac does not support static linkage anyway.
@@ -146,57 +143,6 @@
   UNIMPLEMENTED();
 }
 
-// The range of pages to be used for escape islands.
-// TODO(glider): instead of mapping a fixed range we must find a range of
-// unmapped pages in vmmap and take them.
-// These constants were chosen empirically and may not work if the shadow
-// memory layout changes. Unfortunately they do necessarily depend on
-// kHighMemBeg or kHighMemEnd.
-static void *island_allocator_pos = 0;
-
-#if SANITIZER_WORDSIZE == 32
-# define kIslandEnd (0xffdf0000 - GetPageSizeCached())
-# define kIslandBeg (kIslandEnd - 256 * GetPageSizeCached())
-#else
-# define kIslandEnd (0x7fffffdf0000 - GetPageSizeCached())
-# define kIslandBeg (kIslandEnd - 256 * GetPageSizeCached())
-#endif
-
-extern "C"
-mach_error_t __interception_allocate_island(void **ptr,
-                                            uptr unused_size,
-                                            void *unused_hint) {
-  if (!island_allocator_pos) {
-    island_allocator_pos =
-        internal_mmap((void*)kIslandBeg, kIslandEnd - kIslandBeg,
-                      PROT_READ | PROT_WRITE | PROT_EXEC,
-                      MAP_PRIVATE | MAP_ANON | MAP_FIXED,
-                      -1, 0);
-    if (island_allocator_pos != (void*)kIslandBeg) {
-      return KERN_NO_SPACE;
-    }
-    if (flags()->verbosity) {
-      Report("Mapped pages %p--%p for branch islands.\n",
-             (void*)kIslandBeg, (void*)kIslandEnd);
-    }
-    // Should not be very performance-critical.
-    internal_memset(island_allocator_pos, 0xCC, kIslandEnd - kIslandBeg);
-  };
-  *ptr = island_allocator_pos;
-  island_allocator_pos = (char*)island_allocator_pos + GetPageSizeCached();
-  if (flags()->verbosity) {
-    Report("Branch island allocated at %p\n", *ptr);
-  }
-  return err_none;
-}
-
-extern "C"
-mach_error_t __interception_deallocate_island(void *ptr) {
-  // Do nothing.
-  // TODO(glider): allow to free and reuse the island memory.
-  return err_none;
-}
-
 // Support for the following functions from libdispatch on Mac OS:
 //   dispatch_async_f()
 //   dispatch_async()
@@ -350,14 +296,7 @@
                                asan_dispatch_call_block_and_release);
 }
 
-#if MAC_INTERPOSE_FUNCTIONS && !defined(MISSING_BLOCKS_SUPPORT)
-// dispatch_async, dispatch_group_async and others tailcall the corresponding
-// dispatch_*_f functions. When wrapping functions with mach_override, those
-// dispatch_*_f are intercepted automatically. But with dylib interposition
-// this does not work, because the calls within the same library are not
-// interposed.
-// Therefore we need to re-implement dispatch_async and friends.
-
+#if !defined(MISSING_BLOCKS_SUPPORT)
 extern "C" {
 // FIXME: consolidate these declarations with asan_intercepted_functions.h.
 void dispatch_async(dispatch_queue_t dq, void(^work)(void));
@@ -410,16 +349,4 @@
 }
 #endif
 
-namespace __asan {
-
-void InitializeMacInterceptors() {
-  CHECK(INTERCEPT_FUNCTION(dispatch_async_f));
-  CHECK(INTERCEPT_FUNCTION(dispatch_sync_f));
-  CHECK(INTERCEPT_FUNCTION(dispatch_after_f));
-  CHECK(INTERCEPT_FUNCTION(dispatch_barrier_async_f));
-  CHECK(INTERCEPT_FUNCTION(dispatch_group_async_f));
-}
-
-}  // namespace __asan
-
 #endif  // __APPLE__
Index: libsanitizer/asan/asan_allocator2.cc
===================================================================
--- libsanitizer/asan/asan_allocator2.cc	(revision 195997)
+++ libsanitizer/asan/asan_allocator2.cc	(working copy)
@@ -20,7 +20,6 @@
 #include "asan_report.h"
 #include "asan_thread.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_allocator.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_list.h"
@@ -55,7 +54,11 @@
 };
 
 #if SANITIZER_WORDSIZE == 64
+#if defined(__powerpc64__)
+const uptr kAllocatorSpace =  0xa0000000000ULL;
+#else
 const uptr kAllocatorSpace = 0x600000000000ULL;
+#endif
 const uptr kAllocatorSize  =  0x10000000000ULL;  // 1T.
 typedef DefaultSizeClassMap SizeClassMap;
 typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
@@ -89,8 +92,6 @@
 static const uptr kMaxThreadLocalQuarantine =
   FIRST_32_SECOND_64(1 << 18, 1 << 20);
 
-static const uptr kReturnOnZeroMalloc = 2048;  // Zero page is protected.
-
 // 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.
@@ -112,7 +113,7 @@
   CHECK_GE(rz_size, 16);
   CHECK_LE(rz_size, 2048);
   CHECK(IsPowerOfTwo(rz_size));
-  u32 res = __builtin_ctz(rz_size) - 4;
+  u32 res = Log2(rz_size) - 4;
   CHECK_EQ(rz_size, RZLog2Size(res));
   return res;
 }
@@ -289,27 +290,26 @@
   AllocatorCache *cache_;
 };
 
-static void Init() {
-  static int inited = 0;
-  if (inited) return;
-  __asan_init();
-  inited = true;  // this must happen before any threads are created.
+void InitializeAllocator() {
   allocator.Init();
   quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
 }
 
 static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
                       AllocType alloc_type) {
-  Init();
+  if (!asan_inited)
+    __asan_init();
   CHECK(stack);
   const uptr min_alignment = SHADOW_GRANULARITY;
   if (alignment < min_alignment)
     alignment = min_alignment;
   if (size == 0) {
-    if (alignment <= kReturnOnZeroMalloc)
-      return reinterpret_cast<void *>(kReturnOnZeroMalloc);
-    else
-      return 0;  // 0 bytes with large alignment requested. Just return 0.
+    // We'd be happy to avoid allocating memory for zero-size requests, but
+    // some programs/tests depend on this behavior and assume that malloc would
+    // not return NULL even for zero-size allocations. Moreover, it looks like
+    // operator new should never return NULL, and results of consecutive "new"
+    // calls must be different even if the allocated size is zero.
+    size = 1;
   }
   CHECK(IsPowerOfTwo(alignment));
   uptr rz_log = ComputeRZLog(size);
@@ -415,7 +415,8 @@
 
 static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
   uptr p = reinterpret_cast<uptr>(ptr);
-  if (p == 0 || p == kReturnOnZeroMalloc) return;
+  if (p == 0) return;
+  ASAN_FREE_HOOK(ptr);
   uptr chunk_beg = p - kChunkHeaderSize;
   AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
 
@@ -465,8 +466,6 @@
     quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac),
                    m, m->UsedSize());
   }
-
-  ASAN_FREE_HOOK(ptr);
 }
 
 static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
@@ -546,7 +545,7 @@
       return right_chunk;
   }
   // Same chunk_state: choose based on offset.
-  uptr l_offset = 0, r_offset = 0;
+  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)
@@ -557,7 +556,7 @@
 AsanChunkView FindHeapChunkByAddress(uptr addr) {
   AsanChunk *m1 = GetAsanChunkByAddr(addr);
   if (!m1) return AsanChunkView(m1);
-  uptr offset = 0;
+  sptr offset = 0;
   if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) {
     // The address is in the chunk's left redzone, so maybe it is actually
     // a right buffer overflow from the other chunk to the left.
@@ -601,6 +600,7 @@
 }
 
 void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
+  if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
   void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC);
   if (ptr)
     REAL(memset)(ptr, 0, nmemb * size);
@@ -649,16 +649,17 @@
 }
 
 uptr asan_mz_size(const void *ptr) {
-  UNIMPLEMENTED();
-  return 0;
+  return AllocationSize(reinterpret_cast<uptr>(ptr));
 }
 
 void asan_mz_force_lock() {
-  UNIMPLEMENTED();
+  allocator.ForceLock();
+  fallback_mutex.Lock();
 }
 
 void asan_mz_force_unlock() {
-  UNIMPLEMENTED();
+  fallback_mutex.Unlock();
+  allocator.ForceUnlock();
 }
 
 }  // namespace __asan
@@ -674,7 +675,7 @@
 
 bool __asan_get_ownership(const void *p) {
   uptr ptr = reinterpret_cast<uptr>(p);
-  return (ptr == kReturnOnZeroMalloc) || (AllocationSize(ptr) > 0);
+  return (AllocationSize(ptr) > 0);
 }
 
 uptr __asan_get_allocated_size(const void *p) {
@@ -682,7 +683,7 @@
   uptr ptr = reinterpret_cast<uptr>(p);
   uptr allocated_size = AllocationSize(ptr);
   // Die if p is not malloced or if it is already freed.
-  if (allocated_size == 0 && ptr != kReturnOnZeroMalloc) {
+  if (allocated_size == 0) {
     GET_STACK_TRACE_FATAL_HERE;
     ReportAsanGetAllocatedSizeNotOwned(ptr, &stack);
   }
Index: libsanitizer/asan/asan_stack.cc
===================================================================
--- libsanitizer/asan/asan_stack.cc	(revision 195997)
+++ libsanitizer/asan/asan_stack.cc	(working copy)
@@ -9,9 +9,9 @@
 //
 // Code for ASan stack trace.
 //===----------------------------------------------------------------------===//
+#include "asan_internal.h"
 #include "asan_flags.h"
 #include "asan_stack.h"
-#include "sanitizer/asan_interface.h"
 
 namespace __asan {
 
Index: libsanitizer/asan/asan_report.cc
===================================================================
--- libsanitizer/asan/asan_report.cc	(revision 195997)
+++ libsanitizer/asan/asan_report.cc	(working copy)
@@ -118,19 +118,7 @@
   Printf("\n");
 }
 
-static void PrintShadowMemoryForAddress(uptr addr) {
-  if (!AddrIsInMem(addr))
-    return;
-  uptr shadow_addr = MemToShadow(addr);
-  const uptr n_bytes_per_row = 16;
-  uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
-  Printf("Shadow bytes around the buggy address:\n");
-  for (int i = -5; i <= 5; i++) {
-    const char *prefix = (i == 0) ? "=>" : "  ";
-    PrintShadowBytes(prefix,
-                     (u8*)(aligned_shadow + i * n_bytes_per_row),
-                     (u8*)shadow_addr, n_bytes_per_row);
-  }
+static void PrintLegend() {
   Printf("Shadow byte legend (one shadow byte represents %d "
          "application bytes):\n", (int)SHADOW_GRANULARITY);
   PrintShadowByte("  Addressable:           ", 0);
@@ -153,6 +141,23 @@
   PrintShadowByte("  ASan internal:         ", kAsanInternalHeapMagic);
 }
 
+static void PrintShadowMemoryForAddress(uptr addr) {
+  if (!AddrIsInMem(addr))
+    return;
+  uptr shadow_addr = MemToShadow(addr);
+  const uptr n_bytes_per_row = 16;
+  uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
+  Printf("Shadow bytes around the buggy address:\n");
+  for (int i = -5; i <= 5; i++) {
+    const char *prefix = (i == 0) ? "=>" : "  ";
+    PrintShadowBytes(prefix,
+                     (u8*)(aligned_shadow + i * n_bytes_per_row),
+                     (u8*)shadow_addr, n_bytes_per_row);
+  }
+  if (flags()->print_legend)
+    PrintLegend();
+}
+
 static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
                                 const char *zone_name) {
   if (zone_ptr) {
@@ -183,18 +188,23 @@
   Printf("  '%s' is ascii string '%s'\n", g.name, (char*)g.beg);
 }
 
-bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g) {
-  if (addr < g.beg - kGlobalAndStackRedzone) return false;
+bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
+                                     const __asan_global &g) {
+  static const uptr kMinimalDistanceFromAnotherGlobal = 64;
+  if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
   if (addr >= g.beg + g.size_with_redzone) return false;
   Decorator d;
   Printf("%s", d.Location());
-  Printf("%p is located ", (void*)addr);
   if (addr < g.beg) {
-    Printf("%zd bytes to the left", g.beg - addr);
-  } else if (addr >= g.beg + g.size) {
-    Printf("%zd bytes to the right", addr - (g.beg + g.size));
+    Printf("%p is located %zd bytes to the left", (void*)addr, g.beg - addr);
+  } else if (addr + size > g.beg + g.size) {
+    if (addr < g.beg + g.size)
+      addr = g.beg + g.size;
+    Printf("%p is located %zd bytes to the right", (void*)addr,
+           addr - (g.beg + g.size));
   } else {
-    Printf("%zd bytes inside", addr - g.beg);  // Can it happen?
+    // Can it happen?
+    Printf("%p is located %zd bytes inside", (void*)addr, addr - g.beg);
   }
   Printf(" of global variable '%s' (0x%zx) of size %zu\n",
              g.name, g.beg, g.size);
@@ -280,18 +290,22 @@
 
 static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
                                       uptr access_size) {
-  uptr offset;
+  sptr offset;
   Decorator d;
   Printf("%s", d.Location());
-  Printf("%p is located ", (void*)addr);
-  if (chunk.AddrIsInside(addr, access_size, &offset)) {
-    Printf("%zu bytes inside of", offset);
-  } else if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
-    Printf("%zu bytes to the left of", offset);
+  if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
+    Printf("%p is located %zd bytes to the left of", (void*)addr, offset);
   } else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
-    Printf("%zu bytes to the right of", offset);
+    if (offset < 0) {
+      addr -= offset;
+      offset = 0;
+    }
+    Printf("%p is located %zd bytes to the right of", (void*)addr, offset);
+  } else if (chunk.AddrIsInside(addr, access_size, &offset)) {
+    Printf("%p is located %zd bytes inside of", (void*)addr, offset);
   } else {
-    Printf(" somewhere around (this is AddressSanitizer bug!)");
+    Printf("%p is located somewhere around (this is AddressSanitizer bug!)",
+           (void*)addr);
   }
   Printf(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
          (void*)(chunk.Beg()), (void*)(chunk.End()));
@@ -364,7 +378,7 @@
   if (DescribeAddressIfShadow(addr))
     return;
   CHECK(AddrIsInMem(addr));
-  if (DescribeAddressIfGlobal(addr))
+  if (DescribeAddressIfGlobal(addr, access_size))
     return;
   if (DescribeAddressIfStack(addr, access_size))
     return;
@@ -443,7 +457,8 @@
       DescribeThread(curr_thread->summary());
     }
     // Print memory stats.
-    __asan_print_accumulated_stats();
+    if (flags()->print_stats)
+      __asan_print_accumulated_stats();
     if (error_report_callback) {
       error_report_callback(error_message_buffer);
     }
@@ -452,6 +467,20 @@
   }
 };
 
+static void ReportSummary(const char *error_type, StackTrace *stack) {
+  if (!stack->size) return;
+  if (IsSymbolizerAvailable()) {
+    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);
+    ReportErrorSummary(error_type,
+                       StripPathPrefix(ai.file, flags()->strip_path_prefix),
+                       ai.line, ai.function);
+  }
+  // FIXME: do we need to print anything at all if there is no symbolizer?
+}
+
 void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
   ScopedInErrorReport in_report;
   Decorator d;
@@ -464,6 +493,7 @@
   Printf("AddressSanitizer can not provide additional info.\n");
   GET_STACK_TRACE_FATAL(pc, bp);
   PrintStack(&stack);
+  ReportSummary("SEGV", &stack);
 }
 
 void ReportDoubleFree(uptr addr, StackTrace *stack) {
@@ -474,6 +504,7 @@
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
+  ReportSummary("double-free", stack);
 }
 
 void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
@@ -485,6 +516,7 @@
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
+  ReportSummary("bad-free", stack);
 }
 
 void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
@@ -503,6 +535,7 @@
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
+  ReportSummary("alloc-dealloc-mismatch", stack);
   Report("HINT: if you don't care about these warnings you may set "
          "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
 }
@@ -517,6 +550,7 @@
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
+  ReportSummary("bad-malloc_usable_size", stack);
 }
 
 void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
@@ -529,6 +563,7 @@
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
+  ReportSummary("bad-__asan_get_allocated_size", stack);
 }
 
 void ReportStringFunctionMemoryRangesOverlap(
@@ -536,14 +571,17 @@
     const char *offset2, uptr length2, StackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
+  char bug_type[100];
+  internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
   Printf("%s", d.Warning());
-  Report("ERROR: AddressSanitizer: %s-param-overlap: "
+  Report("ERROR: AddressSanitizer: %s: "
              "memory ranges [%p,%p) and [%p, %p) overlap\n", \
-             function, offset1, offset1 + length1, offset2, offset2 + length2);
+             bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeAddress((uptr)offset1, length1);
   DescribeAddress((uptr)offset2, length2);
+  ReportSummary(bug_type, stack);
 }
 
 // ----------------------- Mac-specific reports ----------------- {{{1
@@ -653,7 +691,7 @@
   PrintStack(&stack);
 
   DescribeAddress(addr, access_size);
-
+  ReportSummary(bug_descr, &stack);
   PrintShadowMemoryForAddress(addr);
 }
 
Index: libsanitizer/asan/asan_allocator.cc
===================================================================
--- libsanitizer/asan/asan_allocator.cc	(revision 195997)
+++ libsanitizer/asan/asan_allocator.cc	(working copy)
@@ -32,7 +32,7 @@
 #include "asan_report.h"
 #include "asan_thread.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
+#include "sanitizer_common/sanitizer_allocator.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_mutex.h"
 
@@ -367,7 +367,7 @@
         left_chunk->chunk_state != CHUNK_AVAILABLE)
       return left_chunk;
     // Choose based on offset.
-    uptr l_offset = 0, r_offset = 0;
+    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)
@@ -387,7 +387,7 @@
     CHECK(m->chunk_state == CHUNK_ALLOCATED ||
           m->chunk_state == CHUNK_AVAILABLE ||
           m->chunk_state == CHUNK_QUARANTINE);
-    uptr offset = 0;
+    sptr offset = 0;
     AsanChunkView m_view(m);
     if (m_view.AddrIsInside(addr, 1, &offset))
       return m;
@@ -685,6 +685,8 @@
 
 namespace __asan {
 
+void InitializeAllocator() { }
+
 void PrintInternalAllocatorStats() {
 }
 
@@ -710,6 +712,7 @@
 }
 
 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);
Index: libsanitizer/asan/asan_interceptors.cc
===================================================================
--- libsanitizer/asan/asan_interceptors.cc	(revision 195997)
+++ libsanitizer/asan/asan_interceptors.cc	(working copy)
@@ -20,7 +20,6 @@
 #include "asan_stats.h"
 #include "asan_thread_registry.h"
 #include "interception/interception.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
 namespace __asan {
@@ -30,12 +29,14 @@
 // that no extra frames are created, and stack trace contains
 // relevant information only.
 // We check all shadow bytes.
-#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do {                  \
-  if (uptr __ptr = __asan_region_is_poisoned((uptr)(offset), size)) {    \
-    GET_CURRENT_PC_BP_SP;                                                \
-    __asan_report_error(pc, bp, sp, __ptr, isWrite, /* access_size */1); \
-  }                                                                      \
-} while (0)
+#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do {                 \
+    uptr __offset = (uptr)(offset);                                     \
+    uptr __size = (uptr)(size);                                         \
+    if (__asan_region_is_poisoned(__offset, __size)) {                  \
+      GET_CURRENT_PC_BP_SP;                                             \
+      __asan_report_error(pc, bp, sp, __offset, isWrite, __size);       \
+    }                                                                   \
+  } 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);
@@ -275,13 +276,9 @@
     ASAN_READ_RANGE(from, size);
     ASAN_WRITE_RANGE(to, size);
   }
-#if MAC_INTERPOSE_FUNCTIONS
   // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8.
   // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
   return internal_memcpy(to, from, size);
-#else
-  return REAL(memcpy)(to, from, size);
-#endif
 }
 
 INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
@@ -294,13 +291,9 @@
     ASAN_READ_RANGE(from, size);
     ASAN_WRITE_RANGE(to, size);
   }
-#if MAC_INTERPOSE_FUNCTIONS
   // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8.
   // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
   return internal_memmove(to, from, size);
-#else
-  return REAL(memmove)(to, from, size);
-#endif
 }
 
 INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
@@ -398,7 +391,7 @@
 }
 
 INTERCEPTOR(char*, strcpy, char *to, const char *from) {  // NOLINT
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
   if (!asan_inited) return REAL(strcpy)(to, from);  // NOLINT
 #endif
   // strcpy is called from malloc_default_purgeable_zone()
@@ -418,7 +411,7 @@
 
 #if ASAN_INTERCEPT_STRDUP
 INTERCEPTOR(char*, strdup, const char *s) {
-#if MAC_INTERPOSE_FUNCTIONS
+#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
@@ -559,7 +552,7 @@
 }
 
 INTERCEPTOR(int, atoi, const char *nptr) {
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
   if (!asan_inited) return REAL(atoi)(nptr);
 #endif
   ENSURE_ASAN_INITED();
@@ -578,7 +571,7 @@
 }
 
 INTERCEPTOR(long, atol, const char *nptr) {  // NOLINT
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
   if (!asan_inited) return REAL(atol)(nptr);
 #endif
   ENSURE_ASAN_INITED();
@@ -659,10 +652,9 @@
   static bool was_called_once;
   CHECK(was_called_once == false);
   was_called_once = true;
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
   return;
-#endif
-
+#else
   SANITIZER_COMMON_INTERCEPTORS_INIT;
 
   // Intercept mem* functions.
@@ -671,12 +663,6 @@
   ASAN_INTERCEPT_FUNC(memset);
   if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
     ASAN_INTERCEPT_FUNC(memcpy);
-  } else {
-#if !MAC_INTERPOSE_FUNCTIONS
-    // If we're using dynamic interceptors on Mac, these two are just plain
-    // functions.
-    internal_memcpy(&REAL(memcpy), &REAL(memmove), sizeof(REAL(memmove)));
-#endif
   }
 
   // Intercept str* functions.
@@ -698,12 +684,8 @@
 #if ASAN_INTERCEPT_STRNLEN
   ASAN_INTERCEPT_FUNC(strnlen);
 #endif
-#if ASAN_INTERCEPT_INDEX
-# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
+#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
   ASAN_INTERCEPT_FUNC(index);
-# else
-  CHECK(OVERRIDE_FUNCTION(index, WRAP(strchr)));
-# endif
 #endif
 
   ASAN_INTERCEPT_FUNC(atoi);
@@ -753,14 +735,10 @@
   InitializeWindowsInterceptors();
 #endif
 
-  // Some Mac-specific interceptors.
-#if defined(__APPLE__)
-  InitializeMacInterceptors();
-#endif
-
   if (flags()->verbosity > 0) {
     Report("AddressSanitizer: libc interceptors initialized\n");
   }
+#endif  // __APPLE__
 }
 
 }  // namespace __asan
Index: libsanitizer/asan/asan_allocator.h
===================================================================
--- libsanitizer/asan/asan_allocator.h	(revision 195997)
+++ libsanitizer/asan/asan_allocator.h	(working copy)
@@ -22,7 +22,7 @@
 // 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
-# if ASAN_LINUX && !ASAN_ANDROID
+# if (ASAN_LINUX && !ASAN_ANDROID) || ASAN_MAC || ASAN_WINDOWS
 #  define ASAN_ALLOCATOR_VERSION 2
 # else
 #  define ASAN_ALLOCATOR_VERSION 1
@@ -40,6 +40,8 @@
 static const uptr kNumberOfSizeClasses = 255;
 struct AsanChunk;
 
+void InitializeAllocator();
+
 class AsanChunkView {
  public:
   explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
@@ -51,14 +53,14 @@
   uptr FreeTid();
   void GetAllocStack(StackTrace *stack);
   void GetFreeStack(StackTrace *stack);
-  bool AddrIsInside(uptr addr, uptr access_size, uptr *offset) {
+  bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
     if (addr >= Beg() && (addr + access_size) <= End()) {
       *offset = addr - Beg();
       return true;
     }
     return false;
   }
-  bool AddrIsAtLeft(uptr addr, uptr access_size, uptr *offset) {
+  bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) {
     (void)access_size;
     if (addr < Beg()) {
       *offset = Beg() - addr;
@@ -66,12 +68,9 @@
     }
     return false;
   }
-  bool AddrIsAtRight(uptr addr, uptr access_size, uptr *offset) {
-    if (addr + access_size >= End()) {
-      if (addr <= End())
-        *offset = 0;
-      else
-        *offset = addr - End();
+  bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) {
+    if (addr + access_size > End()) {
+      *offset = addr - End();
       return true;
     }
     return false;
@@ -225,50 +224,5 @@
 
 void PrintInternalAllocatorStats();
 
-// Log2 and RoundUpToPowerOfTwo should be inlined for performance.
-#if defined(_WIN32) && !defined(__clang__)
-extern "C" {
-unsigned char _BitScanForward(unsigned long *index, unsigned long mask);  // NOLINT
-unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);  // NOLINT
-#if defined(_WIN64)
-unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask);  // NOLINT
-unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask);  // NOLINT
-#endif
-}
-#endif
-
-static inline uptr Log2(uptr x) {
-  CHECK(IsPowerOfTwo(x));
-#if !defined(_WIN32) || defined(__clang__)
-  return __builtin_ctzl(x);
-#elif defined(_WIN64)
-  unsigned long ret;  // NOLINT
-  _BitScanForward64(&ret, x);
-  return ret;
-#else
-  unsigned long ret;  // NOLINT
-  _BitScanForward(&ret, x);
-  return ret;
-#endif
-}
-
-static inline uptr RoundUpToPowerOfTwo(uptr size) {
-  CHECK(size);
-  if (IsPowerOfTwo(size)) return size;
-
-  unsigned long up;  // NOLINT
-#if !defined(_WIN32) || defined(__clang__)
-  up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(size);
-#elif defined(_WIN64)
-  _BitScanReverse64(&up, size);
-#else
-  _BitScanReverse(&up, size);
-#endif
-  CHECK(size < (1ULL << (up + 1)));
-  CHECK(size > (1ULL << up));
-  return 1UL << (up + 1);
-}
-
-
 }  // namespace __asan
 #endif  // ASAN_ALLOCATOR_H
Index: libsanitizer/asan/asan_fake_stack.cc
===================================================================
--- libsanitizer/asan/asan_fake_stack.cc	(revision 195997)
+++ libsanitizer/asan/asan_fake_stack.cc	(working copy)
@@ -12,7 +12,6 @@
 #include "asan_allocator.h"
 #include "asan_thread.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
 
 namespace __asan {
 
Index: libsanitizer/asan/asan_flags.h
===================================================================
--- libsanitizer/asan/asan_flags.h	(revision 195997)
+++ libsanitizer/asan/asan_flags.h	(working copy)
@@ -13,7 +13,7 @@
 #ifndef ASAN_FLAGS_H
 #define ASAN_FLAGS_H
 
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
 
 // ASan flag values can be defined in three ways:
 // 1) initialized with default values at startup.
@@ -50,8 +50,6 @@
   bool replace_str;
   // If set, uses custom wrappers for memset/memcpy/memmove intinsics.
   bool replace_intrin;
-  // Used on Mac only. See comments in asan_mac.cc and asan_malloc_mac.cc.
-  bool replace_cfallocator;
   // Used on Mac only.
   bool mac_ignore_invalid_free;
   // ASan allocator flag. See asan_allocator.cc.
@@ -77,6 +75,10 @@
   bool unmap_shadow_on_exit;
   // If set, calls abort() instead of _exit() after printing an error report.
   bool abort_on_error;
+  // Print various statistics after printing an error message or if atexit=1.
+  bool print_stats;
+  // Print the legend for the shadow bytes.
+  bool print_legend;
   // If set, prints ASan exit stats even after program terminates successfully.
   bool atexit;
   // By default, disable core dumper on 64-bit - it makes little sense
Index: libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc
===================================================================
--- libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc	(revision 195997)
+++ libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc	(working copy)
@@ -17,11 +17,6 @@
 
 namespace __asan {
 
-#if !MAC_INTERPOSE_FUNCTIONS
-# error \
-  Dynamic interposing library should be built with -DMAC_INTERPOSE_FUNCTIONS
-#endif
-
 #define INTERPOSE_FUNCTION(function) \
     { reinterpret_cast<const uptr>(WRAP(function)), \
       reinterpret_cast<const uptr>(function) }
Index: libsanitizer/asan/asan_stats.cc
===================================================================
--- libsanitizer/asan/asan_stats.cc	(revision 195997)
+++ libsanitizer/asan/asan_stats.cc	(working copy)
@@ -13,7 +13,6 @@
 #include "asan_internal.h"
 #include "asan_stats.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 
 namespace __asan {
Index: libsanitizer/asan/asan_interface_internal.h
===================================================================
--- libsanitizer/asan/asan_interface_internal.h	(revision 0)
+++ libsanitizer/asan/asan_interface_internal.h	(revision 0)
@@ -0,0 +1,133 @@
+//===-- asan_interface_internal.h -------------------------------*- C++ -*-===//
+//
+// 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.
+//
+// This header can be included by the instrumented program to fetch
+// data (mostly allocator statistics) from ASan runtime library.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERFACE_INTERNAL_H
+#define ASAN_INTERFACE_INTERNAL_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+using __sanitizer::uptr;
+
+extern "C" {
+  // This function should be called at the very beginning of the process,
+  // before any instrumented code is executed and before any call to malloc.
+  // 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_v1() SANITIZER_INTERFACE_ATTRIBUTE;
+  #define __asan_init __asan_init_v1
+
+  // This structure describes an instrumented global variable.
+  struct __asan_global {
+    uptr beg;                // The address of the global.
+    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.
+    uptr has_dynamic_init;   // Non-zero if the global has dynamic initializer.
+  };
+
+  // These two functions should be called by the instrumented code.
+  // 'globals' is an array of structures describing 'n' globals.
+  void __asan_register_globals(__asan_global *globals, uptr n)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_unregister_globals(__asan_global *globals, uptr n)
+      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)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_after_dynamic_init()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // These two functions are used by the instrumented code in the
+  // use-after-return mode. __asan_stack_malloc allocates size bytes of
+  // fake stack and __asan_stack_free poisons it. real_stack is a pointer to
+  // the real stack region.
+  uptr __asan_stack_malloc(uptr size, uptr real_stack)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_stack_free(uptr ptr, uptr size, uptr real_stack)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // These two functions are used by instrumented code in the
+  // use-after-scope mode. They mark memory for local variables as
+  // unaddressable when they leave scope and addressable before the
+  // function exits.
+  void __asan_poison_stack_memory(uptr addr, uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_unpoison_stack_memory(uptr addr, uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // Performs cleanup before a NoReturn function. Must be called before things
+  // like _exit and execl to avoid false positives on stack.
+  void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE;
+
+  void __asan_poison_memory_region(void const volatile *addr, uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_unpoison_memory_region(void const volatile *addr, uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  bool __asan_address_is_poisoned(void const volatile *addr)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  uptr __asan_region_is_poisoned(uptr beg, uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  void __asan_describe_address(uptr addr)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  void __asan_report_error(uptr pc, uptr bp, uptr sp,
+                           uptr addr, bool is_write, uptr access_size)
+    SANITIZER_INTERFACE_ATTRIBUTE;
+
+  int __asan_set_error_exit_code(int exit_code)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_set_death_callback(void (*callback)(void))
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_set_error_report_callback(void (*callback)(const char*))
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  /* OPTIONAL */ void __asan_on_error()
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+  /* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
+                                       int out_size)
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+  uptr __asan_get_estimated_allocated_size(uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  bool __asan_get_ownership(const void *p)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  uptr __asan_get_allocated_size(const void *p)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  uptr __asan_get_current_allocated_bytes()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  uptr __asan_get_heap_size()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  uptr __asan_get_free_bytes()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  uptr __asan_get_unmapped_bytes()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_print_accumulated_stats()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  /* OPTIONAL */ const char* __asan_default_options()
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+  /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size)
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  /* OPTIONAL */ void __asan_free_hook(void *ptr)
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+}  // extern "C"
+
+#endif  // ASAN_INTERFACE_INTERNAL_H
Index: libsanitizer/include/sanitizer/asan_interface.h
===================================================================
--- libsanitizer/include/sanitizer/asan_interface.h	(revision 195997)
+++ libsanitizer/include/sanitizer/asan_interface.h	(working copy)
@@ -5,69 +5,18 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file is a part of AddressSanitizer, an address sanity checker.
+// This file is a part of AddressSanitizer.
 //
-// This header can be included by the instrumented program to fetch
-// data (mostly allocator statistics) from ASan runtime library.
+// Public interface header.
 //===----------------------------------------------------------------------===//
 #ifndef SANITIZER_ASAN_INTERFACE_H
 #define SANITIZER_ASAN_INTERFACE_H
 
 #include <sanitizer/common_interface_defs.h>
 
-// ----------- ATTENTION -------------
-// This header should NOT include any other headers from ASan runtime.
-// All functions in this header are extern "C" and start with __asan_.
-
-using __sanitizer::uptr;
-
+#ifdef __cplusplus
 extern "C" {
-  // This function should be called at the very beginning of the process,
-  // before any instrumented code is executed and before any call to malloc.
-  void __asan_init() SANITIZER_INTERFACE_ATTRIBUTE;
-
-  // This structure describes an instrumented global variable.
-  struct __asan_global {
-    uptr beg;                // The address of the global.
-    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.
-    uptr has_dynamic_init;   // Non-zero if the global has dynamic initializer.
-  };
-
-  // These two functions should be called by the instrumented code.
-  // 'globals' is an array of structures describing 'n' globals.
-  void __asan_register_globals(__asan_global *globals, uptr n)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_unregister_globals(__asan_global *globals, uptr n)
-      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)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_after_dynamic_init()
-      SANITIZER_INTERFACE_ATTRIBUTE;
-
-  // These two functions are used by the instrumented code in the
-  // use-after-return mode. __asan_stack_malloc allocates size bytes of
-  // fake stack and __asan_stack_free poisons it. real_stack is a pointer to
-  // the real stack region.
-  uptr __asan_stack_malloc(uptr size, uptr real_stack)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_stack_free(uptr ptr, uptr size, uptr real_stack)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-
-  // These two functions are used by instrumented code in the
-  // use-after-scope mode. They mark memory for local variables as
-  // unaddressable when they leave scope and addressable before the
-  // function exits.
-  void __asan_poison_stack_memory(uptr addr, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_unpoison_stack_memory(uptr addr, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-
+#endif
   // Marks memory region [addr, addr+size) as unaddressable.
   // This memory must be previously allocated by the user program. Accessing
   // addresses in this region from instrumented code is forbidden until
@@ -76,8 +25,7 @@
   // to ASan alignment restrictions.
   // Method is NOT thread-safe in the sense that no two threads can
   // (un)poison memory in the same memory region simultaneously.
-  void __asan_poison_memory_region(void const volatile *addr, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_poison_memory_region(void const volatile *addr, size_t size);
   // Marks memory region [addr, addr+size) as addressable.
   // This memory must be previously allocated by the user program. Accessing
   // addresses in this region is allowed until this region is poisoned again.
@@ -85,14 +33,9 @@
   // ASan alignment restrictions.
   // Method is NOT thread-safe in the sense that no two threads can
   // (un)poison memory in the same memory region simultaneously.
-  void __asan_unpoison_memory_region(void const volatile *addr, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
 
-  // Performs cleanup before a NoReturn function. Must be called before things
-  // like _exit and execl to avoid false positives on stack.
-  void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE;
-
-// User code should use macro instead of functions.
+  // User code should use macro instead of functions.
 #if __has_feature(address_sanitizer)
 #define ASAN_POISON_MEMORY_REGION(addr, size) \
   __asan_poison_memory_region((addr), (size))
@@ -107,104 +50,86 @@
 
   // Returns true iff addr is poisoned (i.e. 1-byte read/write access to this
   // address will result in error report from AddressSanitizer).
-  bool __asan_address_is_poisoned(void const volatile *addr)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  bool __asan_address_is_poisoned(void const volatile *addr);
 
   // If at least on byte in [beg, beg+size) is poisoned, return the address
   // of the first such byte. Otherwise return 0.
-  uptr __asan_region_is_poisoned(uptr beg, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void *__asan_region_is_poisoned(void *beg, size_t size);
 
   // Print the description of addr (useful when debugging in gdb).
-  void __asan_describe_address(uptr addr)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_describe_address(void *addr);
 
   // This is an internal function that is called to report an error.
   // However it is still a part of the interface because users may want to
   // set a breakpoint on this function in a debugger.
-  void __asan_report_error(uptr pc, uptr bp, uptr sp,
-                           uptr addr, bool is_write, uptr access_size)
-    SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_report_error(void *pc, void *bp, void *sp,
+                           void *addr, bool is_write, size_t access_size);
 
   // Sets the exit code to use when reporting an error.
   // Returns the old value.
-  int __asan_set_error_exit_code(int exit_code)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  int __asan_set_error_exit_code(int exit_code);
 
   // Sets the callback to be called right before death on error.
   // Passing 0 will unset the callback.
-  void __asan_set_death_callback(void (*callback)(void))
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_set_death_callback(void (*callback)(void));
 
-  void __asan_set_error_report_callback(void (*callback)(const char*))
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_set_error_report_callback(void (*callback)(const char*));
 
   // User may provide function that would be called right when ASan detects
   // an error. This can be used to notice cases when ASan detects an error, but
   // the program crashes before ASan report is printed.
-  /* OPTIONAL */ void __asan_on_error()
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_on_error();
 
   // User may provide its own implementation for symbolization function.
   // It should print the description of instruction at address "pc" to
   // "out_buffer". Description should be at most "out_size" bytes long.
   // User-specified function should return true if symbolization was
   // successful.
-  /* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
-                                       int out_size)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  bool __asan_symbolize(const void *pc, char *out_buffer,
+                                       int out_size);
 
   // Returns the estimated number of bytes that will be reserved by allocator
   // for request of "size" bytes. If ASan allocator can't allocate that much
   // memory, returns the maximal possible allocation size, otherwise returns
   // "size".
-  uptr __asan_get_estimated_allocated_size(uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_estimated_allocated_size(size_t size);
   // Returns true if p was returned by the ASan allocator and
   // is not yet freed.
-  bool __asan_get_ownership(const void *p)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  bool __asan_get_ownership(const void *p);
   // Returns the number of bytes reserved for the pointer p.
   // Requires (get_ownership(p) == true) or (p == 0).
-  uptr __asan_get_allocated_size(const void *p)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_allocated_size(const void *p);
   // Number of bytes, allocated and not yet freed by the application.
-  uptr __asan_get_current_allocated_bytes()
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_current_allocated_bytes();
   // Number of bytes, mmaped by asan 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).
-  uptr __asan_get_heap_size()
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_heap_size();
   // Number of bytes, mmaped by asan 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 __asan_get_free_bytes() later.
-  uptr __asan_get_free_bytes()
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_free_bytes();
   // Number of bytes in unmapped pages, that are released to OS. Currently,
   // always returns 0.
-  uptr __asan_get_unmapped_bytes()
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_unmapped_bytes();
   // Prints accumulated stats to stderr. Used for debugging.
-  void __asan_print_accumulated_stats()
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_print_accumulated_stats();
 
   // This function may be optionally provided by user and should return
   // a string containing ASan runtime options. See asan_flags.h for details.
-  /* OPTIONAL */ const char* __asan_default_options()
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  const char* __asan_default_options();
 
   // Malloc hooks that may be optionally provided by user.
   // __asan_malloc_hook(ptr, size) is called immediately after
   //   allocation of "size" bytes, which returned "ptr".
   // __asan_free_hook(ptr) is called immediately before
   //   deallocation of "ptr".
-  /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
-  /* OPTIONAL */ void __asan_free_hook(void *ptr)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_malloc_hook(void *ptr, size_t size);
+  void __asan_free_hook(void *ptr);
+#ifdef __cplusplus
 }  // extern "C"
+#endif
 
 #endif  // SANITIZER_ASAN_INTERFACE_H
Index: libsanitizer/include/sanitizer/common_interface_defs.h
===================================================================
--- libsanitizer/include/sanitizer/common_interface_defs.h	(revision 195997)
+++ libsanitizer/include/sanitizer/common_interface_defs.h	(working copy)
@@ -5,86 +5,37 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file is shared between AddressSanitizer and ThreadSanitizer.
-// It contains basic macro and types.
-// NOTE: This file may be included into user code.
+// Common part of the public sanitizer interface.
 //===----------------------------------------------------------------------===//
 
 #ifndef SANITIZER_COMMON_INTERFACE_DEFS_H
 #define SANITIZER_COMMON_INTERFACE_DEFS_H
 
-// ----------- ATTENTION -------------
-// This header should NOT include any other headers to avoid portability issues.
+#include <stddef.h>
+#include <stdint.h>
 
-#if defined(_WIN32)
-// FIXME find out what we need on Windows. __declspec(dllexport) ?
-# define SANITIZER_INTERFACE_ATTRIBUTE
-# define SANITIZER_WEAK_ATTRIBUTE
-#elif defined(SANITIZER_GO)
-# define SANITIZER_INTERFACE_ATTRIBUTE
-# define SANITIZER_WEAK_ATTRIBUTE
-#else
-# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
-# define SANITIZER_WEAK_ATTRIBUTE  __attribute__((weak))
-#endif
-
-#ifdef __linux__
-# define SANITIZER_SUPPORTS_WEAK_HOOKS 1
-#else
-# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
-#endif
-
-// __has_feature
-#if !defined(__has_feature)
-# define __has_feature(x) 0
-#endif
-
-// For portability reasons we do not include stddef.h, stdint.h or any other
-// system header, but we do need some basic types that are not defined
-// in a portable way by the language itself.
-namespace __sanitizer {
-
-#if defined(_WIN64)
-// 64-bit Windows uses LLP64 data model.
-typedef unsigned long long uptr;  // NOLINT
-typedef signed   long long sptr;  // NOLINT
-#else
-typedef unsigned long uptr;  // NOLINT
-typedef signed   long sptr;  // NOLINT
-#endif  // defined(_WIN64)
-#if defined(__x86_64__)
-// Since x32 uses ILP32 data model in 64-bit hardware mode,  we must use
-// 64-bit pointer to unwind stack frame.
-typedef unsigned long long uhwptr;  // NOLINT
-#else
-typedef uptr uhwptr;   // NOLINT
-#endif
-typedef unsigned char u8;
-typedef unsigned short u16;  // NOLINT
-typedef unsigned int u32;
-typedef unsigned long long u64;  // NOLINT
-typedef signed   char s8;
-typedef signed   short s16;  // NOLINT
-typedef signed   int s32;
-typedef signed   long long s64;  // NOLINT
-
-}  // namespace __sanitizer
-
+#ifdef __cplusplus
 extern "C" {
+#endif
   // Tell the tools to write their reports to "path.<pid>" instead of stderr.
-  void __sanitizer_set_report_path(const char *path)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __sanitizer_set_report_path(const char *path);
 
   // Tell the tools to write their reports to given file descriptor instead of
   // stderr.
-  void __sanitizer_set_report_fd(int fd)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __sanitizer_set_report_fd(int fd);
 
   // Notify the tools that the sandbox is going to be turned on. The reserved
   // parameter will be used in the future to hold a structure with functions
   // that the tools may call to bypass the sandbox.
-  void __sanitizer_sandbox_on_notify(void *reserved)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  void __sanitizer_sandbox_on_notify(void *reserved);
+
+  // This function is called by the tool when it has just finished reporting
+  // an error. 'error_summary' is a one-line string that summarizes
+  // the error message. This function can be overridden by the client.
+  void __sanitizer_report_error_summary(const char *error_summary);
+
+#ifdef __cplusplus
 }  // extern "C"
+#endif
 
 #endif  // SANITIZER_COMMON_INTERFACE_DEFS_H
Index: libsanitizer/ChangeLog
===================================================================
--- libsanitizer/ChangeLog	(revision 195997)
+++ libsanitizer/ChangeLog	(working copy)
@@ -1,3 +1,10 @@
+2013-02-13  Kostya Serebryany  <kcc@google.com>
+
+        PR sanitizer/56128
+	* All source files: Merge from upstream r175042.
+	* interception/Makefile.am: added include path.
+	* interception/Makefile.in: Regenerated.
+
 2013-02-11  Jack Howarth  <howarth@bromo.med.uc.edu>
 
 	* configure.tgt: Disable build on darwin9 and earlier.
Index: libsanitizer/MERGE
===================================================================
--- libsanitizer/MERGE	(revision 195997)
+++ libsanitizer/MERGE	(working copy)
@@ -1,4 +1,4 @@
-173241
+175042
 
 The first line of this file holds the svn revision number of the
 last merge done from the master library sources.
Index: libsanitizer/interception/interception_mac.cc
===================================================================
--- libsanitizer/interception/interception_mac.cc	(revision 195997)
+++ libsanitizer/interception/interception_mac.cc	(working copy)
@@ -13,17 +13,6 @@
 #ifdef __APPLE__
 
 #include "interception.h"
-#include "mach_override/mach_override.h"
 
-namespace __interception {
-bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
-  *orig_old_func = 0;
-  int res = __asan_mach_override_ptr_custom((void*)old_func, (void*)new_func,
-                                            (void**)orig_old_func,
-                                            __interception_allocate_island,
-                                            __interception_deallocate_island);
-  return (res == 0) && (*orig_old_func != 0);
-}
-}  // namespace __interception
 
 #endif  // __APPLE__
Index: libsanitizer/interception/interception_type_test.cc
===================================================================
--- libsanitizer/interception/interception_type_test.cc	(revision 0)
+++ libsanitizer/interception/interception_type_test.cc	(revision 0)
@@ -0,0 +1,37 @@
+//===-- interception_type_test.cc -------------------------------*- C++ -*-===//
+//
+// 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.
+//
+// Compile-time tests of the internal type definitions.
+//===----------------------------------------------------------------------===//
+
+#if defined(__linux__) || defined(__APPLE__)
+
+#include "interception.h"
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdint.h>
+
+COMPILER_CHECK(sizeof(SIZE_T) == sizeof(size_t));
+COMPILER_CHECK(sizeof(SSIZE_T) == sizeof(ssize_t));
+COMPILER_CHECK(sizeof(PTRDIFF_T) == sizeof(ptrdiff_t));
+COMPILER_CHECK(sizeof(INTMAX_T) == sizeof(intmax_t));
+
+#ifndef __APPLE__
+COMPILER_CHECK(sizeof(OFF64_T) == sizeof(off64_t));
+#endif
+
+// The following are the cases when pread (and friends) is used instead of
+// pread64. In those cases we need OFF_T to match off_t. We don't care about the
+// rest (they depend on _FILE_OFFSET_BITS setting when building an application).
+# if defined(__ANDROID__) || !defined _FILE_OFFSET_BITS || \
+  _FILE_OFFSET_BITS != 64
+COMPILER_CHECK(sizeof(OFF_T) == sizeof(off_t));
+# endif
+
+#endif
Index: libsanitizer/interception/Makefile.am
===================================================================
--- libsanitizer/interception/Makefile.am	(revision 195997)
+++ libsanitizer/interception/Makefile.am	(working copy)
@@ -1,4 +1,4 @@
-AM_CPPFLAGS = -I $(top_srcdir)/include 
+AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
  
 # May be used by toolexeclibdir.
 gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
@@ -13,7 +13,8 @@
 interception_files = \
         interception_linux.cc \
         interception_mac.cc \
-        interception_win.cc
+        interception_win.cc \
+	interception_type_test.cc
 
 libinterception_la_SOURCES = $(interception_files)
 
Index: libsanitizer/interception/interception.h
===================================================================
--- libsanitizer/interception/interception.h	(revision 195997)
+++ libsanitizer/interception/interception.h	(working copy)
@@ -17,7 +17,7 @@
 # error "Interception doesn't work on this operating system."
 #endif
 
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
 
 // These typedefs should be used only in the interceptor definitions to replace
 // the standard system types (e.g. SSIZE_T instead of ssize_t)
@@ -25,21 +25,17 @@
 typedef __sanitizer::sptr SSIZE_T;
 typedef __sanitizer::sptr PTRDIFF_T;
 typedef __sanitizer::s64  INTMAX_T;
-typedef __sanitizer::u64  OFF_T;
+// WARNING: OFF_T may be different from OS type off_t, depending on the value of
+// _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 is special.
+#ifdef __APPLE__
+typedef __sanitizer::u64 OFF_T;
+#else
+typedef __sanitizer::uptr OFF_T;
+#endif
 typedef __sanitizer::u64  OFF64_T;
 
-// How to use this library:
-//      1) Include this header to define your own interceptors
-//         (see details below).
-//      2) Build all *.cc files and link against them.
-// On Mac you will also need to:
-//      3) Provide your own implementation for the following functions:
-//           mach_error_t __interception::allocate_island(void **ptr,
-//                                                      size_t size,
-//                                                      void *hint);
-//           mach_error_t __interception::deallocate_island(void *ptr);
-//         See "interception_mac.h" for more details.
-
 // How to add an interceptor:
 // Suppose you need to wrap/replace system function (generally, from libc):
 //      int foo(const char *bar, double baz);
@@ -80,21 +76,13 @@
 // This is not so on Mac OS, where the two-level namespace makes
 // our replacement functions invisible to other libraries. This may be overcomed
 // using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
-// libraries in Chromium were noticed when doing so. Instead we use
-// mach_override, a handy framework for patching functions at runtime.
-// To avoid possible name clashes, our replacement functions have
-// the "wrap_" prefix on Mac.
-// An alternative to function patching is to create a dylib containing a
-// __DATA,__interpose section that associates library functions with their
-// wrappers. When this dylib is preloaded before an executable using
-// DYLD_INSERT_LIBRARIES, it routes all the calls to interposed functions done
-// through stubs to the wrapper functions. Such a library is built with
-// -DMAC_INTERPOSE_FUNCTIONS=1.
+// libraries in Chromium were noticed when doing so.
+// Instead we create a dylib containing a __DATA,__interpose section that
+// associates library functions with their wrappers. When this dylib is
+// preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all
+// the calls to interposed functions done through stubs to the wrapper
+// functions.
 
-#if !defined(MAC_INTERPOSE_FUNCTIONS) || !defined(__APPLE__)
-# define MAC_INTERPOSE_FUNCTIONS 0
-#endif
-
 #if defined(__APPLE__)
 # define WRAP(x) wrap_##x
 # define WRAPPER_NAME(x) "wrap_"#x
@@ -120,7 +108,7 @@
     __attribute__((weak, alias("__interceptor_" #func), visibility("default")));
 #endif
 
-#if !MAC_INTERPOSE_FUNCTIONS
+#if !defined(__APPLE__)
 # define PTR_TO_REAL(x) real_##x
 # define REAL(x) __interception::PTR_TO_REAL(x)
 # define FUNC_TYPE(x) x##_f
@@ -130,11 +118,11 @@
     namespace __interception { \
       extern FUNC_TYPE(func) PTR_TO_REAL(func); \
     }
-#else  // MAC_INTERPOSE_FUNCTIONS
+#else  // __APPLE__
 # define REAL(x) x
 # define DECLARE_REAL(ret_type, func, ...) \
     extern "C" ret_type func(__VA_ARGS__);
-#endif  // MAC_INTERPOSE_FUNCTIONS
+#endif  // __APPLE__
 
 #define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
   DECLARE_REAL(ret_type, func, __VA_ARGS__) \
@@ -144,7 +132,7 @@
 // macros does its job. In exceptional cases you may need to call REAL(foo)
 // without defining INTERCEPTOR(..., foo, ...). For example, if you override
 // foo with an interceptor for other function.
-#if !MAC_INTERPOSE_FUNCTIONS
+#if !defined(__APPLE__)
 # define DEFINE_REAL(ret_type, func, ...) \
     typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
     namespace __interception { \
Index: libsanitizer/interception/interception_mac.h
===================================================================
--- libsanitizer/interception/interception_mac.h	(revision 195997)
+++ libsanitizer/interception/interception_mac.h	(working copy)
@@ -19,29 +19,7 @@
 #ifndef INTERCEPTION_MAC_H
 #define INTERCEPTION_MAC_H
 
-#include <mach/mach_error.h>
-#include <stddef.h>
+#define INTERCEPT_FUNCTION_MAC(func)
 
-// Allocate memory for the escape island. This cannot be moved to
-// mach_override, because each user of interceptors may specify its
-// own memory range for escape islands.
-extern "C" {
-mach_error_t __interception_allocate_island(void **ptr, size_t unused_size,
-                                            void *unused_hint);
-mach_error_t __interception_deallocate_island(void *ptr);
-}  // extern "C"
-
-namespace __interception {
-// returns true if the old function existed.
-bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func);
-}  // namespace __interception
-
-# define OVERRIDE_FUNCTION_MAC(old_func, new_func) \
-    ::__interception::OverrideFunction( \
-          (::__interception::uptr)old_func, \
-          (::__interception::uptr)new_func, \
-          (::__interception::uptr*)((::__interception::uptr)&REAL(old_func)))
-# define INTERCEPT_FUNCTION_MAC(func) OVERRIDE_FUNCTION_MAC(func, WRAP(func))
-
 #endif  // INTERCEPTION_MAC_H
 #endif  // __APPLE__
Index: libsanitizer/interception/Makefile.in
===================================================================
--- libsanitizer/interception/Makefile.in	(revision 195997)
+++ libsanitizer/interception/Makefile.in	(working copy)
@@ -56,7 +56,7 @@
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 libinterception_la_LIBADD =
 am__objects_1 = interception_linux.lo interception_mac.lo \
-	interception_win.lo
+	interception_win.lo interception_type_test.lo
 am_libinterception_la_OBJECTS = $(am__objects_1)
 libinterception_la_OBJECTS = $(am_libinterception_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@
@@ -208,7 +208,7 @@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-AM_CPPFLAGS = -I $(top_srcdir)/include 
+AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
 
 # May be used by toolexeclibdir.
 gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
@@ -221,7 +221,8 @@
 interception_files = \
         interception_linux.cc \
         interception_mac.cc \
-        interception_win.cc
+        interception_win.cc \
+	interception_type_test.cc
 
 libinterception_la_SOURCES = $(interception_files)
 
@@ -318,6 +319,7 @@
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_linux.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_mac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_type_test.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_win.Plo@am__quote@
 
 .cc.o:
Index: libsanitizer/tsan/tsan_suppressions.h
===================================================================
--- libsanitizer/tsan/tsan_suppressions.h	(revision 195997)
+++ libsanitizer/tsan/tsan_suppressions.h	(working copy)
@@ -33,7 +33,7 @@
   char *templ;
 };
 
-Suppression *SuppressionParse(const char* supp);
+Suppression *SuppressionParse(Suppression *head, const char* supp);
 bool SuppressionMatch(char *templ, const char *str);
 
 }  // namespace __tsan
Index: libsanitizer/tsan/tsan_interceptors.cc
===================================================================
--- libsanitizer/tsan/tsan_interceptors.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_interceptors.cc	(working copy)
@@ -51,9 +51,12 @@
 extern "C" int sigfillset(sigset_t *set);
 extern "C" void *pthread_self();
 extern "C" void _exit(int status);
-extern "C" int __cxa_atexit(void (*func)(void *arg), void *arg, void *dso);
 extern "C" int *__errno_location();
 extern "C" int fileno_unlocked(void *stream);
+extern "C" void *__libc_malloc(uptr size);
+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);
 const int PTHREAD_MUTEX_RECURSIVE = 1;
 const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
 const int kPthreadAttrSize = 56;
@@ -122,7 +125,7 @@
   int pending_signal_count;
   SignalDesc pending_signals[kSigCount];
 };
-}
+}  // namespace __tsan
 
 static SignalContext *SigCtx(ThreadState *thr) {
   SignalContext *ctx = (SignalContext*)thr->signal_ctx;
@@ -238,12 +241,15 @@
 
   typedef void(*atexit_t)();
 
-  int atexit(ThreadState *thr, uptr pc, atexit_t f) {
+  int atexit(ThreadState *thr, uptr pc, bool is_on_exit,
+             atexit_t f, void *arg) {
     Lock l(&mtx_);
     if (pos_ == kMaxAtExit)
       return 1;
     Release(thr, pc, (uptr)this);
     stack_[pos_] = f;
+    args_[pos_] = arg;
+    is_on_exits_[pos_] = is_on_exit;
     pos_++;
     return 0;
   }
@@ -252,11 +258,15 @@
     CHECK_EQ(thr->in_rtl, 0);
     for (;;) {
       atexit_t f = 0;
+      void *arg = 0;
+      bool is_on_exit = false;
       {
         Lock l(&mtx_);
         if (pos_) {
           pos_--;
           f = stack_[pos_];
+          arg = args_[pos_];
+          is_on_exit = is_on_exits_[pos_];
           ScopedInRtl in_rtl;
           Acquire(thr, pc, (uptr)this);
         }
@@ -265,7 +275,10 @@
         break;
       DPrintf("#%d: executing atexit func %p\n", thr->tid, f);
       CHECK_EQ(thr->in_rtl, 0);
-      f();
+      if (is_on_exit)
+        ((void(*)(int status, void *arg))f)(0, arg);
+      else
+        ((void(*)(void *arg, void *dso))f)(arg, 0);
     }
   }
 
@@ -273,6 +286,8 @@
   static const int kMaxAtExit = 128;
   Mutex mtx_;
   atexit_t stack_[kMaxAtExit];
+  void *args_[kMaxAtExit];
+  bool is_on_exits_[kMaxAtExit];
   int pos_;
 };
 
@@ -282,20 +297,34 @@
   ThreadState * thr = cur_thread();
   uptr pc = 0;
   atexit_ctx->exit(thr, pc);
-  {
-    ScopedInRtl in_rtl;
-    DestroyAndFree(atexit_ctx);
-  }
   int status = Finalize(cur_thread());
   if (status)
     _exit(status);
 }
 
 TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
+  if (cur_thread()->in_symbolizer)
+    return 0;
   SCOPED_TSAN_INTERCEPTOR(atexit, f);
-  return atexit_ctx->atexit(thr, pc, f);
+  return atexit_ctx->atexit(thr, pc, false, (void(*)())f, 0);
 }
 
+TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
+  if (cur_thread()->in_symbolizer)
+    return 0;
+  SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
+  return atexit_ctx->atexit(thr, pc, true, (void(*)())f, arg);
+}
+
+TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
+  if (cur_thread()->in_symbolizer)
+    return 0;
+  SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
+  if (dso)
+    return REAL(__cxa_atexit)(f, arg, dso);
+  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");
@@ -309,6 +338,8 @@
 }
 
 TSAN_INTERCEPTOR(void*, malloc, uptr size) {
+  if (cur_thread()->in_symbolizer)
+    return __libc_malloc(size);
   void *p = 0;
   {
     SCOPED_INTERCEPTOR_RAW(malloc, size);
@@ -324,6 +355,9 @@
 }
 
 TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
+  if (cur_thread()->in_symbolizer)
+    return __libc_calloc(size, n);
+  if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, n)) return 0;
   void *p = 0;
   {
     SCOPED_INTERCEPTOR_RAW(calloc, size, n);
@@ -335,6 +369,8 @@
 }
 
 TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
+  if (cur_thread()->in_symbolizer)
+    return __libc_realloc(p, size);
   if (p)
     invoke_free_hook(p);
   {
@@ -348,6 +384,8 @@
 TSAN_INTERCEPTOR(void, free, void *p) {
   if (p == 0)
     return;
+  if (cur_thread()->in_symbolizer)
+    return __libc_free(p);
   invoke_free_hook(p);
   SCOPED_INTERCEPTOR_RAW(free, p);
   user_free(thr, pc, p);
@@ -356,12 +394,16 @@
 TSAN_INTERCEPTOR(void, cfree, void *p) {
   if (p == 0)
     return;
+  if (cur_thread()->in_symbolizer)
+    return __libc_free(p);
   invoke_free_hook(p);
   SCOPED_INTERCEPTOR_RAW(cfree, p);
   user_free(thr, pc, p);
 }
 
 #define OPERATOR_NEW_BODY(mangled_name) \
+  if (cur_thread()->in_symbolizer) \
+    return __libc_malloc(size); \
   void *p = 0; \
   {  \
     SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
@@ -385,6 +427,8 @@
 
 #define OPERATOR_DELETE_BODY(mangled_name) \
   if (ptr == 0) return;  \
+  if (cur_thread()->in_symbolizer) \
+    return __libc_free(ptr); \
   invoke_free_hook(ptr);  \
   SCOPED_INTERCEPTOR_RAW(mangled_name, ptr);  \
   user_free(thr, pc, ptr);
@@ -549,6 +593,8 @@
     return MAP_FAILED;
   void *res = REAL(mmap)(addr, sz, prot, flags, fd, off);
   if (res != MAP_FAILED) {
+    if (fd > 0)
+      FdAccess(thr, pc, fd);
     MemoryResetRange(thr, pc, (uptr)res, sz);
   }
   return res;
@@ -561,6 +607,8 @@
     return MAP_FAILED;
   void *res = REAL(mmap64)(addr, sz, prot, flags, fd, off);
   if (res != MAP_FAILED) {
+    if (fd > 0)
+      FdAccess(thr, pc, fd);
     MemoryResetRange(thr, pc, (uptr)res, sz);
   }
   return res;
@@ -958,14 +1006,14 @@
 
 TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) {
   SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count);
-  MemoryWrite1Byte(thr, pc, (uptr)b);
+  MemoryWrite(thr, pc, (uptr)b, kSizeLog1);
   int res = REAL(pthread_barrier_init)(b, a, count);
   return res;
 }
 
 TSAN_INTERCEPTOR(int, pthread_barrier_destroy, void *b) {
   SCOPED_TSAN_INTERCEPTOR(pthread_barrier_destroy, b);
-  MemoryWrite1Byte(thr, pc, (uptr)b);
+  MemoryWrite(thr, pc, (uptr)b, kSizeLog1);
   int res = REAL(pthread_barrier_destroy)(b);
   return res;
 }
@@ -973,9 +1021,9 @@
 TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
   SCOPED_TSAN_INTERCEPTOR(pthread_barrier_wait, b);
   Release(thr, pc, (uptr)b);
-  MemoryRead1Byte(thr, pc, (uptr)b);
+  MemoryRead(thr, pc, (uptr)b, kSizeLog1);
   int res = REAL(pthread_barrier_wait)(b);
-  MemoryRead1Byte(thr, pc, (uptr)b);
+  MemoryRead(thr, pc, (uptr)b, kSizeLog1);
   if (res == 0 || res == PTHREAD_BARRIER_SERIAL_THREAD) {
     Acquire(thr, pc, (uptr)b);
   }
@@ -1062,6 +1110,74 @@
   return res;
 }
 
+TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
+  return REAL(__xstat)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__xstat, 0, path, buf);
+  return REAL(__xstat)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
+  return REAL(__xstat64)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
+  return REAL(__xstat64)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
+  return REAL(__lxstat)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__lxstat, 0, path, buf);
+  return REAL(__lxstat)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
+  return REAL(__lxstat64)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
+  return REAL(__lxstat64)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf);
+  if (fd > 0)
+    FdAccess(thr, pc, fd);
+  return REAL(__fxstat)(version, fd, buf);
+}
+
+TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf);
+  if (fd > 0)
+    FdAccess(thr, pc, fd);
+  return REAL(__fxstat)(0, fd, buf);
+}
+
+TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
+  if (fd > 0)
+    FdAccess(thr, pc, fd);
+  return REAL(__fxstat64)(version, fd, buf);
+}
+
+TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
+  if (fd > 0)
+    FdAccess(thr, pc, fd);
+  return REAL(__fxstat64)(0, fd, buf);
+}
+
 TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
   SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode);
   int fd = REAL(open)(name, flags, mode);
@@ -1177,6 +1293,22 @@
   return res;
 }
 
+TSAN_INTERCEPTOR(int, bind, int fd, void *addr, unsigned addrlen) {
+  SCOPED_TSAN_INTERCEPTOR(bind, fd, addr, addrlen);
+  int res = REAL(bind)(fd, addr, addrlen);
+  if (fd > 0 && res == 0)
+    FdAccess(thr, pc, fd);
+  return res;
+}
+
+TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
+  SCOPED_TSAN_INTERCEPTOR(listen, fd, backlog);
+  int res = REAL(listen)(fd, backlog);
+  if (fd > 0 && res == 0)
+    FdAccess(thr, pc, fd);
+  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);
@@ -1223,6 +1355,18 @@
   return REAL(__close)(fd);
 }
 
+// glibc guts
+TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
+  SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr);
+  int fds[64];
+  int cnt = ExtractResolvFDs(state, fds, ARRAY_SIZE(fds));
+  for (int i = 0; i < cnt; i++) {
+    if (fds[i] > 0)
+      FdClose(thr, pc, fds[i]);
+  }
+  REAL(__res_iclose)(state, free_addr);
+}
+
 TSAN_INTERCEPTOR(int, pipe, int *pipefd) {
   SCOPED_TSAN_INTERCEPTOR(pipe, pipefd);
   int res = REAL(pipe)(pipefd);
@@ -1765,6 +1909,18 @@
   TSAN_INTERCEPT(sem_post);
   TSAN_INTERCEPT(sem_getvalue);
 
+  TSAN_INTERCEPT(stat);
+  TSAN_INTERCEPT(__xstat);
+  TSAN_INTERCEPT(stat64);
+  TSAN_INTERCEPT(__xstat64);
+  TSAN_INTERCEPT(lstat);
+  TSAN_INTERCEPT(__lxstat);
+  TSAN_INTERCEPT(lstat64);
+  TSAN_INTERCEPT(__lxstat64);
+  TSAN_INTERCEPT(fstat);
+  TSAN_INTERCEPT(__fxstat);
+  TSAN_INTERCEPT(fstat64);
+  TSAN_INTERCEPT(__fxstat64);
   TSAN_INTERCEPT(open);
   TSAN_INTERCEPT(open64);
   TSAN_INTERCEPT(creat);
@@ -1779,11 +1935,15 @@
   TSAN_INTERCEPT(socket);
   TSAN_INTERCEPT(socketpair);
   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);
+  TSAN_INTERCEPT(__close);
+  TSAN_INTERCEPT(__res_iclose);
   TSAN_INTERCEPT(pipe);
   TSAN_INTERCEPT(pipe2);
 
@@ -1826,6 +1986,8 @@
   TSAN_INTERCEPT(munlockall);
 
   TSAN_INTERCEPT(fork);
+  TSAN_INTERCEPT(on_exit);
+  TSAN_INTERCEPT(__cxa_atexit);
 
   // Need to setup it, because interceptors check that the function is resolved.
   // But atexit is emitted directly into the module, so can't be resolved.
@@ -1833,7 +1995,7 @@
   atexit_ctx = new(internal_alloc(MBlockAtExit, sizeof(AtExitContext)))
       AtExitContext();
 
-  if (__cxa_atexit(&finalize, 0, 0)) {
+  if (REAL(__cxa_atexit)(&finalize, 0, 0)) {
     Printf("ThreadSanitizer: failed to setup atexit callback\n");
     Die();
   }
Index: libsanitizer/tsan/tsan_defs.h
===================================================================
--- libsanitizer/tsan/tsan_defs.h	(revision 195997)
+++ libsanitizer/tsan/tsan_defs.h	(working copy)
@@ -26,16 +26,19 @@
 const bool kGoMode = true;
 const bool kCppMode = false;
 const char *const kTsanOptionsEnv = "GORACE";
+// Go linker does not support weak symbols.
+#define CPP_WEAK
 #else
 const bool kGoMode = false;
 const bool kCppMode = true;
 const char *const kTsanOptionsEnv = "TSAN_OPTIONS";
+#define CPP_WEAK WEAK
 #endif
 
 const int kTidBits = 13;
 const unsigned kMaxTid = 1 << kTidBits;
 const unsigned kMaxTidInClock = kMaxTid * 2;  // This includes msb 'freed' bit.
-const int kClkBits = 43;
+const int kClkBits = 42;
 #ifndef TSAN_GO
 const int kShadowStackSize = 4 * 1024;
 const int kTraceStackSize = 256;
Index: libsanitizer/tsan/tsan_rtl_thread.cc
===================================================================
--- libsanitizer/tsan/tsan_rtl_thread.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_rtl_thread.cc	(working copy)
@@ -207,6 +207,9 @@
   thr->shadow_stack_pos = thr->shadow_stack;
   thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
 #endif
+#ifndef TSAN_GO
+  AllocatorThreadStart(thr);
+#endif
   tctx->thr = thr;
   thr->fast_synch_epoch = tctx->epoch0;
   thr->clock.set(tid, tctx->epoch0);
@@ -267,7 +270,7 @@
   tctx->epoch1 = thr->fast_state.epoch();
 
 #ifndef TSAN_GO
-  AlloctorThreadFinish(thr);
+  AllocatorThreadFinish(thr);
 #endif
   thr->~ThreadState();
   StatAggregate(ctx->stat, thr->stat);
@@ -392,7 +395,7 @@
     Shadow cur(fast_state);
     cur.SetWrite(is_write);
     cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
-    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write,
+    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
         shadow_mem, cur);
   }
   if (unaligned)
@@ -403,7 +406,7 @@
     Shadow cur(fast_state);
     cur.SetWrite(is_write);
     cur.SetAddr0AndSizeLog(0, kAccessSizeLog);
-    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write,
+    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
         shadow_mem, cur);
     shadow_mem += kShadowCnt;
   }
@@ -413,24 +416,8 @@
     Shadow cur(fast_state);
     cur.SetWrite(is_write);
     cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
-    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write,
+    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
         shadow_mem, cur);
   }
 }
-
-void MemoryRead1Byte(ThreadState *thr, uptr pc, uptr addr) {
-  MemoryAccess(thr, pc, addr, 0, 0);
-}
-
-void MemoryWrite1Byte(ThreadState *thr, uptr pc, uptr addr) {
-  MemoryAccess(thr, pc, addr, 0, 1);
-}
-
-void MemoryRead8Byte(ThreadState *thr, uptr pc, uptr addr) {
-  MemoryAccess(thr, pc, addr, 3, 0);
-}
-
-void MemoryWrite8Byte(ThreadState *thr, uptr pc, uptr addr) {
-  MemoryAccess(thr, pc, addr, 3, 1);
-}
 }  // namespace __tsan
Index: libsanitizer/tsan/tsan_mman.h
===================================================================
--- libsanitizer/tsan/tsan_mman.h	(revision 195997)
+++ libsanitizer/tsan/tsan_mman.h	(working copy)
@@ -18,7 +18,9 @@
 const uptr kDefaultAlignment = 16;
 
 void InitializeAllocator();
-void AlloctorThreadFinish(ThreadState *thr);
+void AllocatorThreadStart(ThreadState *thr);
+void AllocatorThreadFinish(ThreadState *thr);
+void AllocatorPrintStats();
 
 // For user allocations.
 void *user_alloc(ThreadState *thr, uptr pc, uptr sz,
Index: libsanitizer/tsan/tsan_rtl_report.cc
===================================================================
--- libsanitizer/tsan/tsan_rtl_report.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_rtl_report.cc	(working copy)
@@ -13,6 +13,7 @@
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 #include "tsan_platform.h"
 #include "tsan_rtl.h"
 #include "tsan_suppressions.h"
@@ -27,12 +28,15 @@
 
 using namespace __sanitizer;  // NOLINT
 
+static ReportStack *SymbolizeStack(const StackTrace& trace);
+
 void TsanCheckFailed(const char *file, int line, const char *cond,
                      u64 v1, u64 v2) {
   ScopedInRtl in_rtl;
   Printf("FATAL: ThreadSanitizer CHECK failed: "
          "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
          file, line, cond, (uptr)v1, (uptr)v2);
+  PrintCurrentStackSlow();
   Die();
 }
 
@@ -144,7 +148,8 @@
   mop->tid = s.tid();
   mop->addr = addr + s.addr0();
   mop->size = s.size();
-  mop->write = s.is_write();
+  mop->write = s.IsWrite();
+  mop->atomic = s.IsAtomic();
   mop->stack = SymbolizeStack(*stack);
   for (uptr i = 0; i < mset->Size(); i++) {
     MutexSet::Desc d = mset->Get(i);
@@ -458,9 +463,12 @@
 
 bool OutputReport(Context *ctx,
                   const ScopedReport &srep,
-                  const ReportStack *suppress_stack) {
+                  const ReportStack *suppress_stack1,
+                  const ReportStack *suppress_stack2) {
   const ReportDesc *rep = srep.GetReport();
-  const uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack);
+  uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1);
+  if (suppress_pc == 0)
+    suppress_pc = IsSuppressed(rep->typ, suppress_stack2);
   if (suppress_pc != 0) {
     FiredSuppression supp = {srep.GetReport()->typ, suppress_pc};
     ctx->fired_suppressions.PushBack(supp);
@@ -486,6 +494,13 @@
   return false;
 }
 
+bool FrameIsInternal(const ReportStack *frame) {
+  return frame != 0 && frame->file != 0
+      && (internal_strstr(frame->file, "tsan_interceptors.cc") ||
+          internal_strstr(frame->file, "sanitizer_common_interceptors.inc") ||
+          internal_strstr(frame->file, "tsan_interface_"));
+}
+
 // On programs that use Java we see weird reports like:
 // WARNING: ThreadSanitizer: data race (pid=22512)
 //   Read of size 8 at 0x7d2b00084318 by thread 100:
@@ -495,22 +510,20 @@
 //     #0 strncpy tsan_interceptors.cc:501 (foo+0x00000d8e0919)
 //     #1 <null> <null>:0 (0x7f7ad9b42707)
 static bool IsJavaNonsense(const ReportDesc *rep) {
+#ifndef TSAN_GO
   for (uptr i = 0; i < rep->mops.Size(); i++) {
     ReportMop *mop = rep->mops[i];
     ReportStack *frame = mop->stack;
-    if (frame != 0 && frame->func != 0
-        && (internal_strcmp(frame->func, "memset") == 0
-        || internal_strcmp(frame->func, "memcpy") == 0
-        || internal_strcmp(frame->func, "memmove") == 0
-        || internal_strcmp(frame->func, "strcmp") == 0
-        || internal_strcmp(frame->func, "strncpy") == 0
-        || internal_strcmp(frame->func, "strlen") == 0
-        || internal_strcmp(frame->func, "free") == 0
-        || internal_strcmp(frame->func, "pthread_mutex_lock") == 0)) {
+    if (frame == 0
+        || (frame->func == 0 && frame->file == 0 && frame->line == 0
+          && frame->module == 0)) {
+      return true;
+    }
+    if (FrameIsInternal(frame)) {
       frame = frame->next;
       if (frame == 0
           || (frame->func == 0 && frame->file == 0 && frame->line == 0
-            && frame->module == 0)) {
+          && frame->module == 0)) {
         if (frame) {
           FiredSuppression supp = {rep->typ, frame->pc};
           CTX()->fired_suppressions.PushBack(supp);
@@ -519,14 +532,31 @@
       }
     }
   }
+#endif
   return false;
 }
 
+static bool RaceBetweenAtomicAndFree(ThreadState *thr) {
+  Shadow s0(thr->racy_state[0]);
+  Shadow s1(thr->racy_state[1]);
+  CHECK(!(s0.IsAtomic() && s1.IsAtomic()));
+  if (!s0.IsAtomic() && !s1.IsAtomic())
+    return true;
+  if (s0.IsAtomic() && s1.IsFreed())
+    return true;
+  if (s1.IsAtomic() && thr->is_freeing)
+    return true;
+  return false;
+}
+
 void ReportRace(ThreadState *thr) {
   if (!flags()->report_bugs)
     return;
   ScopedInRtl in_rtl;
 
+  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");
@@ -597,7 +627,8 @@
   }
 #endif
 
-  if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack))
+  if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack,
+                              rep.GetReport()->mops[1]->stack))
     return;
 
   AddRacyStacks(thr, traces, addr_min, addr_max);
@@ -609,4 +640,16 @@
   PrintStack(SymbolizeStack(trace));
 }
 
+void PrintCurrentStackSlow() {
+#ifndef TSAN_GO
+  __sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
+      sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
+  ptrace->SlowUnwindStack(__sanitizer::StackTrace::GetCurrentPc(),
+      kStackTraceMax);
+  StackTrace trace;
+  trace.Init(ptrace->trace, ptrace->size);
+  PrintStack(SymbolizeStack(trace));
+#endif
+}
+
 }  // namespace __tsan
Index: libsanitizer/tsan/tsan_interface_atomic.cc
===================================================================
--- libsanitizer/tsan/tsan_interface_atomic.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_interface_atomic.cc	(working copy)
@@ -18,25 +18,42 @@
 // http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/
 
 #include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 #include "tsan_interface_atomic.h"
 #include "tsan_flags.h"
 #include "tsan_rtl.h"
 
 using namespace __tsan;  // NOLINT
 
+#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__); \
+    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, 1);  // 1 due to our own ScopedInRtl member.
+    CHECK_EQ(thr_->in_rtl, 0);
+    ProcessPendingSignals(thr);
+    FuncEntry(thr_, pc);
     DPrintf("#%d: %s\n", thr_->tid, func);
+    thr_->in_rtl++;
   }
   ~ScopedAtomic() {
-    CHECK_EQ(thr_->in_rtl, 1);
+    thr_->in_rtl--;
+    CHECK_EQ(thr_->in_rtl, 0);
+    FuncExit(thr_);
   }
  private:
   ThreadState *thr_;
-  ScopedInRtl in_rtl_;
 };
 
 // Some shortcuts.
@@ -210,16 +227,19 @@
 }
 #endif
 
-#define SCOPED_ATOMIC(func, ...) \
-    mo = ConvertOrder(mo); \
-    mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
-    ThreadState *const thr = cur_thread(); \
-    ProcessPendingSignals(thr); \
-    const uptr pc = (uptr)__builtin_return_address(0); \
-    AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
-    ScopedAtomic sa(thr, pc, __FUNCTION__); \
-    return Atomic##func(thr, pc, __VA_ARGS__); \
-/**/
+template<typename T>
+static int SizeLog() {
+  if (sizeof(T) <= 1)
+    return kSizeLog1;
+  else if (sizeof(T) <= 2)
+    return kSizeLog2;
+  else if (sizeof(T) <= 4)
+    return kSizeLog4;
+  else
+    return kSizeLog8;
+  // For 16-byte atomics we also use 8-byte memory access,
+  // this leads to false negatives only in very obscure cases.
+}
 
 template<typename T>
 static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a,
@@ -227,14 +247,17 @@
   CHECK(IsLoadOrder(mo));
   // This fast-path is critical for performance.
   // Assume the access is atomic.
-  if (!IsAcquireOrder(mo) && sizeof(T) <= sizeof(a))
+  if (!IsAcquireOrder(mo) && sizeof(T) <= sizeof(a)) {
+    MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
     return *a;
+  }
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, false);
   thr->clock.set(thr->tid, thr->fast_state.epoch());
   thr->clock.acquire(&s->clock);
   T v = *a;
   s->mtx.ReadUnlock();
   __sync_synchronize();
+  MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
   return v;
 }
 
@@ -242,6 +265,7 @@
 static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
     morder mo) {
   CHECK(IsStoreOrder(mo));
+  MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
   // This fast-path is critical for performance.
   // Assume the access is atomic.
   // Strictly saying even relaxed store cuts off release sequence,
@@ -263,6 +287,7 @@
 
 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))
@@ -322,6 +347,7 @@
 static bool AtomicCAS(ThreadState *thr, uptr pc,
     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))
Index: libsanitizer/tsan/tsan_interface_ann.h
===================================================================
--- libsanitizer/tsan/tsan_interface_ann.h	(revision 195997)
+++ libsanitizer/tsan/tsan_interface_ann.h	(working copy)
@@ -12,7 +12,7 @@
 #ifndef TSAN_INTERFACE_ANN_H
 #define TSAN_INTERFACE_ANN_H
 
-#include <sanitizer/common_interface_defs.h>
+#include <sanitizer_common/sanitizer_internal_defs.h>
 
 // This header should NOT include any other headers.
 // All functions in this header are extern "C" and start with __tsan_.
Index: libsanitizer/tsan/tsan_flags.h
===================================================================
--- libsanitizer/tsan/tsan_flags.h	(revision 195997)
+++ libsanitizer/tsan/tsan_flags.h	(working copy)
@@ -41,6 +41,8 @@
   // Report violations of async signal-safety
   // (e.g. malloc() call from a signal handler).
   bool report_signal_unsafe;
+  // Report races between atomic and plain memory accesses.
+  bool report_atomic_races;
   // If set, all atomics are effectively sequentially consistent (seq_cst),
   // regardless of what user actually specified.
   bool force_seq_cst_atomics;
@@ -84,6 +86,6 @@
 
 Flags *flags();
 void InitializeFlags(Flags *flags, const char *env);
-}
+}  // namespace __tsan
 
 #endif  // TSAN_FLAGS_H
Index: libsanitizer/tsan/tsan_interface.h
===================================================================
--- libsanitizer/tsan/tsan_interface.h	(revision 195997)
+++ libsanitizer/tsan/tsan_interface.h	(working copy)
@@ -14,7 +14,7 @@
 #ifndef TSAN_INTERFACE_H
 #define TSAN_INTERFACE_H
 
-#include <sanitizer/common_interface_defs.h>
+#include <sanitizer_common/sanitizer_internal_defs.h>
 
 // This header should NOT include any other headers.
 // All functions in this header are extern "C" and start with __tsan_.
Index: libsanitizer/tsan/tsan_platform_linux.cc
===================================================================
--- libsanitizer/tsan/tsan_platform_linux.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_platform_linux.cc	(working copy)
@@ -38,6 +38,8 @@
 #include <errno.h>
 #include <sched.h>
 #include <dlfcn.h>
+#define __need_res_state
+#include <resolv.h>
 
 extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
 
@@ -287,6 +289,19 @@
   return g_data_start && addr >= g_data_start && addr < g_data_end;
 }
 
+#ifndef TSAN_GO
+int ExtractResolvFDs(void *state, int *fds, int nfd) {
+  int cnt = 0;
+  __res_state *statp = (__res_state*)state;
+  for (int i = 0; i < MAXNS && cnt < nfd; i++) {
+    if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1)
+      fds[cnt++] = statp->_u._ext.nssocks[i];
+  }
+  return cnt;
+}
+#endif
+
+
 }  // namespace __tsan
 
 #endif  // #ifdef __linux__
Index: libsanitizer/tsan/tsan_interface_inl.h
===================================================================
--- libsanitizer/tsan/tsan_interface_inl.h	(revision 195997)
+++ libsanitizer/tsan/tsan_interface_inl.h	(working copy)
@@ -17,41 +17,41 @@
 using namespace __tsan;  // NOLINT
 
 void __tsan_read1(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 0, 0);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog1);
 }
 
 void __tsan_read2(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 1, 0);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog2);
 }
 
 void __tsan_read4(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, 0);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog4);
 }
 
 void __tsan_read8(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 3, 0);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
 }
 
 void __tsan_write1(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 0, 1);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog1);
 }
 
 void __tsan_write2(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 1, 1);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog2);
 }
 
 void __tsan_write4(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, 1);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog4);
 }
 
 void __tsan_write8(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 3, 1);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
 }
 
 void __tsan_vptr_update(void **vptr_p, void *new_val) {
   CHECK_EQ(sizeof(vptr_p), 8);
   if (*vptr_p != new_val)
-    MemoryAccess(cur_thread(), CALLERPC, (uptr)vptr_p, 3, 1);
+    MemoryWrite(cur_thread(), CALLERPC, (uptr)vptr_p, kSizeLog8);
 }
 
 void __tsan_func_entry(void *pc) {
Index: libsanitizer/tsan/tsan_stat.cc
===================================================================
--- libsanitizer/tsan/tsan_stat.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_stat.cc	(working copy)
@@ -179,6 +179,18 @@
   name[StatInt_sem_timedwait]            = "  sem_timedwait                   ";
   name[StatInt_sem_post]                 = "  sem_post                        ";
   name[StatInt_sem_getvalue]             = "  sem_getvalue                    ";
+  name[StatInt_stat]                     = "  stat                            ";
+  name[StatInt___xstat]                  = "  __xstat                         ";
+  name[StatInt_stat64]                   = "  stat64                          ";
+  name[StatInt___xstat64]                = "  __xstat64                       ";
+  name[StatInt_lstat]                    = "  lstat                           ";
+  name[StatInt___lxstat]                 = "  __lxstat                        ";
+  name[StatInt_lstat64]                  = "  lstat64                         ";
+  name[StatInt___lxstat64]               = "  __lxstat64                      ";
+  name[StatInt_fstat]                    = "  fstat                           ";
+  name[StatInt___fxstat]                 = "  __fxstat                        ";
+  name[StatInt_fstat64]                  = "  fstat64                         ";
+  name[StatInt___fxstat64]               = "  __fxstat64                      ";
   name[StatInt_open]                     = "  open                            ";
   name[StatInt_open64]                   = "  open64                          ";
   name[StatInt_creat]                    = "  creat                           ";
@@ -193,12 +205,15 @@
   name[StatInt_socket]                   = "  socket                          ";
   name[StatInt_socketpair]               = "  socketpair                      ";
   name[StatInt_connect]                  = "  connect                         ";
+  name[StatInt_bind]                     = "  bind                            ";
+  name[StatInt_listen]                   = "  listen                          ";
   name[StatInt_accept]                   = "  accept                          ";
   name[StatInt_accept4]                  = "  accept4                         ";
   name[StatInt_epoll_create]             = "  epoll_create                    ";
   name[StatInt_epoll_create1]            = "  epoll_create1                   ";
   name[StatInt_close]                    = "  close                           ";
   name[StatInt___close]                  = "  __close                         ";
+  name[StatInt___res_iclose]             = "  __res_iclose                    ";
   name[StatInt_pipe]                     = "  pipe                            ";
   name[StatInt_pipe2]                    = "  pipe2                           ";
   name[StatInt_read]                     = "  read                            ";
@@ -240,6 +255,14 @@
   name[StatInt_scanf]                    = "  scanf                           ";
   name[StatInt_sscanf]                   = "  sscanf                          ";
   name[StatInt_fscanf]                   = "  fscanf                          ";
+  name[StatInt___isoc99_vscanf]          = "  vscanf                          ";
+  name[StatInt___isoc99_vsscanf]         = "  vsscanf                         ";
+  name[StatInt___isoc99_vfscanf]         = "  vfscanf                         ";
+  name[StatInt___isoc99_scanf]           = "  scanf                           ";
+  name[StatInt___isoc99_sscanf]          = "  sscanf                          ";
+  name[StatInt___isoc99_fscanf]          = "  fscanf                          ";
+  name[StatInt_on_exit]                  = "  on_exit                         ";
+  name[StatInt___cxa_atexit]             = "  __cxa_atexit                    ";
 
   name[StatAnnotation]                   = "Dynamic annotations               ";
   name[StatAnnotateHappensBefore]        = "  HappensBefore                   ";
@@ -285,6 +308,7 @@
   name[StatMtxAnnotations]               = "  Annotations                     ";
   name[StatMtxMBlock]                    = "  MBlock                          ";
   name[StatMtxJavaMBlock]                = "  JavaMBlock                      ";
+  name[StatMtxFD]                        = "  FD                              ";
 
   Printf("Statistics:\n");
   for (int i = 0; i < StatCnt; i++)
Index: libsanitizer/tsan/tsan_symbolize.cc
===================================================================
--- libsanitizer/tsan/tsan_symbolize.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_symbolize.cc	(working copy)
@@ -16,9 +16,24 @@
 #include "sanitizer_common/sanitizer_symbolizer.h"
 #include "tsan_flags.h"
 #include "tsan_report.h"
+#include "tsan_rtl.h"
 
 namespace __tsan {
 
+struct ScopedInSymbolizer {
+  ScopedInSymbolizer() {
+    ThreadState *thr = cur_thread();
+    CHECK(!thr->in_symbolizer);
+    thr->in_symbolizer = true;
+  }
+
+  ~ScopedInSymbolizer() {
+    ThreadState *thr = cur_thread();
+    CHECK(thr->in_symbolizer);
+    thr->in_symbolizer = false;
+  }
+};
+
 ReportStack *NewReportStackEntry(uptr addr) {
   ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
                                                   sizeof(ReportStack));
@@ -53,35 +68,36 @@
 }
 
 ReportStack *SymbolizeCode(uptr addr) {
-  if (flags()->external_symbolizer_path[0]) {
-    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);
-    if (addr_frames_num == 0)
-      return NewReportStackEntry(addr);
-    ReportStack *top = 0;
-    ReportStack *bottom = 0;
-    for (uptr i = 0; i < addr_frames_num; i++) {
-      ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
-      CHECK(cur_entry);
-      addr_frames[i].Clear();
-      if (i == 0)
-        top = cur_entry;
-      else
-        bottom->next = cur_entry;
-      bottom = cur_entry;
-    }
-    return top;
+  if (!IsSymbolizerAvailable())
+    return SymbolizeCodeAddr2Line(addr);
+  ScopedInSymbolizer in_symbolizer;
+  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);
+  if (addr_frames_num == 0)
+    return NewReportStackEntry(addr);
+  ReportStack *top = 0;
+  ReportStack *bottom = 0;
+  for (uptr i = 0; i < addr_frames_num; i++) {
+    ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
+    CHECK(cur_entry);
+    addr_frames[i].Clear();
+    if (i == 0)
+      top = cur_entry;
+    else
+      bottom->next = cur_entry;
+    bottom = cur_entry;
   }
-  return SymbolizeCodeAddr2Line(addr);
+  return top;
 }
 
 ReportLocation *SymbolizeData(uptr addr) {
-  if (flags()->external_symbolizer_path[0] == 0)
+  if (!IsSymbolizerAvailable())
     return 0;
+  ScopedInSymbolizer in_symbolizer;
   DataInfo info;
   if (!__sanitizer::SymbolizeData(addr, &info))
     return 0;
Index: libsanitizer/tsan/tsan_stat.h
===================================================================
--- libsanitizer/tsan/tsan_stat.h	(revision 195997)
+++ libsanitizer/tsan/tsan_stat.h	(working copy)
@@ -174,6 +174,18 @@
   StatInt_sem_timedwait,
   StatInt_sem_post,
   StatInt_sem_getvalue,
+  StatInt_stat,
+  StatInt___xstat,
+  StatInt_stat64,
+  StatInt___xstat64,
+  StatInt_lstat,
+  StatInt___lxstat,
+  StatInt_lstat64,
+  StatInt___lxstat64,
+  StatInt_fstat,
+  StatInt___fxstat,
+  StatInt_fstat64,
+  StatInt___fxstat64,
   StatInt_open,
   StatInt_open64,
   StatInt_creat,
@@ -188,12 +200,15 @@
   StatInt_socket,
   StatInt_socketpair,
   StatInt_connect,
+  StatInt_bind,
+  StatInt_listen,
   StatInt_accept,
   StatInt_accept4,
   StatInt_epoll_create,
   StatInt_epoll_create1,
   StatInt_close,
   StatInt___close,
+  StatInt___res_iclose,
   StatInt_pipe,
   StatInt_pipe2,
   StatInt_read,
@@ -239,6 +254,14 @@
   StatInt_scanf,
   StatInt_sscanf,
   StatInt_fscanf,
+  StatInt___isoc99_vscanf,
+  StatInt___isoc99_vsscanf,
+  StatInt___isoc99_vfscanf,
+  StatInt___isoc99_scanf,
+  StatInt___isoc99_sscanf,
+  StatInt___isoc99_fscanf,
+  StatInt_on_exit,
+  StatInt___cxa_atexit,
 
   // Dynamic annotations.
   StatAnnotation,
@@ -287,6 +310,7 @@
   StatMtxAtExit,
   StatMtxMBlock,
   StatMtxJavaMBlock,
+  StatMtxFD,
 
   // This must be the last.
   StatCnt
Index: libsanitizer/tsan/tsan_rtl_mutex.cc
===================================================================
--- libsanitizer/tsan/tsan_rtl_mutex.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_rtl_mutex.cc	(working copy)
@@ -24,8 +24,12 @@
   CHECK_GT(thr->in_rtl, 0);
   DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
   StatInc(thr, StatMutexCreate);
-  if (!linker_init && IsAppMem(addr))
-    MemoryWrite1Byte(thr, pc, addr);
+  if (!linker_init && IsAppMem(addr)) {
+    CHECK(!thr->is_freeing);
+    thr->is_freeing = true;
+    MemoryWrite(thr, pc, addr, kSizeLog1);
+    thr->is_freeing = false;
+  }
   SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
   s->is_rw = rw;
   s->is_recursive = recursive;
@@ -47,8 +51,12 @@
   SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr);
   if (s == 0)
     return;
-  if (IsAppMem(addr))
-    MemoryWrite1Byte(thr, pc, addr);
+  if (IsAppMem(addr)) {
+    CHECK(!thr->is_freeing);
+    thr->is_freeing = true;
+    MemoryWrite(thr, pc, addr, kSizeLog1);
+    thr->is_freeing = false;
+  }
   if (flags()->report_destroy_locked
       && s->owner_tid != SyncVar::kInvalidTid
       && !s->is_broken) {
@@ -73,7 +81,7 @@
   CHECK_GT(thr->in_rtl, 0);
   DPrintf("#%d: MutexLock %zx\n", thr->tid, addr);
   if (IsAppMem(addr))
-    MemoryRead1Byte(thr, pc, addr);
+    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
@@ -106,7 +114,7 @@
   CHECK_GT(thr->in_rtl, 0);
   DPrintf("#%d: MutexUnlock %zx\n", thr->tid, addr);
   if (IsAppMem(addr))
-    MemoryRead1Byte(thr, pc, 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());
@@ -144,7 +152,7 @@
   DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
   StatInc(thr, StatMutexReadLock);
   if (IsAppMem(addr))
-    MemoryRead1Byte(thr, pc, addr);
+    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, false);
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
@@ -165,7 +173,7 @@
   DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
   StatInc(thr, StatMutexReadUnlock);
   if (IsAppMem(addr))
-    MemoryRead1Byte(thr, pc, addr);
+    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
@@ -186,7 +194,7 @@
   CHECK_GT(thr->in_rtl, 0);
   DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
   if (IsAppMem(addr))
-    MemoryRead1Byte(thr, pc, addr);
+    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
   bool write = true;
   if (s->owner_tid == SyncVar::kInvalidTid) {
Index: libsanitizer/tsan/tsan_md5.cc
===================================================================
--- libsanitizer/tsan/tsan_md5.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_md5.cc	(working copy)
@@ -240,4 +240,4 @@
   MD5_Final((unsigned char*)&res.hash[0], &ctx);
   return res;
 }
-}
+}  // namespace __tsan
Index: libsanitizer/tsan/tsan_platform.h
===================================================================
--- libsanitizer/tsan/tsan_platform.h	(revision 195997)
+++ libsanitizer/tsan/tsan_platform.h	(working copy)
@@ -149,6 +149,7 @@
 uptr GetTlsSize();
 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
 
Index: libsanitizer/tsan/tsan_update_shadow_word_inl.h
===================================================================
--- libsanitizer/tsan/tsan_update_shadow_word_inl.h	(revision 195997)
+++ libsanitizer/tsan/tsan_update_shadow_word_inl.h	(working copy)
@@ -32,7 +32,7 @@
     if (Shadow::TidsAreEqual(old, cur)) {
       StatInc(thr, StatShadowSameThread);
       if (OldIsInSameSynchEpoch(old, thr)) {
-        if (OldIsRWNotWeaker(old, kAccessIsWrite)) {
+        if (old.IsRWNotWeaker(kAccessIsWrite, kIsAtomic)) {
           // found a slot that holds effectively the same info
           // (that is, same tid, same sync epoch and same size)
           StatInc(thr, StatMopSame);
@@ -41,7 +41,7 @@
         StoreIfNotYetStored(sp, &store_word);
         break;
       }
-      if (OldIsRWWeakerOrEqual(old, kAccessIsWrite))
+      if (old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic))
         StoreIfNotYetStored(sp, &store_word);
       break;
     }
@@ -50,25 +50,23 @@
       StoreIfNotYetStored(sp, &store_word);
       break;
     }
-    if (BothReads(old, kAccessIsWrite))
+    if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))
       break;
     goto RACE;
   }
-
   // Do the memory access intersect?
-  if (Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
+  // In Go all memory accesses are 1 byte, so there can be no intersections.
+  if (kCppMode && Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
     StatInc(thr, StatShadowIntersect);
     if (Shadow::TidsAreEqual(old, cur)) {
       StatInc(thr, StatShadowSameThread);
       break;
     }
     StatInc(thr, StatShadowAnotherThread);
+    if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))
+      break;
     if (HappensBefore(old, thr))
       break;
-
-    if (BothReads(old, kAccessIsWrite))
-      break;
-
     goto RACE;
   }
   // The accesses do not intersect.
Index: libsanitizer/tsan/tsan_mman.cc
===================================================================
--- libsanitizer/tsan/tsan_mman.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_mman.cc	(working copy)
@@ -36,10 +36,18 @@
   allocator()->Init();
 }
 
-void AlloctorThreadFinish(ThreadState *thr) {
-  allocator()->SwallowCache(&thr->alloc_cache);
+void AllocatorThreadStart(ThreadState *thr) {
+  allocator()->InitCache(&thr->alloc_cache);
 }
 
+void AllocatorThreadFinish(ThreadState *thr) {
+  allocator()->DestroyCache(&thr->alloc_cache);
+}
+
+void AllocatorPrintStats() {
+  allocator()->PrintStats();
+}
+
 static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
   if (!thr->in_signal_handler || !flags()->report_signal_unsafe)
     return;
@@ -162,3 +170,49 @@
 }
 
 }  // namespace __tsan
+
+using namespace __tsan;
+
+extern "C" {
+uptr __tsan_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 __tsan_get_heap_size() {
+  u64 stats[AllocatorStatCount];
+  allocator()->GetStats(stats);
+  u64 m = stats[AllocatorStatMmapped];
+  u64 f = stats[AllocatorStatUnmapped];
+  return m >= f ? m - f : 1;
+}
+
+uptr __tsan_get_free_bytes() {
+  return 1;
+}
+
+uptr __tsan_get_unmapped_bytes() {
+  return 1;
+}
+
+uptr __tsan_get_estimated_allocated_size(uptr size) {
+  return size;
+}
+
+bool __tsan_get_ownership(void *p) {
+  return allocator()->GetBlockBegin(p) != 0;
+}
+
+uptr __tsan_get_allocated_size(void *p) {
+  if (p == 0)
+    return 0;
+  p = allocator()->GetBlockBegin(p);
+  if (p == 0)
+    return 0;
+  MBlock *b = (MBlock*)allocator()->GetMetaData(p);
+  return b->size;
+}
+}  // extern "C"
Index: libsanitizer/tsan/tsan_fd.cc
===================================================================
--- libsanitizer/tsan/tsan_fd.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_fd.cc	(working copy)
@@ -148,7 +148,7 @@
   FdDesc *d = fddesc(thr, pc, fd);
   FdSync *s = d->sync;
   DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, s);
-  MemoryRead8Byte(thr, pc, (uptr)d);
+  MemoryRead(thr, pc, (uptr)d, kSizeLog8);
   if (s)
     Acquire(thr, pc, (uptr)s);
 }
@@ -159,20 +159,20 @@
   DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, s);
   if (s)
     Release(thr, pc, (uptr)s);
-  MemoryRead8Byte(thr, pc, (uptr)d);
+  MemoryRead(thr, pc, (uptr)d, kSizeLog8);
 }
 
 void FdAccess(ThreadState *thr, uptr pc, int fd) {
   DPrintf("#%d: FdAccess(%d)\n", thr->tid, fd);
   FdDesc *d = fddesc(thr, pc, fd);
-  MemoryRead8Byte(thr, pc, (uptr)d);
+  MemoryRead(thr, pc, (uptr)d, kSizeLog8);
 }
 
 void FdClose(ThreadState *thr, uptr pc, int fd) {
   DPrintf("#%d: FdClose(%d)\n", thr->tid, fd);
   FdDesc *d = fddesc(thr, pc, fd);
   // To catch races between fd usage and close.
-  MemoryWrite8Byte(thr, pc, (uptr)d);
+  MemoryWrite(thr, pc, (uptr)d, kSizeLog8);
   // We need to clear it, because if we do not intercept any call out there
   // that creates fd, we will hit false postives.
   MemoryResetRange(thr, pc, (uptr)d, 8);
@@ -191,7 +191,7 @@
   DPrintf("#%d: FdDup(%d, %d)\n", thr->tid, oldfd, newfd);
   // Ignore the case when user dups not yet connected socket.
   FdDesc *od = fddesc(thr, pc, oldfd);
-  MemoryRead8Byte(thr, pc, (uptr)od);
+  MemoryRead(thr, pc, (uptr)od, kSizeLog8);
   FdClose(thr, pc, newfd);
   init(thr, pc, newfd, ref(od->sync));
 }
Index: libsanitizer/tsan/tsan_flags.cc
===================================================================
--- libsanitizer/tsan/tsan_flags.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_flags.cc	(working copy)
@@ -43,6 +43,7 @@
   f->report_thread_leaks = true;
   f->report_destroy_locked = true;
   f->report_signal_unsafe = true;
+  f->report_atomic_races = true;
   f->force_seq_cst_atomics = false;
   f->strip_path_prefix = "";
   f->suppressions = "";
@@ -70,6 +71,7 @@
   ParseFlag(env, &f->report_thread_leaks, "report_thread_leaks");
   ParseFlag(env, &f->report_destroy_locked, "report_destroy_locked");
   ParseFlag(env, &f->report_signal_unsafe, "report_signal_unsafe");
+  ParseFlag(env, &f->report_atomic_races, "report_atomic_races");
   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");
Index: libsanitizer/tsan/tsan_interface.cc
===================================================================
--- libsanitizer/tsan/tsan_interface.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_interface.cc	(working copy)
@@ -22,13 +22,13 @@
 }
 
 void __tsan_read16(void *addr) {
-  MemoryRead8Byte(cur_thread(), CALLERPC, (uptr)addr);
-  MemoryRead8Byte(cur_thread(), CALLERPC, (uptr)addr + 8);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
 }
 
 void __tsan_write16(void *addr) {
-  MemoryWrite8Byte(cur_thread(), CALLERPC, (uptr)addr);
-  MemoryWrite8Byte(cur_thread(), CALLERPC, (uptr)addr + 8);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
 }
 
 void __tsan_acquire(void *addr) {
Index: libsanitizer/tsan/tsan_interface_java.cc
===================================================================
--- libsanitizer/tsan/tsan_interface_java.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_interface_java.cc	(working copy)
@@ -150,7 +150,7 @@
   return 0;
 }
 
-}  // namespace __tsan {
+}  // namespace __tsan
 
 #define SCOPED_JAVA_FUNC(func) \
   ThreadState *thr = cur_thread(); \
Index: libsanitizer/tsan/tsan_rtl.cc
===================================================================
--- libsanitizer/tsan/tsan_rtl.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_rtl.cc	(working copy)
@@ -35,6 +35,11 @@
 #endif
 static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
 
+// Can be overriden by a front-end.
+bool CPP_WEAK OnFinalize(bool failed) {
+  return failed;
+}
+
 static Context *ctx;
 Context *CTX() {
   return ctx;
@@ -136,7 +141,7 @@
   InternalScopedBuffer<char> filename(4096);
   internal_snprintf(filename.data(), filename.size(), "%s.%d",
       flags()->profile_memory, GetPid());
-  fd_t fd = internal_open(filename.data(), true);
+  fd_t fd = OpenFile(filename.data(), true);
   if (fd == kInvalidFd) {
     Printf("Failed to open memory profile file '%s'\n", &filename[0]);
     Die();
@@ -180,6 +185,7 @@
   if (is_initialized)
     return;
   is_initialized = true;
+  SanitizerToolName = "ThreadSanitizer";
   // Install tool-specific callbacks in sanitizer_common.
   SetCheckFailedCallback(TsanCheckFailed);
 
@@ -237,7 +243,7 @@
     Printf("ThreadSanitizer is suspended at startup (pid %d)."
            " Call __tsan_resume().\n",
            GetPid());
-    while (__tsan_resumed == 0);
+    while (__tsan_resumed == 0) {}
   }
 }
 
@@ -253,6 +259,11 @@
   ctx->report_mtx.Lock();
   ctx->report_mtx.Unlock();
 
+#ifndef TSAN_GO
+  if (ctx->flags.verbosity)
+    AllocatorPrintStats();
+#endif
+
   ThreadFinalize(thr);
 
   if (ctx->nreported) {
@@ -270,6 +281,8 @@
         ctx->nmissed_expected);
   }
 
+  failed = OnFinalize(failed);
+
   StatAggregate(ctx->stat, thr->stat);
   StatOutput(ctx->stat);
   return failed ? flags()->exitcode : 0;
@@ -356,18 +369,6 @@
 #endif
 }
 
-static inline bool BothReads(Shadow s, int kAccessIsWrite) {
-  return !kAccessIsWrite && !s.is_write();
-}
-
-static inline bool OldIsRWNotWeaker(Shadow old, int kAccessIsWrite) {
-  return old.is_write() || !kAccessIsWrite;
-}
-
-static inline bool OldIsRWWeakerOrEqual(Shadow old, int kAccessIsWrite) {
-  return !old.is_write() || kAccessIsWrite;
-}
-
 static inline bool OldIsInSameSynchEpoch(Shadow old, ThreadState *thr) {
   return old.epoch() >= thr->fast_synch_epoch;
 }
@@ -378,7 +379,7 @@
 
 ALWAYS_INLINE
 void MemoryAccessImpl(ThreadState *thr, uptr addr,
-    int kAccessSizeLog, bool kAccessIsWrite,
+    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
     u64 *shadow_mem, Shadow cur) {
   StatInc(thr, StatMop);
   StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
@@ -452,7 +453,7 @@
 
 ALWAYS_INLINE
 void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
-    int kAccessSizeLog, bool kAccessIsWrite) {
+    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) {
   u64 *shadow_mem = (u64*)MemToShadow(addr);
   DPrintf2("#%d: MemoryAccess: @%p %p size=%d"
       " is_write=%d shadow_mem=%p {%zx, %zx, %zx, %zx}\n",
@@ -479,12 +480,13 @@
   Shadow cur(fast_state);
   cur.SetAddr0AndSizeLog(addr & 7, kAccessSizeLog);
   cur.SetWrite(kAccessIsWrite);
+  cur.SetAtomic(kIsAtomic);
 
   // We must not store to the trace if we do not store to the shadow.
   // That is, this call must be moved somewhere below.
   TraceAddEvent(thr, fast_state, EventTypeMop, pc);
 
-  MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite,
+  MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic,
       shadow_mem, cur);
 }
 
@@ -531,7 +533,10 @@
 }
 
 void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) {
+  CHECK_EQ(thr->is_freeing, false);
+  thr->is_freeing = true;
   MemoryAccessRange(thr, pc, addr, size, true);
+  thr->is_freeing = false;
   Shadow s(thr->fast_state);
   s.ClearIgnoreBit();
   s.MarkAsFreed();
Index: libsanitizer/tsan/tsan_rtl.h
===================================================================
--- libsanitizer/tsan/tsan_rtl.h	(revision 195997)
+++ libsanitizer/tsan/tsan_rtl.h	(working copy)
@@ -171,7 +171,8 @@
 //   freed           : 1
 //   tid             : kTidBits
 //   epoch           : kClkBits
-//   is_write        : 1
+//   is_atomic       : 1
+//   is_read         : 1
 //   size_log        : 2
 //   addr0           : 3
 class Shadow : public FastState {
@@ -195,14 +196,27 @@
   }
 
   void SetWrite(unsigned kAccessIsWrite) {
-    DCHECK_EQ(x_ & 32, 0);
-    if (kAccessIsWrite)
-      x_ |= 32;
-    DCHECK_EQ(kAccessIsWrite, is_write());
+    DCHECK_EQ(x_ & kReadBit, 0);
+    if (!kAccessIsWrite)
+      x_ |= kReadBit;
+    DCHECK_EQ(kAccessIsWrite, IsWrite());
   }
 
-  bool IsZero() const { return x_ == 0; }
+  void SetAtomic(bool kIsAtomic) {
+    DCHECK(!IsAtomic());
+    if (kIsAtomic)
+      x_ |= kAtomicBit;
+    DCHECK_EQ(IsAtomic(), kIsAtomic);
+  }
 
+  bool IsAtomic() const {
+    return x_ & kAtomicBit;
+  }
+
+  bool IsZero() const {
+    return x_ == 0;
+  }
+
   static inline bool TidsAreEqual(const Shadow s1, const Shadow s2) {
     u64 shifted_xor = (s1.x_ ^ s2.x_) >> kTidShift;
     DCHECK_EQ(shifted_xor == 0, s1.TidWithIgnore() == s2.TidWithIgnore());
@@ -248,7 +262,8 @@
   }
   u64 addr0() const { return x_ & 7; }
   u64 size() const { return 1ull << size_log(); }
-  bool is_write() const { return x_ & 32; }
+  bool IsWrite() const { return !IsRead(); }
+  bool IsRead() const { return x_ & kReadBit; }
 
   // The idea behind the freed bit is as follows.
   // When the memory is freed (or otherwise unaccessible) we write to the shadow
@@ -263,13 +278,46 @@
      x_ |= kFreedBit;
   }
 
+  bool IsFreed() const {
+    return x_ & kFreedBit;
+  }
+
   bool GetFreedAndReset() {
     bool res = x_ & kFreedBit;
     x_ &= ~kFreedBit;
     return res;
   }
 
+  bool IsBothReadsOrAtomic(bool kIsWrite, bool kIsAtomic) const {
+    // analyzes 5-th bit (is_read) and 6-th bit (is_atomic)
+    bool v = x_ & u64(((kIsWrite ^ 1) << kReadShift)
+        | (kIsAtomic << kAtomicShift));
+    DCHECK_EQ(v, (!IsWrite() && !kIsWrite) || (IsAtomic() && kIsAtomic));
+    return v;
+  }
+
+  bool IsRWNotWeaker(bool kIsWrite, bool kIsAtomic) const {
+    bool v = ((x_ >> kReadShift) & 3)
+        <= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
+    DCHECK_EQ(v, (IsAtomic() < kIsAtomic) ||
+        (IsAtomic() == kIsAtomic && !IsWrite() <= !kIsWrite));
+    return v;
+  }
+
+  bool IsRWWeakerOrEqual(bool kIsWrite, bool kIsAtomic) const {
+    bool v = ((x_ >> kReadShift) & 3)
+        >= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
+    DCHECK_EQ(v, (IsAtomic() > kIsAtomic) ||
+        (IsAtomic() == kIsAtomic && !IsWrite() >= !kIsWrite));
+    return v;
+  }
+
  private:
+  static const u64 kReadShift   = 5;
+  static const u64 kReadBit     = 1ull << kReadShift;
+  static const u64 kAtomicShift = 6;
+  static const u64 kAtomicBit   = 1ull << kAtomicShift;
+
   u64 size_log() const { return (x_ >> 3) & 3; }
 
   static bool TwoRangesIntersectSLOW(const Shadow s1, const Shadow s2) {
@@ -324,7 +372,9 @@
   const int tid;
   const int unique_id;
   int in_rtl;
+  bool in_symbolizer;
   bool is_alive;
+  bool is_freeing;
   const uptr stk_addr;
   const uptr stk_size;
   const uptr tls_addr;
@@ -501,11 +551,14 @@
 void ReportRace(ThreadState *thr);
 bool OutputReport(Context *ctx,
                   const ScopedReport &srep,
-                  const ReportStack *suppress_stack = 0);
+                  const ReportStack *suppress_stack1 = 0,
+                  const ReportStack *suppress_stack2 = 0);
 bool IsFiredSuppression(Context *ctx,
                         const ScopedReport &srep,
                         const StackTrace &trace);
 bool IsExpectedReport(uptr addr, uptr size);
+bool FrameIsInternal(const ReportStack *frame);
+ReportStack *SkipTsanInternalFrames(ReportStack *ent);
 
 #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
 # define DPrintf Printf
@@ -521,6 +574,7 @@
 
 u32 CurrentStackId(ThreadState *thr, uptr pc);
 void PrintCurrentStack(ThreadState *thr, uptr pc);
+void PrintCurrentStackSlow();  // uses libunwind
 
 void Initialize(ThreadState *thr);
 int Finalize(ThreadState *thr);
@@ -530,16 +584,38 @@
 SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr);
 
 void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
-    int kAccessSizeLog, bool kAccessIsWrite);
+    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic);
 void MemoryAccessImpl(ThreadState *thr, uptr addr,
-    int kAccessSizeLog, bool kAccessIsWrite,
+    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
     u64 *shadow_mem, Shadow cur);
-void MemoryRead1Byte(ThreadState *thr, uptr pc, uptr addr);
-void MemoryWrite1Byte(ThreadState *thr, uptr pc, uptr addr);
-void MemoryRead8Byte(ThreadState *thr, uptr pc, uptr addr);
-void MemoryWrite8Byte(ThreadState *thr, uptr pc, uptr addr);
 void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
-                       uptr size, bool is_write);
+    uptr size, bool is_write);
+
+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,
+                                     uptr addr, int kAccessSizeLog) {
+  MemoryAccess(thr, pc, addr, kAccessSizeLog, false, false);
+}
+
+void ALWAYS_INLINE 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,
+                                           uptr addr, int kAccessSizeLog) {
+  MemoryAccess(thr, pc, addr, kAccessSizeLog, false, true);
+}
+
+void ALWAYS_INLINE INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
+                                            uptr addr, int kAccessSizeLog) {
+  MemoryAccess(thr, pc, addr, kAccessSizeLog, true, true);
+}
+
 void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size);
 void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size);
 void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size);
Index: libsanitizer/tsan/tsan_vector.h
===================================================================
--- libsanitizer/tsan/tsan_vector.h	(revision 195997)
+++ libsanitizer/tsan/tsan_vector.h	(working copy)
@@ -103,6 +103,6 @@
   Vector(const Vector&);
   void operator=(const Vector&);
 };
-}
+}  // namespace __tsan
 
 #endif  // #ifndef TSAN_VECTOR_H
Index: libsanitizer/tsan/tsan_report.cc
===================================================================
--- libsanitizer/tsan/tsan_report.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_report.cc	(working copy)
@@ -41,23 +41,20 @@
   return buf;
 }
 
-static void PrintHeader(ReportType typ) {
-  Printf("WARNING: ThreadSanitizer: ");
-
+static const char *ReportTypeString(ReportType typ) {
   if (typ == ReportTypeRace)
-    Printf("data race");
-  else if (typ == ReportTypeUseAfterFree)
-    Printf("heap-use-after-free");
-  else if (typ == ReportTypeThreadLeak)
-    Printf("thread leak");
-  else if (typ == ReportTypeMutexDestroyLocked)
-    Printf("destroy of a locked mutex");
-  else if (typ == ReportTypeSignalUnsafe)
-    Printf("signal-unsafe call inside of a signal");
-  else if (typ == ReportTypeErrnoInSignal)
-    Printf("signal handler spoils errno");
-
-  Printf(" (pid=%d)\n", GetPid());
+    return "data race";
+  if (typ == ReportTypeUseAfterFree)
+    return "heap-use-after-free";
+  if (typ == ReportTypeThreadLeak)
+    return "thread leak";
+  if (typ == ReportTypeMutexDestroyLocked)
+    return "destroy of a locked mutex";
+  if (typ == ReportTypeSignalUnsafe)
+    return "signal-unsafe call inside of a signal";
+  if (typ == ReportTypeErrnoInSignal)
+    return "signal handler spoils errno";
+  return "";
 }
 
 void PrintStack(const ReportStack *ent) {
@@ -87,11 +84,17 @@
   }
 }
 
+static const char *MopDesc(bool first, bool write, bool atomic) {
+  return atomic ? (first ? (write ? "Atomic write" : "Atomic read")
+                : (write ? "Previous atomic write" : "Previous atomic read"))
+                : (first ? (write ? "Write" : "Read")
+                : (write ? "Previous write" : "Previous read"));
+}
+
 static void PrintMop(const ReportMop *mop, bool first) {
   char thrbuf[kThreadBufSize];
   Printf("  %s of size %d at %p by %s",
-      (first ? (mop->write ? "Write" : "Read")
-             : (mop->write ? "Previous write" : "Previous read")),
+      MopDesc(first, mop->write, mop->atomic),
       mop->size, (void*)mop->addr,
       thread_name(thrbuf, mop->tid));
   PrintMutexSet(mop->mset);
@@ -150,9 +153,28 @@
   PrintStack(s);
 }
 
+static ReportStack *ChooseSummaryStack(const ReportDesc *rep) {
+  if (rep->mops.Size())
+    return rep->mops[0]->stack;
+  if (rep->stacks.Size())
+    return rep->stacks[0];
+  if (rep->mutexes.Size())
+    return rep->mutexes[0]->stack;
+  if (rep->threads.Size())
+    return rep->threads[0]->stack;
+  return 0;
+}
+
+ReportStack *SkipTsanInternalFrames(ReportStack *ent) {
+  while (FrameIsInternal(ent) && ent->next)
+    ent = ent->next;
+  return ent;
+}
+
 void PrintReport(const ReportDesc *rep) {
   Printf("==================\n");
-  PrintHeader(rep->typ);
+  const char *rep_typ_str = ReportTypeString(rep->typ);
+  Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, GetPid());
 
   for (uptr i = 0; i < rep->stacks.Size(); i++) {
     if (i)
@@ -175,6 +197,9 @@
   for (uptr i = 0; i < rep->threads.Size(); i++)
     PrintThread(rep->threads[i]);
 
+  if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep)))
+    ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
+
   Printf("==================\n");
 }
 
Index: libsanitizer/tsan/tsan_suppressions.cc
===================================================================
--- libsanitizer/tsan/tsan_suppressions.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_suppressions.cc	(working copy)
@@ -17,6 +17,13 @@
 #include "tsan_mman.h"
 #include "tsan_platform.h"
 
+// Can be overriden in frontend.
+#ifndef TSAN_GO
+extern "C" const char *WEAK __tsan_default_suppressions() {
+  return 0;
+}
+#endif
+
 namespace __tsan {
 
 static Suppression *g_suppressions;
@@ -29,7 +36,7 @@
     internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
   else
     internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
-  fd_t fd = internal_open(tmp.data(), false);
+  fd_t fd = OpenFile(tmp.data(), false);
   if (fd == kInvalidFd) {
     Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
                tmp.data());
@@ -78,8 +85,7 @@
   return true;
 }
 
-Suppression *SuppressionParse(const char* supp) {
-  Suppression *head = 0;
+Suppression *SuppressionParse(Suppression *head, const char* supp) {
   const char *line = supp;
   while (line) {
     while (line[0] == ' ' || line[0] == '\t')
@@ -128,8 +134,12 @@
 }
 
 void InitializeSuppressions() {
-  char *supp = ReadFile(flags()->suppressions);
-  g_suppressions = SuppressionParse(supp);
+  const char *supp = ReadFile(flags()->suppressions);
+  g_suppressions = SuppressionParse(0, supp);
+#ifndef TSAN_GO
+  supp = __tsan_default_suppressions();
+  g_suppressions = SuppressionParse(0, supp);
+#endif
 }
 
 uptr IsSuppressed(ReportType typ, const ReportStack *stack) {
@@ -150,7 +160,8 @@
     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->file) ||
+           SuppressionMatch(supp->templ, frame->module))) {
         DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
         return frame->pc;
       }
Index: libsanitizer/tsan/tsan_report.h
===================================================================
--- libsanitizer/tsan/tsan_report.h	(revision 195997)
+++ libsanitizer/tsan/tsan_report.h	(working copy)
@@ -46,6 +46,7 @@
   uptr addr;
   int size;
   bool write;
+  bool atomic;
   Vector<ReportMopMutex> mset;
   ReportStack *stack;
 
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 195997)
+++ gcc/config/i386/i386.c	(working copy)
@@ -5436,7 +5436,9 @@
 static unsigned HOST_WIDE_INT
 ix86_asan_shadow_offset (void)
 {
-  return (unsigned HOST_WIDE_INT) 1 << (TARGET_LP64 ? 44 : 29);
+  return TARGET_LP64 ? (TARGET_MACHO ? (HOST_WIDE_INT_1 << 44)
+                     : HOST_WIDE_INT_C (0x7fff8000))
+             : (HOST_WIDE_INT_1 << 29);
 }
 \f
 /* Argument support functions.  */
Index: gcc/sanitizer.def
===================================================================
--- gcc/sanitizer.def	(revision 195997)
+++ gcc/sanitizer.def	(working copy)
@@ -27,7 +27,7 @@
    for other FEs by asan.c.  */
 
 /* Address Sanitizer */
-DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init",
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init_v1",
 		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 /* Do not reorder the BUILT_IN_ASAN_REPORT* builtins, e.g. cfgcleanup.c
    relies on this order.  */
Index: gcc/ChangeLog
===================================================================
--- gcc/ChangeLog	(revision 195997)
+++ gcc/ChangeLog	(working copy)
@@ -1,3 +1,12 @@
+2013-02-13  Kostya Serebryany  <kcc@google.com>
+
+	* config/i386/i386.c: use 0x7fff8000 as asan_shadow_offset on x86_64
+	linux.
+	* sanitizer.def: rename __asan_init to __asan_init_v1.
+	* testsuite/c-c++-common/asan/strncpy-overflow-1.c: update the test
+	to match the fresh asan run-time.
+	* testsuite/c-c++-common/asan/rlimit-mmap-test-1.c: Ditto.
+
 2013-02-12  Vladimir Makarov  <vmakarov@redhat.com>
 
 	PR inline-asm/56148
Index: gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(revision 195997)
+++ gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(working copy)
@@ -12,7 +12,7 @@
   return short_buffer[8];
 }
 
-/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "WRITE of size \[0-9\]* at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*strncpy-overflow-1.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c	(revision 195997)
+++ gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c	(working copy)
@@ -18,4 +18,4 @@
   return 0;
 }
 
-/* { dg-output "AddressSanitizer is unable to mmap" } */
+/* { dg-output "ERROR: Failed to mmap" } */

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13  9:20 libsanitizer merge from upstream r175042 Konstantin Serebryany
@ 2013-02-13  9:51 ` Jakub Jelinek
  2013-02-13 10:28   ` Konstantin Serebryany
  2013-02-13 18:29 ` H.J. Lu
  1 sibling, 1 reply; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-13  9:51 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 01:19:47PM +0400, Konstantin Serebryany wrote:
> The attached patch is the libsanitizer merge from upstream r175042.
> 
> Lots of changes. Among other things:
>  - x86_64 linux: change the shadow offset to 0x7fff8000 (~5% speedup)
>  - the new asan allocator is enabled on Mac (was enabled on Linux before).
>  - tsan finds races between atomic and plain accesses
>  - better scanf interceptor, enabled by default
>  - don't include linux/futex.h (fixes PR56128)
>  - simple tests seem to work (again?) on PowerPC64 with 44-bit address
> space (46 AS not tested)
> 
> Patch for libsanitizer is automatically generated by libsanitizer/merge.sh
> Tested with
> rm -rf */{*/,}libsanitizer \
>   && make -j 50 \
>   && make -C gcc check-g{cc,++}
> RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} asan.exp'
> 
> Our internal LLVM bots (Linux, Mac and Android) are green.
> 
> Ok to commit?

--- libsanitizer/asan/asan_mapping.h	(revision 195997)
+++ libsanitizer/asan/asan_mapping.h	(working copy)
@@ -34,27 +34,16 @@
 #   if defined(__powerpc64__)
 #    define SHADOW_OFFSET (1ULL << 41)
 #   else
-#    define SHADOW_OFFSET (1ULL << 44)
+#    define SHADOW_OFFSET 0x7fff8000ULL
 #   endif
 #  endif
 # endif
 #endif  // ASAN_FLEXIBLE_MAPPING_AND_OFFSET

This is inconsistent with the i386.c change.  You said the 0x7fff8000ULL
shadow offset doesn't work on Darwin, so either the above should be

+#    if ASAN_MAC
+#     define SHADOW_OFFSET (1ULL << 44)
+#    else
+#     define SHADOW_OFFSET 0x7fff8000ULL
+#    endif

or i386.c should use 0x7fff8000 even for TARGET_MACHO && TARGET_LP64.

--- gcc/config/i386/i386.c	(revision 195997)
+++ gcc/config/i386/i386.c	(working copy)
@@ -5436,7 +5436,9 @@
 static unsigned HOST_WIDE_INT
 ix86_asan_shadow_offset (void)
 {
-  return (unsigned HOST_WIDE_INT) 1 << (TARGET_LP64 ? 44 : 29);
+  return TARGET_LP64 ? (TARGET_MACHO ? (HOST_WIDE_INT_1 << 44)
+                     : HOST_WIDE_INT_C (0x7fff8000))
+             : (HOST_WIDE_INT_1 << 29);

Please use tabs instead of 8 spaces, and indent it properly (second line
: below the second ?, third line : below first ?).

+2013-02-13  Kostya Serebryany  <kcc@google.com>
+
+	* config/i386/i386.c: use 0x7fff8000 as asan_shadow_offset on x86_64
+	linux.

Start sentence, so "Use" instead of "use".

+	* sanitizer.def: rename __asan_init to __asan_init_v1.

Likewise, "Rename".

+	* testsuite/c-c++-common/asan/strncpy-overflow-1.c: update the test
+	to match the fresh asan run-time.

"Update".  Also, these two go into gcc/testsuite/ChangeLog, without
testsuite/ prefix in the pathnames.

+	* testsuite/c-c++-common/asan/rlimit-mmap-test-1.c: Ditto.
+

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13  9:51 ` Jakub Jelinek
@ 2013-02-13 10:28   ` Konstantin Serebryany
  2013-02-13 10:32     ` Jakub Jelinek
  0 siblings, 1 reply; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-13 10:28 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

[-- Attachment #1: Type: text/plain, Size: 3074 bytes --]

On Wed, Feb 13, 2013 at 1:51 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Feb 13, 2013 at 01:19:47PM +0400, Konstantin Serebryany wrote:
>> The attached patch is the libsanitizer merge from upstream r175042.
>>
>> Lots of changes. Among other things:
>>  - x86_64 linux: change the shadow offset to 0x7fff8000 (~5% speedup)
>>  - the new asan allocator is enabled on Mac (was enabled on Linux before).
>>  - tsan finds races between atomic and plain accesses
>>  - better scanf interceptor, enabled by default
>>  - don't include linux/futex.h (fixes PR56128)
>>  - simple tests seem to work (again?) on PowerPC64 with 44-bit address
>> space (46 AS not tested)
>>
>> Patch for libsanitizer is automatically generated by libsanitizer/merge.sh
>> Tested with
>> rm -rf */{*/,}libsanitizer \
>>   && make -j 50 \
>>   && make -C gcc check-g{cc,++}
>> RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} asan.exp'
>>
>> Our internal LLVM bots (Linux, Mac and Android) are green.
>>
>> Ok to commit?
>
> --- libsanitizer/asan/asan_mapping.h    (revision 195997)
> +++ libsanitizer/asan/asan_mapping.h    (working copy)
> @@ -34,27 +34,16 @@
>  #   if defined(__powerpc64__)
>  #    define SHADOW_OFFSET (1ULL << 41)
>  #   else
> -#    define SHADOW_OFFSET (1ULL << 44)
> +#    define SHADOW_OFFSET 0x7fff8000ULL
>  #   endif
>  #  endif
>  # endif
>  #endif  // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
>
> This is inconsistent with the i386.c change.  You said the 0x7fff8000ULL
> shadow offset doesn't work on Darwin, so either the above should be
>
> +#    if ASAN_MAC
> +#     define SHADOW_OFFSET (1ULL << 44)
> +#    else
> +#     define SHADOW_OFFSET 0x7fff8000ULL
> +#    endif

Right. In LLVM we test only with ASAN_FLEXIBLE_MAPPING_AND_OFFSET==1,
so this came unnoticed.
Fixed in r175049.

>
> or i386.c should use 0x7fff8000 even for TARGET_MACHO && TARGET_LP64.
>
> --- gcc/config/i386/i386.c      (revision 195997)
> +++ gcc/config/i386/i386.c      (working copy)
> @@ -5436,7 +5436,9 @@
>  static unsigned HOST_WIDE_INT
>  ix86_asan_shadow_offset (void)
>  {
> -  return (unsigned HOST_WIDE_INT) 1 << (TARGET_LP64 ? 44 : 29);
> +  return TARGET_LP64 ? (TARGET_MACHO ? (HOST_WIDE_INT_1 << 44)
> +                     : HOST_WIDE_INT_C (0x7fff8000))
> +             : (HOST_WIDE_INT_1 << 29);
>
> Please use tabs instead of 8 spaces, and indent it properly (second line
> : below the second ?, third line : below first ?).
>
> +2013-02-13  Kostya Serebryany  <kcc@google.com>
> +
> +       * config/i386/i386.c: use 0x7fff8000 as asan_shadow_offset on x86_64
> +       linux.
>
> Start sentence, so "Use" instead of "use".

done

>
> +       * sanitizer.def: rename __asan_init to __asan_init_v1.
>
> Likewise, "Rename".

done

>
> +       * testsuite/c-c++-common/asan/strncpy-overflow-1.c: update the test
> +       to match the fresh asan run-time.
>
> "Update".  Also, these two go into gcc/testsuite/ChangeLog, without
> testsuite/ prefix in the pathnames.

done.

--kcc
>
> +       * testsuite/c-c++-common/asan/rlimit-mmap-test-1.c: Ditto.
> +
>
>         Jakub

[-- Attachment #2: libsanitizer-r175049.patch --]
[-- Type: application/octet-stream, Size: 219723 bytes --]

Index: libsanitizer/ChangeLog
===================================================================
--- libsanitizer/ChangeLog	(revision 195997)
+++ libsanitizer/ChangeLog	(working copy)
@@ -1,3 +1,10 @@
+2013-02-13  Kostya Serebryany  <kcc@google.com>
+
+        PR sanitizer/56128
+	* All source files: Merge from upstream r175049.
+	* interception/Makefile.am: added include path.
+	* interception/Makefile.in: Regenerated.
+
 2013-02-11  Jack Howarth  <howarth@bromo.med.uc.edu>
 
 	* configure.tgt: Disable build on darwin9 and earlier.
Index: libsanitizer/MERGE
===================================================================
--- libsanitizer/MERGE	(revision 195997)
+++ libsanitizer/MERGE	(working copy)
@@ -1,4 +1,4 @@
-173241
+175049
 
 The first line of this file holds the svn revision number of the
 last merge done from the master library sources.
Index: libsanitizer/interception/Makefile.am
===================================================================
--- libsanitizer/interception/Makefile.am	(revision 195997)
+++ libsanitizer/interception/Makefile.am	(working copy)
@@ -1,4 +1,4 @@
-AM_CPPFLAGS = -I $(top_srcdir)/include 
+AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
  
 # May be used by toolexeclibdir.
 gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
@@ -13,7 +13,8 @@
 interception_files = \
         interception_linux.cc \
         interception_mac.cc \
-        interception_win.cc
+        interception_win.cc \
+	interception_type_test.cc
 
 libinterception_la_SOURCES = $(interception_files)
 
Index: libsanitizer/interception/interception.h
===================================================================
--- libsanitizer/interception/interception.h	(revision 195997)
+++ libsanitizer/interception/interception.h	(working copy)
@@ -17,7 +17,7 @@
 # error "Interception doesn't work on this operating system."
 #endif
 
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
 
 // These typedefs should be used only in the interceptor definitions to replace
 // the standard system types (e.g. SSIZE_T instead of ssize_t)
@@ -25,21 +25,17 @@
 typedef __sanitizer::sptr SSIZE_T;
 typedef __sanitizer::sptr PTRDIFF_T;
 typedef __sanitizer::s64  INTMAX_T;
-typedef __sanitizer::u64  OFF_T;
+// WARNING: OFF_T may be different from OS type off_t, depending on the value of
+// _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 is special.
+#ifdef __APPLE__
+typedef __sanitizer::u64 OFF_T;
+#else
+typedef __sanitizer::uptr OFF_T;
+#endif
 typedef __sanitizer::u64  OFF64_T;
 
-// How to use this library:
-//      1) Include this header to define your own interceptors
-//         (see details below).
-//      2) Build all *.cc files and link against them.
-// On Mac you will also need to:
-//      3) Provide your own implementation for the following functions:
-//           mach_error_t __interception::allocate_island(void **ptr,
-//                                                      size_t size,
-//                                                      void *hint);
-//           mach_error_t __interception::deallocate_island(void *ptr);
-//         See "interception_mac.h" for more details.
-
 // How to add an interceptor:
 // Suppose you need to wrap/replace system function (generally, from libc):
 //      int foo(const char *bar, double baz);
@@ -80,21 +76,13 @@
 // This is not so on Mac OS, where the two-level namespace makes
 // our replacement functions invisible to other libraries. This may be overcomed
 // using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
-// libraries in Chromium were noticed when doing so. Instead we use
-// mach_override, a handy framework for patching functions at runtime.
-// To avoid possible name clashes, our replacement functions have
-// the "wrap_" prefix on Mac.
-// An alternative to function patching is to create a dylib containing a
-// __DATA,__interpose section that associates library functions with their
-// wrappers. When this dylib is preloaded before an executable using
-// DYLD_INSERT_LIBRARIES, it routes all the calls to interposed functions done
-// through stubs to the wrapper functions. Such a library is built with
-// -DMAC_INTERPOSE_FUNCTIONS=1.
+// libraries in Chromium were noticed when doing so.
+// Instead we create a dylib containing a __DATA,__interpose section that
+// associates library functions with their wrappers. When this dylib is
+// preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all
+// the calls to interposed functions done through stubs to the wrapper
+// functions.
 
-#if !defined(MAC_INTERPOSE_FUNCTIONS) || !defined(__APPLE__)
-# define MAC_INTERPOSE_FUNCTIONS 0
-#endif
-
 #if defined(__APPLE__)
 # define WRAP(x) wrap_##x
 # define WRAPPER_NAME(x) "wrap_"#x
@@ -120,7 +108,7 @@
     __attribute__((weak, alias("__interceptor_" #func), visibility("default")));
 #endif
 
-#if !MAC_INTERPOSE_FUNCTIONS
+#if !defined(__APPLE__)
 # define PTR_TO_REAL(x) real_##x
 # define REAL(x) __interception::PTR_TO_REAL(x)
 # define FUNC_TYPE(x) x##_f
@@ -130,11 +118,11 @@
     namespace __interception { \
       extern FUNC_TYPE(func) PTR_TO_REAL(func); \
     }
-#else  // MAC_INTERPOSE_FUNCTIONS
+#else  // __APPLE__
 # define REAL(x) x
 # define DECLARE_REAL(ret_type, func, ...) \
     extern "C" ret_type func(__VA_ARGS__);
-#endif  // MAC_INTERPOSE_FUNCTIONS
+#endif  // __APPLE__
 
 #define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
   DECLARE_REAL(ret_type, func, __VA_ARGS__) \
@@ -144,7 +132,7 @@
 // macros does its job. In exceptional cases you may need to call REAL(foo)
 // without defining INTERCEPTOR(..., foo, ...). For example, if you override
 // foo with an interceptor for other function.
-#if !MAC_INTERPOSE_FUNCTIONS
+#if !defined(__APPLE__)
 # define DEFINE_REAL(ret_type, func, ...) \
     typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
     namespace __interception { \
Index: libsanitizer/interception/interception_mac.h
===================================================================
--- libsanitizer/interception/interception_mac.h	(revision 195997)
+++ libsanitizer/interception/interception_mac.h	(working copy)
@@ -19,29 +19,7 @@
 #ifndef INTERCEPTION_MAC_H
 #define INTERCEPTION_MAC_H
 
-#include <mach/mach_error.h>
-#include <stddef.h>
+#define INTERCEPT_FUNCTION_MAC(func)
 
-// Allocate memory for the escape island. This cannot be moved to
-// mach_override, because each user of interceptors may specify its
-// own memory range for escape islands.
-extern "C" {
-mach_error_t __interception_allocate_island(void **ptr, size_t unused_size,
-                                            void *unused_hint);
-mach_error_t __interception_deallocate_island(void *ptr);
-}  // extern "C"
-
-namespace __interception {
-// returns true if the old function existed.
-bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func);
-}  // namespace __interception
-
-# define OVERRIDE_FUNCTION_MAC(old_func, new_func) \
-    ::__interception::OverrideFunction( \
-          (::__interception::uptr)old_func, \
-          (::__interception::uptr)new_func, \
-          (::__interception::uptr*)((::__interception::uptr)&REAL(old_func)))
-# define INTERCEPT_FUNCTION_MAC(func) OVERRIDE_FUNCTION_MAC(func, WRAP(func))
-
 #endif  // INTERCEPTION_MAC_H
 #endif  // __APPLE__
Index: libsanitizer/interception/Makefile.in
===================================================================
--- libsanitizer/interception/Makefile.in	(revision 195997)
+++ libsanitizer/interception/Makefile.in	(working copy)
@@ -56,7 +56,7 @@
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 libinterception_la_LIBADD =
 am__objects_1 = interception_linux.lo interception_mac.lo \
-	interception_win.lo
+	interception_win.lo interception_type_test.lo
 am_libinterception_la_OBJECTS = $(am__objects_1)
 libinterception_la_OBJECTS = $(am_libinterception_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@
@@ -208,7 +208,7 @@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-AM_CPPFLAGS = -I $(top_srcdir)/include 
+AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
 
 # May be used by toolexeclibdir.
 gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
@@ -221,7 +221,8 @@
 interception_files = \
         interception_linux.cc \
         interception_mac.cc \
-        interception_win.cc
+        interception_win.cc \
+	interception_type_test.cc
 
 libinterception_la_SOURCES = $(interception_files)
 
@@ -318,6 +319,7 @@
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_linux.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_mac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_type_test.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_win.Plo@am__quote@
 
 .cc.o:
Index: libsanitizer/interception/interception_mac.cc
===================================================================
--- libsanitizer/interception/interception_mac.cc	(revision 195997)
+++ libsanitizer/interception/interception_mac.cc	(working copy)
@@ -13,17 +13,6 @@
 #ifdef __APPLE__
 
 #include "interception.h"
-#include "mach_override/mach_override.h"
 
-namespace __interception {
-bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
-  *orig_old_func = 0;
-  int res = __asan_mach_override_ptr_custom((void*)old_func, (void*)new_func,
-                                            (void**)orig_old_func,
-                                            __interception_allocate_island,
-                                            __interception_deallocate_island);
-  return (res == 0) && (*orig_old_func != 0);
-}
-}  // namespace __interception
 
 #endif  // __APPLE__
Index: libsanitizer/interception/interception_type_test.cc
===================================================================
--- libsanitizer/interception/interception_type_test.cc	(revision 0)
+++ libsanitizer/interception/interception_type_test.cc	(revision 0)
@@ -0,0 +1,37 @@
+//===-- interception_type_test.cc -------------------------------*- C++ -*-===//
+//
+// 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.
+//
+// Compile-time tests of the internal type definitions.
+//===----------------------------------------------------------------------===//
+
+#if defined(__linux__) || defined(__APPLE__)
+
+#include "interception.h"
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdint.h>
+
+COMPILER_CHECK(sizeof(SIZE_T) == sizeof(size_t));
+COMPILER_CHECK(sizeof(SSIZE_T) == sizeof(ssize_t));
+COMPILER_CHECK(sizeof(PTRDIFF_T) == sizeof(ptrdiff_t));
+COMPILER_CHECK(sizeof(INTMAX_T) == sizeof(intmax_t));
+
+#ifndef __APPLE__
+COMPILER_CHECK(sizeof(OFF64_T) == sizeof(off64_t));
+#endif
+
+// The following are the cases when pread (and friends) is used instead of
+// pread64. In those cases we need OFF_T to match off_t. We don't care about the
+// rest (they depend on _FILE_OFFSET_BITS setting when building an application).
+# if defined(__ANDROID__) || !defined _FILE_OFFSET_BITS || \
+  _FILE_OFFSET_BITS != 64
+COMPILER_CHECK(sizeof(OFF_T) == sizeof(off_t));
+# endif
+
+#endif
Index: libsanitizer/tsan/tsan_rtl_mutex.cc
===================================================================
--- libsanitizer/tsan/tsan_rtl_mutex.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_rtl_mutex.cc	(working copy)
@@ -24,8 +24,12 @@
   CHECK_GT(thr->in_rtl, 0);
   DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
   StatInc(thr, StatMutexCreate);
-  if (!linker_init && IsAppMem(addr))
-    MemoryWrite1Byte(thr, pc, addr);
+  if (!linker_init && IsAppMem(addr)) {
+    CHECK(!thr->is_freeing);
+    thr->is_freeing = true;
+    MemoryWrite(thr, pc, addr, kSizeLog1);
+    thr->is_freeing = false;
+  }
   SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
   s->is_rw = rw;
   s->is_recursive = recursive;
@@ -47,8 +51,12 @@
   SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr);
   if (s == 0)
     return;
-  if (IsAppMem(addr))
-    MemoryWrite1Byte(thr, pc, addr);
+  if (IsAppMem(addr)) {
+    CHECK(!thr->is_freeing);
+    thr->is_freeing = true;
+    MemoryWrite(thr, pc, addr, kSizeLog1);
+    thr->is_freeing = false;
+  }
   if (flags()->report_destroy_locked
       && s->owner_tid != SyncVar::kInvalidTid
       && !s->is_broken) {
@@ -73,7 +81,7 @@
   CHECK_GT(thr->in_rtl, 0);
   DPrintf("#%d: MutexLock %zx\n", thr->tid, addr);
   if (IsAppMem(addr))
-    MemoryRead1Byte(thr, pc, addr);
+    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
@@ -106,7 +114,7 @@
   CHECK_GT(thr->in_rtl, 0);
   DPrintf("#%d: MutexUnlock %zx\n", thr->tid, addr);
   if (IsAppMem(addr))
-    MemoryRead1Byte(thr, pc, 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());
@@ -144,7 +152,7 @@
   DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
   StatInc(thr, StatMutexReadLock);
   if (IsAppMem(addr))
-    MemoryRead1Byte(thr, pc, addr);
+    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, false);
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
@@ -165,7 +173,7 @@
   DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
   StatInc(thr, StatMutexReadUnlock);
   if (IsAppMem(addr))
-    MemoryRead1Byte(thr, pc, addr);
+    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
@@ -186,7 +194,7 @@
   CHECK_GT(thr->in_rtl, 0);
   DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
   if (IsAppMem(addr))
-    MemoryRead1Byte(thr, pc, addr);
+    MemoryReadAtomic(thr, pc, addr, kSizeLog1);
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
   bool write = true;
   if (s->owner_tid == SyncVar::kInvalidTid) {
Index: libsanitizer/tsan/tsan_md5.cc
===================================================================
--- libsanitizer/tsan/tsan_md5.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_md5.cc	(working copy)
@@ -240,4 +240,4 @@
   MD5_Final((unsigned char*)&res.hash[0], &ctx);
   return res;
 }
-}
+}  // namespace __tsan
Index: libsanitizer/tsan/tsan_platform.h
===================================================================
--- libsanitizer/tsan/tsan_platform.h	(revision 195997)
+++ libsanitizer/tsan/tsan_platform.h	(working copy)
@@ -149,6 +149,7 @@
 uptr GetTlsSize();
 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
 
Index: libsanitizer/tsan/tsan_update_shadow_word_inl.h
===================================================================
--- libsanitizer/tsan/tsan_update_shadow_word_inl.h	(revision 195997)
+++ libsanitizer/tsan/tsan_update_shadow_word_inl.h	(working copy)
@@ -32,7 +32,7 @@
     if (Shadow::TidsAreEqual(old, cur)) {
       StatInc(thr, StatShadowSameThread);
       if (OldIsInSameSynchEpoch(old, thr)) {
-        if (OldIsRWNotWeaker(old, kAccessIsWrite)) {
+        if (old.IsRWNotWeaker(kAccessIsWrite, kIsAtomic)) {
           // found a slot that holds effectively the same info
           // (that is, same tid, same sync epoch and same size)
           StatInc(thr, StatMopSame);
@@ -41,7 +41,7 @@
         StoreIfNotYetStored(sp, &store_word);
         break;
       }
-      if (OldIsRWWeakerOrEqual(old, kAccessIsWrite))
+      if (old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic))
         StoreIfNotYetStored(sp, &store_word);
       break;
     }
@@ -50,25 +50,23 @@
       StoreIfNotYetStored(sp, &store_word);
       break;
     }
-    if (BothReads(old, kAccessIsWrite))
+    if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))
       break;
     goto RACE;
   }
-
   // Do the memory access intersect?
-  if (Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
+  // In Go all memory accesses are 1 byte, so there can be no intersections.
+  if (kCppMode && Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
     StatInc(thr, StatShadowIntersect);
     if (Shadow::TidsAreEqual(old, cur)) {
       StatInc(thr, StatShadowSameThread);
       break;
     }
     StatInc(thr, StatShadowAnotherThread);
+    if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))
+      break;
     if (HappensBefore(old, thr))
       break;
-
-    if (BothReads(old, kAccessIsWrite))
-      break;
-
     goto RACE;
   }
   // The accesses do not intersect.
Index: libsanitizer/tsan/tsan_mman.cc
===================================================================
--- libsanitizer/tsan/tsan_mman.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_mman.cc	(working copy)
@@ -36,10 +36,18 @@
   allocator()->Init();
 }
 
-void AlloctorThreadFinish(ThreadState *thr) {
-  allocator()->SwallowCache(&thr->alloc_cache);
+void AllocatorThreadStart(ThreadState *thr) {
+  allocator()->InitCache(&thr->alloc_cache);
 }
 
+void AllocatorThreadFinish(ThreadState *thr) {
+  allocator()->DestroyCache(&thr->alloc_cache);
+}
+
+void AllocatorPrintStats() {
+  allocator()->PrintStats();
+}
+
 static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
   if (!thr->in_signal_handler || !flags()->report_signal_unsafe)
     return;
@@ -162,3 +170,49 @@
 }
 
 }  // namespace __tsan
+
+using namespace __tsan;
+
+extern "C" {
+uptr __tsan_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 __tsan_get_heap_size() {
+  u64 stats[AllocatorStatCount];
+  allocator()->GetStats(stats);
+  u64 m = stats[AllocatorStatMmapped];
+  u64 f = stats[AllocatorStatUnmapped];
+  return m >= f ? m - f : 1;
+}
+
+uptr __tsan_get_free_bytes() {
+  return 1;
+}
+
+uptr __tsan_get_unmapped_bytes() {
+  return 1;
+}
+
+uptr __tsan_get_estimated_allocated_size(uptr size) {
+  return size;
+}
+
+bool __tsan_get_ownership(void *p) {
+  return allocator()->GetBlockBegin(p) != 0;
+}
+
+uptr __tsan_get_allocated_size(void *p) {
+  if (p == 0)
+    return 0;
+  p = allocator()->GetBlockBegin(p);
+  if (p == 0)
+    return 0;
+  MBlock *b = (MBlock*)allocator()->GetMetaData(p);
+  return b->size;
+}
+}  // extern "C"
Index: libsanitizer/tsan/tsan_fd.cc
===================================================================
--- libsanitizer/tsan/tsan_fd.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_fd.cc	(working copy)
@@ -148,7 +148,7 @@
   FdDesc *d = fddesc(thr, pc, fd);
   FdSync *s = d->sync;
   DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, s);
-  MemoryRead8Byte(thr, pc, (uptr)d);
+  MemoryRead(thr, pc, (uptr)d, kSizeLog8);
   if (s)
     Acquire(thr, pc, (uptr)s);
 }
@@ -159,20 +159,20 @@
   DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, s);
   if (s)
     Release(thr, pc, (uptr)s);
-  MemoryRead8Byte(thr, pc, (uptr)d);
+  MemoryRead(thr, pc, (uptr)d, kSizeLog8);
 }
 
 void FdAccess(ThreadState *thr, uptr pc, int fd) {
   DPrintf("#%d: FdAccess(%d)\n", thr->tid, fd);
   FdDesc *d = fddesc(thr, pc, fd);
-  MemoryRead8Byte(thr, pc, (uptr)d);
+  MemoryRead(thr, pc, (uptr)d, kSizeLog8);
 }
 
 void FdClose(ThreadState *thr, uptr pc, int fd) {
   DPrintf("#%d: FdClose(%d)\n", thr->tid, fd);
   FdDesc *d = fddesc(thr, pc, fd);
   // To catch races between fd usage and close.
-  MemoryWrite8Byte(thr, pc, (uptr)d);
+  MemoryWrite(thr, pc, (uptr)d, kSizeLog8);
   // We need to clear it, because if we do not intercept any call out there
   // that creates fd, we will hit false postives.
   MemoryResetRange(thr, pc, (uptr)d, 8);
@@ -191,7 +191,7 @@
   DPrintf("#%d: FdDup(%d, %d)\n", thr->tid, oldfd, newfd);
   // Ignore the case when user dups not yet connected socket.
   FdDesc *od = fddesc(thr, pc, oldfd);
-  MemoryRead8Byte(thr, pc, (uptr)od);
+  MemoryRead(thr, pc, (uptr)od, kSizeLog8);
   FdClose(thr, pc, newfd);
   init(thr, pc, newfd, ref(od->sync));
 }
Index: libsanitizer/tsan/tsan_flags.cc
===================================================================
--- libsanitizer/tsan/tsan_flags.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_flags.cc	(working copy)
@@ -43,6 +43,7 @@
   f->report_thread_leaks = true;
   f->report_destroy_locked = true;
   f->report_signal_unsafe = true;
+  f->report_atomic_races = true;
   f->force_seq_cst_atomics = false;
   f->strip_path_prefix = "";
   f->suppressions = "";
@@ -70,6 +71,7 @@
   ParseFlag(env, &f->report_thread_leaks, "report_thread_leaks");
   ParseFlag(env, &f->report_destroy_locked, "report_destroy_locked");
   ParseFlag(env, &f->report_signal_unsafe, "report_signal_unsafe");
+  ParseFlag(env, &f->report_atomic_races, "report_atomic_races");
   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");
Index: libsanitizer/tsan/tsan_interface.cc
===================================================================
--- libsanitizer/tsan/tsan_interface.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_interface.cc	(working copy)
@@ -22,13 +22,13 @@
 }
 
 void __tsan_read16(void *addr) {
-  MemoryRead8Byte(cur_thread(), CALLERPC, (uptr)addr);
-  MemoryRead8Byte(cur_thread(), CALLERPC, (uptr)addr + 8);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
 }
 
 void __tsan_write16(void *addr) {
-  MemoryWrite8Byte(cur_thread(), CALLERPC, (uptr)addr);
-  MemoryWrite8Byte(cur_thread(), CALLERPC, (uptr)addr + 8);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
 }
 
 void __tsan_acquire(void *addr) {
Index: libsanitizer/tsan/tsan_interface_java.cc
===================================================================
--- libsanitizer/tsan/tsan_interface_java.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_interface_java.cc	(working copy)
@@ -150,7 +150,7 @@
   return 0;
 }
 
-}  // namespace __tsan {
+}  // namespace __tsan
 
 #define SCOPED_JAVA_FUNC(func) \
   ThreadState *thr = cur_thread(); \
Index: libsanitizer/tsan/tsan_rtl.cc
===================================================================
--- libsanitizer/tsan/tsan_rtl.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_rtl.cc	(working copy)
@@ -35,6 +35,11 @@
 #endif
 static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
 
+// Can be overriden by a front-end.
+bool CPP_WEAK OnFinalize(bool failed) {
+  return failed;
+}
+
 static Context *ctx;
 Context *CTX() {
   return ctx;
@@ -136,7 +141,7 @@
   InternalScopedBuffer<char> filename(4096);
   internal_snprintf(filename.data(), filename.size(), "%s.%d",
       flags()->profile_memory, GetPid());
-  fd_t fd = internal_open(filename.data(), true);
+  fd_t fd = OpenFile(filename.data(), true);
   if (fd == kInvalidFd) {
     Printf("Failed to open memory profile file '%s'\n", &filename[0]);
     Die();
@@ -180,6 +185,7 @@
   if (is_initialized)
     return;
   is_initialized = true;
+  SanitizerToolName = "ThreadSanitizer";
   // Install tool-specific callbacks in sanitizer_common.
   SetCheckFailedCallback(TsanCheckFailed);
 
@@ -237,7 +243,7 @@
     Printf("ThreadSanitizer is suspended at startup (pid %d)."
            " Call __tsan_resume().\n",
            GetPid());
-    while (__tsan_resumed == 0);
+    while (__tsan_resumed == 0) {}
   }
 }
 
@@ -253,6 +259,11 @@
   ctx->report_mtx.Lock();
   ctx->report_mtx.Unlock();
 
+#ifndef TSAN_GO
+  if (ctx->flags.verbosity)
+    AllocatorPrintStats();
+#endif
+
   ThreadFinalize(thr);
 
   if (ctx->nreported) {
@@ -270,6 +281,8 @@
         ctx->nmissed_expected);
   }
 
+  failed = OnFinalize(failed);
+
   StatAggregate(ctx->stat, thr->stat);
   StatOutput(ctx->stat);
   return failed ? flags()->exitcode : 0;
@@ -356,18 +369,6 @@
 #endif
 }
 
-static inline bool BothReads(Shadow s, int kAccessIsWrite) {
-  return !kAccessIsWrite && !s.is_write();
-}
-
-static inline bool OldIsRWNotWeaker(Shadow old, int kAccessIsWrite) {
-  return old.is_write() || !kAccessIsWrite;
-}
-
-static inline bool OldIsRWWeakerOrEqual(Shadow old, int kAccessIsWrite) {
-  return !old.is_write() || kAccessIsWrite;
-}
-
 static inline bool OldIsInSameSynchEpoch(Shadow old, ThreadState *thr) {
   return old.epoch() >= thr->fast_synch_epoch;
 }
@@ -378,7 +379,7 @@
 
 ALWAYS_INLINE
 void MemoryAccessImpl(ThreadState *thr, uptr addr,
-    int kAccessSizeLog, bool kAccessIsWrite,
+    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
     u64 *shadow_mem, Shadow cur) {
   StatInc(thr, StatMop);
   StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
@@ -452,7 +453,7 @@
 
 ALWAYS_INLINE
 void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
-    int kAccessSizeLog, bool kAccessIsWrite) {
+    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) {
   u64 *shadow_mem = (u64*)MemToShadow(addr);
   DPrintf2("#%d: MemoryAccess: @%p %p size=%d"
       " is_write=%d shadow_mem=%p {%zx, %zx, %zx, %zx}\n",
@@ -479,12 +480,13 @@
   Shadow cur(fast_state);
   cur.SetAddr0AndSizeLog(addr & 7, kAccessSizeLog);
   cur.SetWrite(kAccessIsWrite);
+  cur.SetAtomic(kIsAtomic);
 
   // We must not store to the trace if we do not store to the shadow.
   // That is, this call must be moved somewhere below.
   TraceAddEvent(thr, fast_state, EventTypeMop, pc);
 
-  MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite,
+  MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic,
       shadow_mem, cur);
 }
 
@@ -531,7 +533,10 @@
 }
 
 void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) {
+  CHECK_EQ(thr->is_freeing, false);
+  thr->is_freeing = true;
   MemoryAccessRange(thr, pc, addr, size, true);
+  thr->is_freeing = false;
   Shadow s(thr->fast_state);
   s.ClearIgnoreBit();
   s.MarkAsFreed();
Index: libsanitizer/tsan/tsan_rtl.h
===================================================================
--- libsanitizer/tsan/tsan_rtl.h	(revision 195997)
+++ libsanitizer/tsan/tsan_rtl.h	(working copy)
@@ -171,7 +171,8 @@
 //   freed           : 1
 //   tid             : kTidBits
 //   epoch           : kClkBits
-//   is_write        : 1
+//   is_atomic       : 1
+//   is_read         : 1
 //   size_log        : 2
 //   addr0           : 3
 class Shadow : public FastState {
@@ -195,14 +196,27 @@
   }
 
   void SetWrite(unsigned kAccessIsWrite) {
-    DCHECK_EQ(x_ & 32, 0);
-    if (kAccessIsWrite)
-      x_ |= 32;
-    DCHECK_EQ(kAccessIsWrite, is_write());
+    DCHECK_EQ(x_ & kReadBit, 0);
+    if (!kAccessIsWrite)
+      x_ |= kReadBit;
+    DCHECK_EQ(kAccessIsWrite, IsWrite());
   }
 
-  bool IsZero() const { return x_ == 0; }
+  void SetAtomic(bool kIsAtomic) {
+    DCHECK(!IsAtomic());
+    if (kIsAtomic)
+      x_ |= kAtomicBit;
+    DCHECK_EQ(IsAtomic(), kIsAtomic);
+  }
 
+  bool IsAtomic() const {
+    return x_ & kAtomicBit;
+  }
+
+  bool IsZero() const {
+    return x_ == 0;
+  }
+
   static inline bool TidsAreEqual(const Shadow s1, const Shadow s2) {
     u64 shifted_xor = (s1.x_ ^ s2.x_) >> kTidShift;
     DCHECK_EQ(shifted_xor == 0, s1.TidWithIgnore() == s2.TidWithIgnore());
@@ -248,7 +262,8 @@
   }
   u64 addr0() const { return x_ & 7; }
   u64 size() const { return 1ull << size_log(); }
-  bool is_write() const { return x_ & 32; }
+  bool IsWrite() const { return !IsRead(); }
+  bool IsRead() const { return x_ & kReadBit; }
 
   // The idea behind the freed bit is as follows.
   // When the memory is freed (or otherwise unaccessible) we write to the shadow
@@ -263,13 +278,46 @@
      x_ |= kFreedBit;
   }
 
+  bool IsFreed() const {
+    return x_ & kFreedBit;
+  }
+
   bool GetFreedAndReset() {
     bool res = x_ & kFreedBit;
     x_ &= ~kFreedBit;
     return res;
   }
 
+  bool IsBothReadsOrAtomic(bool kIsWrite, bool kIsAtomic) const {
+    // analyzes 5-th bit (is_read) and 6-th bit (is_atomic)
+    bool v = x_ & u64(((kIsWrite ^ 1) << kReadShift)
+        | (kIsAtomic << kAtomicShift));
+    DCHECK_EQ(v, (!IsWrite() && !kIsWrite) || (IsAtomic() && kIsAtomic));
+    return v;
+  }
+
+  bool IsRWNotWeaker(bool kIsWrite, bool kIsAtomic) const {
+    bool v = ((x_ >> kReadShift) & 3)
+        <= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
+    DCHECK_EQ(v, (IsAtomic() < kIsAtomic) ||
+        (IsAtomic() == kIsAtomic && !IsWrite() <= !kIsWrite));
+    return v;
+  }
+
+  bool IsRWWeakerOrEqual(bool kIsWrite, bool kIsAtomic) const {
+    bool v = ((x_ >> kReadShift) & 3)
+        >= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
+    DCHECK_EQ(v, (IsAtomic() > kIsAtomic) ||
+        (IsAtomic() == kIsAtomic && !IsWrite() >= !kIsWrite));
+    return v;
+  }
+
  private:
+  static const u64 kReadShift   = 5;
+  static const u64 kReadBit     = 1ull << kReadShift;
+  static const u64 kAtomicShift = 6;
+  static const u64 kAtomicBit   = 1ull << kAtomicShift;
+
   u64 size_log() const { return (x_ >> 3) & 3; }
 
   static bool TwoRangesIntersectSLOW(const Shadow s1, const Shadow s2) {
@@ -324,7 +372,9 @@
   const int tid;
   const int unique_id;
   int in_rtl;
+  bool in_symbolizer;
   bool is_alive;
+  bool is_freeing;
   const uptr stk_addr;
   const uptr stk_size;
   const uptr tls_addr;
@@ -501,11 +551,14 @@
 void ReportRace(ThreadState *thr);
 bool OutputReport(Context *ctx,
                   const ScopedReport &srep,
-                  const ReportStack *suppress_stack = 0);
+                  const ReportStack *suppress_stack1 = 0,
+                  const ReportStack *suppress_stack2 = 0);
 bool IsFiredSuppression(Context *ctx,
                         const ScopedReport &srep,
                         const StackTrace &trace);
 bool IsExpectedReport(uptr addr, uptr size);
+bool FrameIsInternal(const ReportStack *frame);
+ReportStack *SkipTsanInternalFrames(ReportStack *ent);
 
 #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
 # define DPrintf Printf
@@ -521,6 +574,7 @@
 
 u32 CurrentStackId(ThreadState *thr, uptr pc);
 void PrintCurrentStack(ThreadState *thr, uptr pc);
+void PrintCurrentStackSlow();  // uses libunwind
 
 void Initialize(ThreadState *thr);
 int Finalize(ThreadState *thr);
@@ -530,16 +584,38 @@
 SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr);
 
 void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
-    int kAccessSizeLog, bool kAccessIsWrite);
+    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic);
 void MemoryAccessImpl(ThreadState *thr, uptr addr,
-    int kAccessSizeLog, bool kAccessIsWrite,
+    int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
     u64 *shadow_mem, Shadow cur);
-void MemoryRead1Byte(ThreadState *thr, uptr pc, uptr addr);
-void MemoryWrite1Byte(ThreadState *thr, uptr pc, uptr addr);
-void MemoryRead8Byte(ThreadState *thr, uptr pc, uptr addr);
-void MemoryWrite8Byte(ThreadState *thr, uptr pc, uptr addr);
 void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
-                       uptr size, bool is_write);
+    uptr size, bool is_write);
+
+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,
+                                     uptr addr, int kAccessSizeLog) {
+  MemoryAccess(thr, pc, addr, kAccessSizeLog, false, false);
+}
+
+void ALWAYS_INLINE 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,
+                                           uptr addr, int kAccessSizeLog) {
+  MemoryAccess(thr, pc, addr, kAccessSizeLog, false, true);
+}
+
+void ALWAYS_INLINE INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
+                                            uptr addr, int kAccessSizeLog) {
+  MemoryAccess(thr, pc, addr, kAccessSizeLog, true, true);
+}
+
 void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size);
 void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size);
 void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size);
Index: libsanitizer/tsan/tsan_vector.h
===================================================================
--- libsanitizer/tsan/tsan_vector.h	(revision 195997)
+++ libsanitizer/tsan/tsan_vector.h	(working copy)
@@ -103,6 +103,6 @@
   Vector(const Vector&);
   void operator=(const Vector&);
 };
-}
+}  // namespace __tsan
 
 #endif  // #ifndef TSAN_VECTOR_H
Index: libsanitizer/tsan/tsan_report.cc
===================================================================
--- libsanitizer/tsan/tsan_report.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_report.cc	(working copy)
@@ -41,23 +41,20 @@
   return buf;
 }
 
-static void PrintHeader(ReportType typ) {
-  Printf("WARNING: ThreadSanitizer: ");
-
+static const char *ReportTypeString(ReportType typ) {
   if (typ == ReportTypeRace)
-    Printf("data race");
-  else if (typ == ReportTypeUseAfterFree)
-    Printf("heap-use-after-free");
-  else if (typ == ReportTypeThreadLeak)
-    Printf("thread leak");
-  else if (typ == ReportTypeMutexDestroyLocked)
-    Printf("destroy of a locked mutex");
-  else if (typ == ReportTypeSignalUnsafe)
-    Printf("signal-unsafe call inside of a signal");
-  else if (typ == ReportTypeErrnoInSignal)
-    Printf("signal handler spoils errno");
-
-  Printf(" (pid=%d)\n", GetPid());
+    return "data race";
+  if (typ == ReportTypeUseAfterFree)
+    return "heap-use-after-free";
+  if (typ == ReportTypeThreadLeak)
+    return "thread leak";
+  if (typ == ReportTypeMutexDestroyLocked)
+    return "destroy of a locked mutex";
+  if (typ == ReportTypeSignalUnsafe)
+    return "signal-unsafe call inside of a signal";
+  if (typ == ReportTypeErrnoInSignal)
+    return "signal handler spoils errno";
+  return "";
 }
 
 void PrintStack(const ReportStack *ent) {
@@ -87,11 +84,17 @@
   }
 }
 
+static const char *MopDesc(bool first, bool write, bool atomic) {
+  return atomic ? (first ? (write ? "Atomic write" : "Atomic read")
+                : (write ? "Previous atomic write" : "Previous atomic read"))
+                : (first ? (write ? "Write" : "Read")
+                : (write ? "Previous write" : "Previous read"));
+}
+
 static void PrintMop(const ReportMop *mop, bool first) {
   char thrbuf[kThreadBufSize];
   Printf("  %s of size %d at %p by %s",
-      (first ? (mop->write ? "Write" : "Read")
-             : (mop->write ? "Previous write" : "Previous read")),
+      MopDesc(first, mop->write, mop->atomic),
       mop->size, (void*)mop->addr,
       thread_name(thrbuf, mop->tid));
   PrintMutexSet(mop->mset);
@@ -150,9 +153,28 @@
   PrintStack(s);
 }
 
+static ReportStack *ChooseSummaryStack(const ReportDesc *rep) {
+  if (rep->mops.Size())
+    return rep->mops[0]->stack;
+  if (rep->stacks.Size())
+    return rep->stacks[0];
+  if (rep->mutexes.Size())
+    return rep->mutexes[0]->stack;
+  if (rep->threads.Size())
+    return rep->threads[0]->stack;
+  return 0;
+}
+
+ReportStack *SkipTsanInternalFrames(ReportStack *ent) {
+  while (FrameIsInternal(ent) && ent->next)
+    ent = ent->next;
+  return ent;
+}
+
 void PrintReport(const ReportDesc *rep) {
   Printf("==================\n");
-  PrintHeader(rep->typ);
+  const char *rep_typ_str = ReportTypeString(rep->typ);
+  Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, GetPid());
 
   for (uptr i = 0; i < rep->stacks.Size(); i++) {
     if (i)
@@ -175,6 +197,9 @@
   for (uptr i = 0; i < rep->threads.Size(); i++)
     PrintThread(rep->threads[i]);
 
+  if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep)))
+    ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
+
   Printf("==================\n");
 }
 
Index: libsanitizer/tsan/tsan_suppressions.cc
===================================================================
--- libsanitizer/tsan/tsan_suppressions.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_suppressions.cc	(working copy)
@@ -17,6 +17,13 @@
 #include "tsan_mman.h"
 #include "tsan_platform.h"
 
+// Can be overriden in frontend.
+#ifndef TSAN_GO
+extern "C" const char *WEAK __tsan_default_suppressions() {
+  return 0;
+}
+#endif
+
 namespace __tsan {
 
 static Suppression *g_suppressions;
@@ -29,7 +36,7 @@
     internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
   else
     internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
-  fd_t fd = internal_open(tmp.data(), false);
+  fd_t fd = OpenFile(tmp.data(), false);
   if (fd == kInvalidFd) {
     Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
                tmp.data());
@@ -78,8 +85,7 @@
   return true;
 }
 
-Suppression *SuppressionParse(const char* supp) {
-  Suppression *head = 0;
+Suppression *SuppressionParse(Suppression *head, const char* supp) {
   const char *line = supp;
   while (line) {
     while (line[0] == ' ' || line[0] == '\t')
@@ -128,8 +134,12 @@
 }
 
 void InitializeSuppressions() {
-  char *supp = ReadFile(flags()->suppressions);
-  g_suppressions = SuppressionParse(supp);
+  const char *supp = ReadFile(flags()->suppressions);
+  g_suppressions = SuppressionParse(0, supp);
+#ifndef TSAN_GO
+  supp = __tsan_default_suppressions();
+  g_suppressions = SuppressionParse(0, supp);
+#endif
 }
 
 uptr IsSuppressed(ReportType typ, const ReportStack *stack) {
@@ -150,7 +160,8 @@
     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->file) ||
+           SuppressionMatch(supp->templ, frame->module))) {
         DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
         return frame->pc;
       }
Index: libsanitizer/tsan/tsan_report.h
===================================================================
--- libsanitizer/tsan/tsan_report.h	(revision 195997)
+++ libsanitizer/tsan/tsan_report.h	(working copy)
@@ -46,6 +46,7 @@
   uptr addr;
   int size;
   bool write;
+  bool atomic;
   Vector<ReportMopMutex> mset;
   ReportStack *stack;
 
Index: libsanitizer/tsan/tsan_suppressions.h
===================================================================
--- libsanitizer/tsan/tsan_suppressions.h	(revision 195997)
+++ libsanitizer/tsan/tsan_suppressions.h	(working copy)
@@ -33,7 +33,7 @@
   char *templ;
 };
 
-Suppression *SuppressionParse(const char* supp);
+Suppression *SuppressionParse(Suppression *head, const char* supp);
 bool SuppressionMatch(char *templ, const char *str);
 
 }  // namespace __tsan
Index: libsanitizer/tsan/tsan_interceptors.cc
===================================================================
--- libsanitizer/tsan/tsan_interceptors.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_interceptors.cc	(working copy)
@@ -51,9 +51,12 @@
 extern "C" int sigfillset(sigset_t *set);
 extern "C" void *pthread_self();
 extern "C" void _exit(int status);
-extern "C" int __cxa_atexit(void (*func)(void *arg), void *arg, void *dso);
 extern "C" int *__errno_location();
 extern "C" int fileno_unlocked(void *stream);
+extern "C" void *__libc_malloc(uptr size);
+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);
 const int PTHREAD_MUTEX_RECURSIVE = 1;
 const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
 const int kPthreadAttrSize = 56;
@@ -122,7 +125,7 @@
   int pending_signal_count;
   SignalDesc pending_signals[kSigCount];
 };
-}
+}  // namespace __tsan
 
 static SignalContext *SigCtx(ThreadState *thr) {
   SignalContext *ctx = (SignalContext*)thr->signal_ctx;
@@ -238,12 +241,15 @@
 
   typedef void(*atexit_t)();
 
-  int atexit(ThreadState *thr, uptr pc, atexit_t f) {
+  int atexit(ThreadState *thr, uptr pc, bool is_on_exit,
+             atexit_t f, void *arg) {
     Lock l(&mtx_);
     if (pos_ == kMaxAtExit)
       return 1;
     Release(thr, pc, (uptr)this);
     stack_[pos_] = f;
+    args_[pos_] = arg;
+    is_on_exits_[pos_] = is_on_exit;
     pos_++;
     return 0;
   }
@@ -252,11 +258,15 @@
     CHECK_EQ(thr->in_rtl, 0);
     for (;;) {
       atexit_t f = 0;
+      void *arg = 0;
+      bool is_on_exit = false;
       {
         Lock l(&mtx_);
         if (pos_) {
           pos_--;
           f = stack_[pos_];
+          arg = args_[pos_];
+          is_on_exit = is_on_exits_[pos_];
           ScopedInRtl in_rtl;
           Acquire(thr, pc, (uptr)this);
         }
@@ -265,7 +275,10 @@
         break;
       DPrintf("#%d: executing atexit func %p\n", thr->tid, f);
       CHECK_EQ(thr->in_rtl, 0);
-      f();
+      if (is_on_exit)
+        ((void(*)(int status, void *arg))f)(0, arg);
+      else
+        ((void(*)(void *arg, void *dso))f)(arg, 0);
     }
   }
 
@@ -273,6 +286,8 @@
   static const int kMaxAtExit = 128;
   Mutex mtx_;
   atexit_t stack_[kMaxAtExit];
+  void *args_[kMaxAtExit];
+  bool is_on_exits_[kMaxAtExit];
   int pos_;
 };
 
@@ -282,20 +297,34 @@
   ThreadState * thr = cur_thread();
   uptr pc = 0;
   atexit_ctx->exit(thr, pc);
-  {
-    ScopedInRtl in_rtl;
-    DestroyAndFree(atexit_ctx);
-  }
   int status = Finalize(cur_thread());
   if (status)
     _exit(status);
 }
 
 TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
+  if (cur_thread()->in_symbolizer)
+    return 0;
   SCOPED_TSAN_INTERCEPTOR(atexit, f);
-  return atexit_ctx->atexit(thr, pc, f);
+  return atexit_ctx->atexit(thr, pc, false, (void(*)())f, 0);
 }
 
+TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
+  if (cur_thread()->in_symbolizer)
+    return 0;
+  SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
+  return atexit_ctx->atexit(thr, pc, true, (void(*)())f, arg);
+}
+
+TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
+  if (cur_thread()->in_symbolizer)
+    return 0;
+  SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
+  if (dso)
+    return REAL(__cxa_atexit)(f, arg, dso);
+  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");
@@ -309,6 +338,8 @@
 }
 
 TSAN_INTERCEPTOR(void*, malloc, uptr size) {
+  if (cur_thread()->in_symbolizer)
+    return __libc_malloc(size);
   void *p = 0;
   {
     SCOPED_INTERCEPTOR_RAW(malloc, size);
@@ -324,6 +355,9 @@
 }
 
 TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
+  if (cur_thread()->in_symbolizer)
+    return __libc_calloc(size, n);
+  if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, n)) return 0;
   void *p = 0;
   {
     SCOPED_INTERCEPTOR_RAW(calloc, size, n);
@@ -335,6 +369,8 @@
 }
 
 TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
+  if (cur_thread()->in_symbolizer)
+    return __libc_realloc(p, size);
   if (p)
     invoke_free_hook(p);
   {
@@ -348,6 +384,8 @@
 TSAN_INTERCEPTOR(void, free, void *p) {
   if (p == 0)
     return;
+  if (cur_thread()->in_symbolizer)
+    return __libc_free(p);
   invoke_free_hook(p);
   SCOPED_INTERCEPTOR_RAW(free, p);
   user_free(thr, pc, p);
@@ -356,12 +394,16 @@
 TSAN_INTERCEPTOR(void, cfree, void *p) {
   if (p == 0)
     return;
+  if (cur_thread()->in_symbolizer)
+    return __libc_free(p);
   invoke_free_hook(p);
   SCOPED_INTERCEPTOR_RAW(cfree, p);
   user_free(thr, pc, p);
 }
 
 #define OPERATOR_NEW_BODY(mangled_name) \
+  if (cur_thread()->in_symbolizer) \
+    return __libc_malloc(size); \
   void *p = 0; \
   {  \
     SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
@@ -385,6 +427,8 @@
 
 #define OPERATOR_DELETE_BODY(mangled_name) \
   if (ptr == 0) return;  \
+  if (cur_thread()->in_symbolizer) \
+    return __libc_free(ptr); \
   invoke_free_hook(ptr);  \
   SCOPED_INTERCEPTOR_RAW(mangled_name, ptr);  \
   user_free(thr, pc, ptr);
@@ -549,6 +593,8 @@
     return MAP_FAILED;
   void *res = REAL(mmap)(addr, sz, prot, flags, fd, off);
   if (res != MAP_FAILED) {
+    if (fd > 0)
+      FdAccess(thr, pc, fd);
     MemoryResetRange(thr, pc, (uptr)res, sz);
   }
   return res;
@@ -561,6 +607,8 @@
     return MAP_FAILED;
   void *res = REAL(mmap64)(addr, sz, prot, flags, fd, off);
   if (res != MAP_FAILED) {
+    if (fd > 0)
+      FdAccess(thr, pc, fd);
     MemoryResetRange(thr, pc, (uptr)res, sz);
   }
   return res;
@@ -958,14 +1006,14 @@
 
 TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) {
   SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count);
-  MemoryWrite1Byte(thr, pc, (uptr)b);
+  MemoryWrite(thr, pc, (uptr)b, kSizeLog1);
   int res = REAL(pthread_barrier_init)(b, a, count);
   return res;
 }
 
 TSAN_INTERCEPTOR(int, pthread_barrier_destroy, void *b) {
   SCOPED_TSAN_INTERCEPTOR(pthread_barrier_destroy, b);
-  MemoryWrite1Byte(thr, pc, (uptr)b);
+  MemoryWrite(thr, pc, (uptr)b, kSizeLog1);
   int res = REAL(pthread_barrier_destroy)(b);
   return res;
 }
@@ -973,9 +1021,9 @@
 TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
   SCOPED_TSAN_INTERCEPTOR(pthread_barrier_wait, b);
   Release(thr, pc, (uptr)b);
-  MemoryRead1Byte(thr, pc, (uptr)b);
+  MemoryRead(thr, pc, (uptr)b, kSizeLog1);
   int res = REAL(pthread_barrier_wait)(b);
-  MemoryRead1Byte(thr, pc, (uptr)b);
+  MemoryRead(thr, pc, (uptr)b, kSizeLog1);
   if (res == 0 || res == PTHREAD_BARRIER_SERIAL_THREAD) {
     Acquire(thr, pc, (uptr)b);
   }
@@ -1062,6 +1110,74 @@
   return res;
 }
 
+TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
+  return REAL(__xstat)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__xstat, 0, path, buf);
+  return REAL(__xstat)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
+  return REAL(__xstat64)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
+  return REAL(__xstat64)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
+  return REAL(__lxstat)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__lxstat, 0, path, buf);
+  return REAL(__lxstat)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
+  return REAL(__lxstat64)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
+  return REAL(__lxstat64)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf);
+  if (fd > 0)
+    FdAccess(thr, pc, fd);
+  return REAL(__fxstat)(version, fd, buf);
+}
+
+TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf);
+  if (fd > 0)
+    FdAccess(thr, pc, fd);
+  return REAL(__fxstat)(0, fd, buf);
+}
+
+TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
+  if (fd > 0)
+    FdAccess(thr, pc, fd);
+  return REAL(__fxstat64)(version, fd, buf);
+}
+
+TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
+  if (fd > 0)
+    FdAccess(thr, pc, fd);
+  return REAL(__fxstat64)(0, fd, buf);
+}
+
 TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
   SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode);
   int fd = REAL(open)(name, flags, mode);
@@ -1177,6 +1293,22 @@
   return res;
 }
 
+TSAN_INTERCEPTOR(int, bind, int fd, void *addr, unsigned addrlen) {
+  SCOPED_TSAN_INTERCEPTOR(bind, fd, addr, addrlen);
+  int res = REAL(bind)(fd, addr, addrlen);
+  if (fd > 0 && res == 0)
+    FdAccess(thr, pc, fd);
+  return res;
+}
+
+TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
+  SCOPED_TSAN_INTERCEPTOR(listen, fd, backlog);
+  int res = REAL(listen)(fd, backlog);
+  if (fd > 0 && res == 0)
+    FdAccess(thr, pc, fd);
+  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);
@@ -1223,6 +1355,18 @@
   return REAL(__close)(fd);
 }
 
+// glibc guts
+TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
+  SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr);
+  int fds[64];
+  int cnt = ExtractResolvFDs(state, fds, ARRAY_SIZE(fds));
+  for (int i = 0; i < cnt; i++) {
+    if (fds[i] > 0)
+      FdClose(thr, pc, fds[i]);
+  }
+  REAL(__res_iclose)(state, free_addr);
+}
+
 TSAN_INTERCEPTOR(int, pipe, int *pipefd) {
   SCOPED_TSAN_INTERCEPTOR(pipe, pipefd);
   int res = REAL(pipe)(pipefd);
@@ -1765,6 +1909,18 @@
   TSAN_INTERCEPT(sem_post);
   TSAN_INTERCEPT(sem_getvalue);
 
+  TSAN_INTERCEPT(stat);
+  TSAN_INTERCEPT(__xstat);
+  TSAN_INTERCEPT(stat64);
+  TSAN_INTERCEPT(__xstat64);
+  TSAN_INTERCEPT(lstat);
+  TSAN_INTERCEPT(__lxstat);
+  TSAN_INTERCEPT(lstat64);
+  TSAN_INTERCEPT(__lxstat64);
+  TSAN_INTERCEPT(fstat);
+  TSAN_INTERCEPT(__fxstat);
+  TSAN_INTERCEPT(fstat64);
+  TSAN_INTERCEPT(__fxstat64);
   TSAN_INTERCEPT(open);
   TSAN_INTERCEPT(open64);
   TSAN_INTERCEPT(creat);
@@ -1779,11 +1935,15 @@
   TSAN_INTERCEPT(socket);
   TSAN_INTERCEPT(socketpair);
   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);
+  TSAN_INTERCEPT(__close);
+  TSAN_INTERCEPT(__res_iclose);
   TSAN_INTERCEPT(pipe);
   TSAN_INTERCEPT(pipe2);
 
@@ -1826,6 +1986,8 @@
   TSAN_INTERCEPT(munlockall);
 
   TSAN_INTERCEPT(fork);
+  TSAN_INTERCEPT(on_exit);
+  TSAN_INTERCEPT(__cxa_atexit);
 
   // Need to setup it, because interceptors check that the function is resolved.
   // But atexit is emitted directly into the module, so can't be resolved.
@@ -1833,7 +1995,7 @@
   atexit_ctx = new(internal_alloc(MBlockAtExit, sizeof(AtExitContext)))
       AtExitContext();
 
-  if (__cxa_atexit(&finalize, 0, 0)) {
+  if (REAL(__cxa_atexit)(&finalize, 0, 0)) {
     Printf("ThreadSanitizer: failed to setup atexit callback\n");
     Die();
   }
Index: libsanitizer/tsan/tsan_defs.h
===================================================================
--- libsanitizer/tsan/tsan_defs.h	(revision 195997)
+++ libsanitizer/tsan/tsan_defs.h	(working copy)
@@ -26,16 +26,19 @@
 const bool kGoMode = true;
 const bool kCppMode = false;
 const char *const kTsanOptionsEnv = "GORACE";
+// Go linker does not support weak symbols.
+#define CPP_WEAK
 #else
 const bool kGoMode = false;
 const bool kCppMode = true;
 const char *const kTsanOptionsEnv = "TSAN_OPTIONS";
+#define CPP_WEAK WEAK
 #endif
 
 const int kTidBits = 13;
 const unsigned kMaxTid = 1 << kTidBits;
 const unsigned kMaxTidInClock = kMaxTid * 2;  // This includes msb 'freed' bit.
-const int kClkBits = 43;
+const int kClkBits = 42;
 #ifndef TSAN_GO
 const int kShadowStackSize = 4 * 1024;
 const int kTraceStackSize = 256;
Index: libsanitizer/tsan/tsan_rtl_thread.cc
===================================================================
--- libsanitizer/tsan/tsan_rtl_thread.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_rtl_thread.cc	(working copy)
@@ -207,6 +207,9 @@
   thr->shadow_stack_pos = thr->shadow_stack;
   thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
 #endif
+#ifndef TSAN_GO
+  AllocatorThreadStart(thr);
+#endif
   tctx->thr = thr;
   thr->fast_synch_epoch = tctx->epoch0;
   thr->clock.set(tid, tctx->epoch0);
@@ -267,7 +270,7 @@
   tctx->epoch1 = thr->fast_state.epoch();
 
 #ifndef TSAN_GO
-  AlloctorThreadFinish(thr);
+  AllocatorThreadFinish(thr);
 #endif
   thr->~ThreadState();
   StatAggregate(ctx->stat, thr->stat);
@@ -392,7 +395,7 @@
     Shadow cur(fast_state);
     cur.SetWrite(is_write);
     cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
-    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write,
+    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
         shadow_mem, cur);
   }
   if (unaligned)
@@ -403,7 +406,7 @@
     Shadow cur(fast_state);
     cur.SetWrite(is_write);
     cur.SetAddr0AndSizeLog(0, kAccessSizeLog);
-    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write,
+    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
         shadow_mem, cur);
     shadow_mem += kShadowCnt;
   }
@@ -413,24 +416,8 @@
     Shadow cur(fast_state);
     cur.SetWrite(is_write);
     cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
-    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write,
+    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
         shadow_mem, cur);
   }
 }
-
-void MemoryRead1Byte(ThreadState *thr, uptr pc, uptr addr) {
-  MemoryAccess(thr, pc, addr, 0, 0);
-}
-
-void MemoryWrite1Byte(ThreadState *thr, uptr pc, uptr addr) {
-  MemoryAccess(thr, pc, addr, 0, 1);
-}
-
-void MemoryRead8Byte(ThreadState *thr, uptr pc, uptr addr) {
-  MemoryAccess(thr, pc, addr, 3, 0);
-}
-
-void MemoryWrite8Byte(ThreadState *thr, uptr pc, uptr addr) {
-  MemoryAccess(thr, pc, addr, 3, 1);
-}
 }  // namespace __tsan
Index: libsanitizer/tsan/tsan_mman.h
===================================================================
--- libsanitizer/tsan/tsan_mman.h	(revision 195997)
+++ libsanitizer/tsan/tsan_mman.h	(working copy)
@@ -18,7 +18,9 @@
 const uptr kDefaultAlignment = 16;
 
 void InitializeAllocator();
-void AlloctorThreadFinish(ThreadState *thr);
+void AllocatorThreadStart(ThreadState *thr);
+void AllocatorThreadFinish(ThreadState *thr);
+void AllocatorPrintStats();
 
 // For user allocations.
 void *user_alloc(ThreadState *thr, uptr pc, uptr sz,
Index: libsanitizer/tsan/tsan_rtl_report.cc
===================================================================
--- libsanitizer/tsan/tsan_rtl_report.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_rtl_report.cc	(working copy)
@@ -13,6 +13,7 @@
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 #include "tsan_platform.h"
 #include "tsan_rtl.h"
 #include "tsan_suppressions.h"
@@ -27,12 +28,15 @@
 
 using namespace __sanitizer;  // NOLINT
 
+static ReportStack *SymbolizeStack(const StackTrace& trace);
+
 void TsanCheckFailed(const char *file, int line, const char *cond,
                      u64 v1, u64 v2) {
   ScopedInRtl in_rtl;
   Printf("FATAL: ThreadSanitizer CHECK failed: "
          "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
          file, line, cond, (uptr)v1, (uptr)v2);
+  PrintCurrentStackSlow();
   Die();
 }
 
@@ -144,7 +148,8 @@
   mop->tid = s.tid();
   mop->addr = addr + s.addr0();
   mop->size = s.size();
-  mop->write = s.is_write();
+  mop->write = s.IsWrite();
+  mop->atomic = s.IsAtomic();
   mop->stack = SymbolizeStack(*stack);
   for (uptr i = 0; i < mset->Size(); i++) {
     MutexSet::Desc d = mset->Get(i);
@@ -458,9 +463,12 @@
 
 bool OutputReport(Context *ctx,
                   const ScopedReport &srep,
-                  const ReportStack *suppress_stack) {
+                  const ReportStack *suppress_stack1,
+                  const ReportStack *suppress_stack2) {
   const ReportDesc *rep = srep.GetReport();
-  const uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack);
+  uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1);
+  if (suppress_pc == 0)
+    suppress_pc = IsSuppressed(rep->typ, suppress_stack2);
   if (suppress_pc != 0) {
     FiredSuppression supp = {srep.GetReport()->typ, suppress_pc};
     ctx->fired_suppressions.PushBack(supp);
@@ -486,6 +494,13 @@
   return false;
 }
 
+bool FrameIsInternal(const ReportStack *frame) {
+  return frame != 0 && frame->file != 0
+      && (internal_strstr(frame->file, "tsan_interceptors.cc") ||
+          internal_strstr(frame->file, "sanitizer_common_interceptors.inc") ||
+          internal_strstr(frame->file, "tsan_interface_"));
+}
+
 // On programs that use Java we see weird reports like:
 // WARNING: ThreadSanitizer: data race (pid=22512)
 //   Read of size 8 at 0x7d2b00084318 by thread 100:
@@ -495,22 +510,20 @@
 //     #0 strncpy tsan_interceptors.cc:501 (foo+0x00000d8e0919)
 //     #1 <null> <null>:0 (0x7f7ad9b42707)
 static bool IsJavaNonsense(const ReportDesc *rep) {
+#ifndef TSAN_GO
   for (uptr i = 0; i < rep->mops.Size(); i++) {
     ReportMop *mop = rep->mops[i];
     ReportStack *frame = mop->stack;
-    if (frame != 0 && frame->func != 0
-        && (internal_strcmp(frame->func, "memset") == 0
-        || internal_strcmp(frame->func, "memcpy") == 0
-        || internal_strcmp(frame->func, "memmove") == 0
-        || internal_strcmp(frame->func, "strcmp") == 0
-        || internal_strcmp(frame->func, "strncpy") == 0
-        || internal_strcmp(frame->func, "strlen") == 0
-        || internal_strcmp(frame->func, "free") == 0
-        || internal_strcmp(frame->func, "pthread_mutex_lock") == 0)) {
+    if (frame == 0
+        || (frame->func == 0 && frame->file == 0 && frame->line == 0
+          && frame->module == 0)) {
+      return true;
+    }
+    if (FrameIsInternal(frame)) {
       frame = frame->next;
       if (frame == 0
           || (frame->func == 0 && frame->file == 0 && frame->line == 0
-            && frame->module == 0)) {
+          && frame->module == 0)) {
         if (frame) {
           FiredSuppression supp = {rep->typ, frame->pc};
           CTX()->fired_suppressions.PushBack(supp);
@@ -519,14 +532,31 @@
       }
     }
   }
+#endif
   return false;
 }
 
+static bool RaceBetweenAtomicAndFree(ThreadState *thr) {
+  Shadow s0(thr->racy_state[0]);
+  Shadow s1(thr->racy_state[1]);
+  CHECK(!(s0.IsAtomic() && s1.IsAtomic()));
+  if (!s0.IsAtomic() && !s1.IsAtomic())
+    return true;
+  if (s0.IsAtomic() && s1.IsFreed())
+    return true;
+  if (s1.IsAtomic() && thr->is_freeing)
+    return true;
+  return false;
+}
+
 void ReportRace(ThreadState *thr) {
   if (!flags()->report_bugs)
     return;
   ScopedInRtl in_rtl;
 
+  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");
@@ -597,7 +627,8 @@
   }
 #endif
 
-  if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack))
+  if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack,
+                              rep.GetReport()->mops[1]->stack))
     return;
 
   AddRacyStacks(thr, traces, addr_min, addr_max);
@@ -609,4 +640,16 @@
   PrintStack(SymbolizeStack(trace));
 }
 
+void PrintCurrentStackSlow() {
+#ifndef TSAN_GO
+  __sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
+      sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
+  ptrace->SlowUnwindStack(__sanitizer::StackTrace::GetCurrentPc(),
+      kStackTraceMax);
+  StackTrace trace;
+  trace.Init(ptrace->trace, ptrace->size);
+  PrintStack(SymbolizeStack(trace));
+#endif
+}
+
 }  // namespace __tsan
Index: libsanitizer/tsan/tsan_interface_atomic.cc
===================================================================
--- libsanitizer/tsan/tsan_interface_atomic.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_interface_atomic.cc	(working copy)
@@ -18,25 +18,42 @@
 // http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/
 
 #include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 #include "tsan_interface_atomic.h"
 #include "tsan_flags.h"
 #include "tsan_rtl.h"
 
 using namespace __tsan;  // NOLINT
 
+#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__); \
+    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, 1);  // 1 due to our own ScopedInRtl member.
+    CHECK_EQ(thr_->in_rtl, 0);
+    ProcessPendingSignals(thr);
+    FuncEntry(thr_, pc);
     DPrintf("#%d: %s\n", thr_->tid, func);
+    thr_->in_rtl++;
   }
   ~ScopedAtomic() {
-    CHECK_EQ(thr_->in_rtl, 1);
+    thr_->in_rtl--;
+    CHECK_EQ(thr_->in_rtl, 0);
+    FuncExit(thr_);
   }
  private:
   ThreadState *thr_;
-  ScopedInRtl in_rtl_;
 };
 
 // Some shortcuts.
@@ -210,16 +227,19 @@
 }
 #endif
 
-#define SCOPED_ATOMIC(func, ...) \
-    mo = ConvertOrder(mo); \
-    mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
-    ThreadState *const thr = cur_thread(); \
-    ProcessPendingSignals(thr); \
-    const uptr pc = (uptr)__builtin_return_address(0); \
-    AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
-    ScopedAtomic sa(thr, pc, __FUNCTION__); \
-    return Atomic##func(thr, pc, __VA_ARGS__); \
-/**/
+template<typename T>
+static int SizeLog() {
+  if (sizeof(T) <= 1)
+    return kSizeLog1;
+  else if (sizeof(T) <= 2)
+    return kSizeLog2;
+  else if (sizeof(T) <= 4)
+    return kSizeLog4;
+  else
+    return kSizeLog8;
+  // For 16-byte atomics we also use 8-byte memory access,
+  // this leads to false negatives only in very obscure cases.
+}
 
 template<typename T>
 static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a,
@@ -227,14 +247,17 @@
   CHECK(IsLoadOrder(mo));
   // This fast-path is critical for performance.
   // Assume the access is atomic.
-  if (!IsAcquireOrder(mo) && sizeof(T) <= sizeof(a))
+  if (!IsAcquireOrder(mo) && sizeof(T) <= sizeof(a)) {
+    MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
     return *a;
+  }
   SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, false);
   thr->clock.set(thr->tid, thr->fast_state.epoch());
   thr->clock.acquire(&s->clock);
   T v = *a;
   s->mtx.ReadUnlock();
   __sync_synchronize();
+  MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
   return v;
 }
 
@@ -242,6 +265,7 @@
 static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
     morder mo) {
   CHECK(IsStoreOrder(mo));
+  MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
   // This fast-path is critical for performance.
   // Assume the access is atomic.
   // Strictly saying even relaxed store cuts off release sequence,
@@ -263,6 +287,7 @@
 
 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))
@@ -322,6 +347,7 @@
 static bool AtomicCAS(ThreadState *thr, uptr pc,
     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))
Index: libsanitizer/tsan/tsan_interface_ann.h
===================================================================
--- libsanitizer/tsan/tsan_interface_ann.h	(revision 195997)
+++ libsanitizer/tsan/tsan_interface_ann.h	(working copy)
@@ -12,7 +12,7 @@
 #ifndef TSAN_INTERFACE_ANN_H
 #define TSAN_INTERFACE_ANN_H
 
-#include <sanitizer/common_interface_defs.h>
+#include <sanitizer_common/sanitizer_internal_defs.h>
 
 // This header should NOT include any other headers.
 // All functions in this header are extern "C" and start with __tsan_.
Index: libsanitizer/tsan/tsan_flags.h
===================================================================
--- libsanitizer/tsan/tsan_flags.h	(revision 195997)
+++ libsanitizer/tsan/tsan_flags.h	(working copy)
@@ -41,6 +41,8 @@
   // Report violations of async signal-safety
   // (e.g. malloc() call from a signal handler).
   bool report_signal_unsafe;
+  // Report races between atomic and plain memory accesses.
+  bool report_atomic_races;
   // If set, all atomics are effectively sequentially consistent (seq_cst),
   // regardless of what user actually specified.
   bool force_seq_cst_atomics;
@@ -84,6 +86,6 @@
 
 Flags *flags();
 void InitializeFlags(Flags *flags, const char *env);
-}
+}  // namespace __tsan
 
 #endif  // TSAN_FLAGS_H
Index: libsanitizer/tsan/tsan_interface.h
===================================================================
--- libsanitizer/tsan/tsan_interface.h	(revision 195997)
+++ libsanitizer/tsan/tsan_interface.h	(working copy)
@@ -14,7 +14,7 @@
 #ifndef TSAN_INTERFACE_H
 #define TSAN_INTERFACE_H
 
-#include <sanitizer/common_interface_defs.h>
+#include <sanitizer_common/sanitizer_internal_defs.h>
 
 // This header should NOT include any other headers.
 // All functions in this header are extern "C" and start with __tsan_.
Index: libsanitizer/tsan/tsan_platform_linux.cc
===================================================================
--- libsanitizer/tsan/tsan_platform_linux.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_platform_linux.cc	(working copy)
@@ -38,6 +38,8 @@
 #include <errno.h>
 #include <sched.h>
 #include <dlfcn.h>
+#define __need_res_state
+#include <resolv.h>
 
 extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
 
@@ -287,6 +289,19 @@
   return g_data_start && addr >= g_data_start && addr < g_data_end;
 }
 
+#ifndef TSAN_GO
+int ExtractResolvFDs(void *state, int *fds, int nfd) {
+  int cnt = 0;
+  __res_state *statp = (__res_state*)state;
+  for (int i = 0; i < MAXNS && cnt < nfd; i++) {
+    if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1)
+      fds[cnt++] = statp->_u._ext.nssocks[i];
+  }
+  return cnt;
+}
+#endif
+
+
 }  // namespace __tsan
 
 #endif  // #ifdef __linux__
Index: libsanitizer/tsan/tsan_interface_inl.h
===================================================================
--- libsanitizer/tsan/tsan_interface_inl.h	(revision 195997)
+++ libsanitizer/tsan/tsan_interface_inl.h	(working copy)
@@ -17,41 +17,41 @@
 using namespace __tsan;  // NOLINT
 
 void __tsan_read1(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 0, 0);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog1);
 }
 
 void __tsan_read2(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 1, 0);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog2);
 }
 
 void __tsan_read4(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, 0);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog4);
 }
 
 void __tsan_read8(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 3, 0);
+  MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
 }
 
 void __tsan_write1(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 0, 1);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog1);
 }
 
 void __tsan_write2(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 1, 1);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog2);
 }
 
 void __tsan_write4(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, 1);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog4);
 }
 
 void __tsan_write8(void *addr) {
-  MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 3, 1);
+  MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
 }
 
 void __tsan_vptr_update(void **vptr_p, void *new_val) {
   CHECK_EQ(sizeof(vptr_p), 8);
   if (*vptr_p != new_val)
-    MemoryAccess(cur_thread(), CALLERPC, (uptr)vptr_p, 3, 1);
+    MemoryWrite(cur_thread(), CALLERPC, (uptr)vptr_p, kSizeLog8);
 }
 
 void __tsan_func_entry(void *pc) {
Index: libsanitizer/tsan/tsan_stat.cc
===================================================================
--- libsanitizer/tsan/tsan_stat.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_stat.cc	(working copy)
@@ -179,6 +179,18 @@
   name[StatInt_sem_timedwait]            = "  sem_timedwait                   ";
   name[StatInt_sem_post]                 = "  sem_post                        ";
   name[StatInt_sem_getvalue]             = "  sem_getvalue                    ";
+  name[StatInt_stat]                     = "  stat                            ";
+  name[StatInt___xstat]                  = "  __xstat                         ";
+  name[StatInt_stat64]                   = "  stat64                          ";
+  name[StatInt___xstat64]                = "  __xstat64                       ";
+  name[StatInt_lstat]                    = "  lstat                           ";
+  name[StatInt___lxstat]                 = "  __lxstat                        ";
+  name[StatInt_lstat64]                  = "  lstat64                         ";
+  name[StatInt___lxstat64]               = "  __lxstat64                      ";
+  name[StatInt_fstat]                    = "  fstat                           ";
+  name[StatInt___fxstat]                 = "  __fxstat                        ";
+  name[StatInt_fstat64]                  = "  fstat64                         ";
+  name[StatInt___fxstat64]               = "  __fxstat64                      ";
   name[StatInt_open]                     = "  open                            ";
   name[StatInt_open64]                   = "  open64                          ";
   name[StatInt_creat]                    = "  creat                           ";
@@ -193,12 +205,15 @@
   name[StatInt_socket]                   = "  socket                          ";
   name[StatInt_socketpair]               = "  socketpair                      ";
   name[StatInt_connect]                  = "  connect                         ";
+  name[StatInt_bind]                     = "  bind                            ";
+  name[StatInt_listen]                   = "  listen                          ";
   name[StatInt_accept]                   = "  accept                          ";
   name[StatInt_accept4]                  = "  accept4                         ";
   name[StatInt_epoll_create]             = "  epoll_create                    ";
   name[StatInt_epoll_create1]            = "  epoll_create1                   ";
   name[StatInt_close]                    = "  close                           ";
   name[StatInt___close]                  = "  __close                         ";
+  name[StatInt___res_iclose]             = "  __res_iclose                    ";
   name[StatInt_pipe]                     = "  pipe                            ";
   name[StatInt_pipe2]                    = "  pipe2                           ";
   name[StatInt_read]                     = "  read                            ";
@@ -240,6 +255,14 @@
   name[StatInt_scanf]                    = "  scanf                           ";
   name[StatInt_sscanf]                   = "  sscanf                          ";
   name[StatInt_fscanf]                   = "  fscanf                          ";
+  name[StatInt___isoc99_vscanf]          = "  vscanf                          ";
+  name[StatInt___isoc99_vsscanf]         = "  vsscanf                         ";
+  name[StatInt___isoc99_vfscanf]         = "  vfscanf                         ";
+  name[StatInt___isoc99_scanf]           = "  scanf                           ";
+  name[StatInt___isoc99_sscanf]          = "  sscanf                          ";
+  name[StatInt___isoc99_fscanf]          = "  fscanf                          ";
+  name[StatInt_on_exit]                  = "  on_exit                         ";
+  name[StatInt___cxa_atexit]             = "  __cxa_atexit                    ";
 
   name[StatAnnotation]                   = "Dynamic annotations               ";
   name[StatAnnotateHappensBefore]        = "  HappensBefore                   ";
@@ -285,6 +308,7 @@
   name[StatMtxAnnotations]               = "  Annotations                     ";
   name[StatMtxMBlock]                    = "  MBlock                          ";
   name[StatMtxJavaMBlock]                = "  JavaMBlock                      ";
+  name[StatMtxFD]                        = "  FD                              ";
 
   Printf("Statistics:\n");
   for (int i = 0; i < StatCnt; i++)
Index: libsanitizer/tsan/tsan_symbolize.cc
===================================================================
--- libsanitizer/tsan/tsan_symbolize.cc	(revision 195997)
+++ libsanitizer/tsan/tsan_symbolize.cc	(working copy)
@@ -16,9 +16,24 @@
 #include "sanitizer_common/sanitizer_symbolizer.h"
 #include "tsan_flags.h"
 #include "tsan_report.h"
+#include "tsan_rtl.h"
 
 namespace __tsan {
 
+struct ScopedInSymbolizer {
+  ScopedInSymbolizer() {
+    ThreadState *thr = cur_thread();
+    CHECK(!thr->in_symbolizer);
+    thr->in_symbolizer = true;
+  }
+
+  ~ScopedInSymbolizer() {
+    ThreadState *thr = cur_thread();
+    CHECK(thr->in_symbolizer);
+    thr->in_symbolizer = false;
+  }
+};
+
 ReportStack *NewReportStackEntry(uptr addr) {
   ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
                                                   sizeof(ReportStack));
@@ -53,35 +68,36 @@
 }
 
 ReportStack *SymbolizeCode(uptr addr) {
-  if (flags()->external_symbolizer_path[0]) {
-    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);
-    if (addr_frames_num == 0)
-      return NewReportStackEntry(addr);
-    ReportStack *top = 0;
-    ReportStack *bottom = 0;
-    for (uptr i = 0; i < addr_frames_num; i++) {
-      ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
-      CHECK(cur_entry);
-      addr_frames[i].Clear();
-      if (i == 0)
-        top = cur_entry;
-      else
-        bottom->next = cur_entry;
-      bottom = cur_entry;
-    }
-    return top;
+  if (!IsSymbolizerAvailable())
+    return SymbolizeCodeAddr2Line(addr);
+  ScopedInSymbolizer in_symbolizer;
+  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);
+  if (addr_frames_num == 0)
+    return NewReportStackEntry(addr);
+  ReportStack *top = 0;
+  ReportStack *bottom = 0;
+  for (uptr i = 0; i < addr_frames_num; i++) {
+    ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
+    CHECK(cur_entry);
+    addr_frames[i].Clear();
+    if (i == 0)
+      top = cur_entry;
+    else
+      bottom->next = cur_entry;
+    bottom = cur_entry;
   }
-  return SymbolizeCodeAddr2Line(addr);
+  return top;
 }
 
 ReportLocation *SymbolizeData(uptr addr) {
-  if (flags()->external_symbolizer_path[0] == 0)
+  if (!IsSymbolizerAvailable())
     return 0;
+  ScopedInSymbolizer in_symbolizer;
   DataInfo info;
   if (!__sanitizer::SymbolizeData(addr, &info))
     return 0;
Index: libsanitizer/tsan/tsan_stat.h
===================================================================
--- libsanitizer/tsan/tsan_stat.h	(revision 195997)
+++ libsanitizer/tsan/tsan_stat.h	(working copy)
@@ -174,6 +174,18 @@
   StatInt_sem_timedwait,
   StatInt_sem_post,
   StatInt_sem_getvalue,
+  StatInt_stat,
+  StatInt___xstat,
+  StatInt_stat64,
+  StatInt___xstat64,
+  StatInt_lstat,
+  StatInt___lxstat,
+  StatInt_lstat64,
+  StatInt___lxstat64,
+  StatInt_fstat,
+  StatInt___fxstat,
+  StatInt_fstat64,
+  StatInt___fxstat64,
   StatInt_open,
   StatInt_open64,
   StatInt_creat,
@@ -188,12 +200,15 @@
   StatInt_socket,
   StatInt_socketpair,
   StatInt_connect,
+  StatInt_bind,
+  StatInt_listen,
   StatInt_accept,
   StatInt_accept4,
   StatInt_epoll_create,
   StatInt_epoll_create1,
   StatInt_close,
   StatInt___close,
+  StatInt___res_iclose,
   StatInt_pipe,
   StatInt_pipe2,
   StatInt_read,
@@ -239,6 +254,14 @@
   StatInt_scanf,
   StatInt_sscanf,
   StatInt_fscanf,
+  StatInt___isoc99_vscanf,
+  StatInt___isoc99_vsscanf,
+  StatInt___isoc99_vfscanf,
+  StatInt___isoc99_scanf,
+  StatInt___isoc99_sscanf,
+  StatInt___isoc99_fscanf,
+  StatInt_on_exit,
+  StatInt___cxa_atexit,
 
   // Dynamic annotations.
   StatAnnotation,
@@ -287,6 +310,7 @@
   StatMtxAtExit,
   StatMtxMBlock,
   StatMtxJavaMBlock,
+  StatMtxFD,
 
   // This must be the last.
   StatCnt
Index: libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc	(working copy)
@@ -6,139 +6,302 @@
 //===----------------------------------------------------------------------===//
 //
 // Scanf implementation for use in *Sanitizer interceptors.
+// Follows http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html
+// with a few common GNU extensions.
 //
 //===----------------------------------------------------------------------===//
 #include <stdarg.h>
 
-#ifdef _WIN32
-#define va_copy(dst, src) ((dst) = (src))
-#endif  // _WIN32
-
-struct ScanfSpec {
-  char c;
-  unsigned size;
+struct ScanfDirective {
+  int argIdx; // argument index, or -1 of not specified ("%n$")
+  int fieldWidth;
+  bool suppressed; // suppress assignment ("*")
+  bool allocate;   // allocate space ("m")
+  char lengthModifier[2];
+  char convSpecifier;
+  bool maybeGnuMalloc;
 };
 
-// One-letter specs.
-static const ScanfSpec scanf_specs[] = {
-  {'p', sizeof(void *)},
-  {'e', sizeof(float)},
-  {'E', sizeof(float)},
-  {'a', sizeof(float)},
-  {'f', sizeof(float)},
-  {'g', sizeof(float)},
-  {'d', sizeof(int)},
-  {'i', sizeof(int)},
-  {'o', sizeof(int)},
-  {'u', sizeof(int)},
-  {'x', sizeof(int)},
-  {'X', sizeof(int)},
-  {'n', sizeof(int)},
-  {'t', sizeof(PTRDIFF_T)},
-  {'z', sizeof(SIZE_T)},
-  {'j', sizeof(INTMAX_T)},
-  {'h', sizeof(short)}
-};
+static const char *parse_number(const char *p, int *out) {
+  *out = internal_atoll(p);
+  while (*p >= '0' && *p <= '9')
+    ++p;
+  return p;
+}
 
-static const unsigned scanf_specs_cnt =
-  sizeof(scanf_specs) / sizeof(scanf_specs[0]);
-
-// %ll?, %L?, %q? specs
-static const ScanfSpec scanf_llspecs[] = {
-  {'e', sizeof(long double)},
-  {'f', sizeof(long double)},
-  {'g', sizeof(long double)},
-  {'d', sizeof(long long)},
-  {'i', sizeof(long long)},
-  {'o', sizeof(long long)},
-  {'u', sizeof(long long)},
-  {'x', sizeof(long long)}
-};
-
-static const unsigned scanf_llspecs_cnt =
-  sizeof(scanf_llspecs) / sizeof(scanf_llspecs[0]);
-
-// %l? specs
-static const ScanfSpec scanf_lspecs[] = {
-  {'e', sizeof(double)},
-  {'f', sizeof(double)},
-  {'g', sizeof(double)},
-  {'d', sizeof(long)},
-  {'i', sizeof(long)},
-  {'o', sizeof(long)},
-  {'u', sizeof(long)},
-  {'x', sizeof(long)},
-  {'X', sizeof(long)},
-};
-
-static const unsigned scanf_lspecs_cnt =
-  sizeof(scanf_lspecs) / sizeof(scanf_lspecs[0]);
-
-static unsigned match_spec(const struct ScanfSpec *spec, unsigned n, char c) {
-  for (unsigned i = 0; i < n; ++i)
-    if (spec[i].c == c)
-      return spec[i].size;
-  return 0;
+static bool char_is_one_of(char c, const char *s) {
+  return !!internal_strchr(s, c);
 }
 
-static void scanf_common(void *ctx, const char *format, va_list ap_const) {
-  va_list aq;
-  va_copy(aq, ap_const);
+// Parse scanf format string. If a valid directive in encountered, it is
+// returned in dir. This function returns the pointer to the first
+// unprocessed character, or 0 in case of error.
+// In case of the end-of-string, a pointer to the closing \0 is returned.
+static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
+                                    ScanfDirective *dir) {
+  internal_memset(dir, 0, sizeof(*dir));
+  dir->argIdx = -1;
 
-  const char *p = format;
-  unsigned size;
-
   while (*p) {
     if (*p != '%') {
       ++p;
       continue;
     }
     ++p;
-    if (*p == '*' || *p == '%' || *p == 0) {
+    // %%
+    if (*p == '%') {
       ++p;
       continue;
     }
-    if (*p == '0' || (*p >= '1' && *p <= '9')) {
-      size = internal_atoll(p);
-      // +1 for the \0 at the end
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size + 1);
+    if (*p == '\0') {
+      return 0;
+    }
+    // %n$
+    if (*p >= '0' && *p <= '9') {
+      int number;
+      const char *q = parse_number(p, &number);
+      if (*q == '$') {
+        dir->argIdx = number;
+        p = q + 1;
+      }
+      // Otherwise, do not change p. This will be re-parsed later as the field
+      // width.
+    }
+    // *
+    if (*p == '*') {
+      dir->suppressed = true;
       ++p;
-      continue;
     }
-
-    if (*p == 'L' || *p == 'q') {
+    // Field width.
+    if (*p >= '0' && *p <= '9') {
+      p = parse_number(p, &dir->fieldWidth);
+      if (dir->fieldWidth <= 0)
+        return 0;
+    }
+    // m
+    if (*p == 'm') {
+      dir->allocate = true;
       ++p;
-      size = match_spec(scanf_llspecs, scanf_llspecs_cnt, *p);
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
-      continue;
     }
-
-    if (*p == 'l') {
+    // Length modifier.
+    if (char_is_one_of(*p, "jztLq")) {
+      dir->lengthModifier[0] = *p;
       ++p;
+    } else if (*p == 'h') {
+      dir->lengthModifier[0] = 'h';
+      ++p;
+      if (*p == 'h') {
+        dir->lengthModifier[1] = 'h';
+        ++p;
+      }
+    } else if (*p == 'l') {
+      dir->lengthModifier[0] = 'l';
+      ++p;
       if (*p == 'l') {
+        dir->lengthModifier[1] = 'l';
         ++p;
-        size = match_spec(scanf_llspecs, scanf_llspecs_cnt, *p);
-        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
-        continue;
-      } else {
-        size = match_spec(scanf_lspecs, scanf_lspecs_cnt, *p);
-        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
-        continue;
       }
     }
+    // Conversion specifier.
+    dir->convSpecifier = *p++;
+    // Consume %[...] expression.
+    if (dir->convSpecifier == '[') {
+      if (*p == '^')
+        ++p;
+      if (*p == ']')
+        ++p;
+      while (*p && *p != ']')
+        ++p;
+      if (*p == 0)
+        return 0; // unexpected end of string
+                  // Consume the closing ']'.
+      ++p;
+    }
+    // This is unfortunately ambiguous between old GNU extension
+    // of %as, %aS and %a[...] and newer POSIX %a followed by
+    // letters s, S or [.
+    if (allowGnuMalloc && dir->convSpecifier == 'a' &&
+        !dir->lengthModifier[0]) {
+      if (*p == 's' || *p == 'S') {
+        dir->maybeGnuMalloc = true;
+        ++p;
+      } else if (*p == '[') {
+        // Watch for %a[h-j%d], if % appears in the
+        // [...] range, then we need to give up, we don't know
+        // if scanf will parse it as POSIX %a [h-j %d ] or
+        // GNU allocation of string with range dh-j plus %.
+        const char *q = p + 1;
+        if (*q == '^')
+          ++q;
+        if (*q == ']')
+          ++q;
+        while (*q && *q != ']' && *q != '%')
+          ++q;
+        if (*q == 0 || *q == '%')
+          return 0;
+        p = q + 1; // Consume the closing ']'.
+        dir->maybeGnuMalloc = true;
+      }
+    }
+    break;
+  }
+  return p;
+}
 
-    if (*p == 'h' && *(p + 1) == 'h') {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), sizeof(char));
-      p += 2;
-      continue;
+// Returns true if the character is an integer conversion specifier.
+static bool scanf_is_integer_conv(char c) {
+  return char_is_one_of(c, "diouxXn");
+}
+
+// Returns true if the character is an floating point conversion specifier.
+static bool scanf_is_float_conv(char c) {
+  return char_is_one_of(c, "aAeEfFgG");
+}
+
+// Returns string output character size for string-like conversions,
+// or 0 if the conversion is invalid.
+static int scanf_get_char_size(ScanfDirective *dir) {
+  if (char_is_one_of(dir->convSpecifier, "CS")) {
+    // wchar_t
+    return 0;
+  }
+
+  if (char_is_one_of(dir->convSpecifier, "cs[")) {
+    if (dir->lengthModifier[0] == 'l')
+      // wchar_t
+      return 0;
+    else if (dir->lengthModifier[0] == 0)
+      return sizeof(char);
+    else
+      return 0;
+  }
+
+  return 0;
+}
+
+enum ScanfStoreSize {
+  // Store size not known in advance; can be calculated as strlen() of the
+  // destination buffer.
+  SSS_STRLEN = -1,
+  // Invalid conversion specifier.
+  SSS_INVALID = 0
+};
+
+// Returns the store size of a scanf directive (if >0), or a value of
+// ScanfStoreSize.
+static int scanf_get_store_size(ScanfDirective *dir) {
+  if (dir->allocate) {
+    if (!char_is_one_of(dir->convSpecifier, "cCsS["))
+      return SSS_INVALID;
+    return sizeof(char *);
+  }
+
+  if (dir->maybeGnuMalloc) {
+    if (dir->convSpecifier != 'a' || dir->lengthModifier[0])
+      return SSS_INVALID;
+    // This is ambiguous, so check the smaller size of char * (if it is
+    // a GNU extension of %as, %aS or %a[...]) and float (if it is
+    // POSIX %a followed by s, S or [ letters).
+    return sizeof(char *) < sizeof(float) ? sizeof(char *) : sizeof(float);
+  }
+
+  if (scanf_is_integer_conv(dir->convSpecifier)) {
+    switch (dir->lengthModifier[0]) {
+    case 'h':
+      return dir->lengthModifier[1] == 'h' ? sizeof(char) : sizeof(short);
+    case 'l':
+      return dir->lengthModifier[1] == 'l' ? sizeof(long long) : sizeof(long);
+    case 'L':
+      return sizeof(long long);
+    case 'j':
+      return sizeof(INTMAX_T);
+    case 'z':
+      return sizeof(SIZE_T);
+    case 't':
+      return sizeof(PTRDIFF_T);
+    case 0:
+      return sizeof(int);
+    default:
+      return SSS_INVALID;
     }
+  }
 
-    size = match_spec(scanf_specs, scanf_specs_cnt, *p);
-    if (size) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
-      ++p;
+  if (scanf_is_float_conv(dir->convSpecifier)) {
+    switch (dir->lengthModifier[0]) {
+    case 'L':
+    case 'q':
+      return sizeof(long double);
+    case 'l':
+      return dir->lengthModifier[1] == 'l' ? sizeof(long double)
+                                           : sizeof(double);
+    case 0:
+      return sizeof(float);
+    default:
+      return SSS_INVALID;
+    }
+  }
+
+  if (char_is_one_of(dir->convSpecifier, "sS[")) {
+    unsigned charSize = scanf_get_char_size(dir);
+    if (charSize == 0)
+      return SSS_INVALID;
+    if (dir->fieldWidth == 0)
+      return SSS_STRLEN;
+    return (dir->fieldWidth + 1) * charSize;
+  }
+
+  if (char_is_one_of(dir->convSpecifier, "cC")) {
+    unsigned charSize = scanf_get_char_size(dir);
+    if (charSize == 0)
+      return SSS_INVALID;
+    if (dir->fieldWidth == 0)
+      return charSize;
+    return dir->fieldWidth * charSize;
+  }
+
+  if (dir->convSpecifier == 'p') {
+    if (dir->lengthModifier[1] != 0)
+      return SSS_INVALID;
+    return sizeof(void *);
+  }
+
+  return SSS_INVALID;
+}
+
+// Common part of *scanf interceptors.
+// Process format string and va_list, and report all store ranges.
+// Stops when "consuming" n_inputs input items.
+static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
+                         const char *format, va_list aq) {
+  CHECK_GT(n_inputs, 0);
+  const char *p = format;
+
+  while (*p && n_inputs) {
+    ScanfDirective dir;
+    p = scanf_parse_next(p, allowGnuMalloc, &dir);
+    if (!p)
+      break;
+    if (dir.convSpecifier == 0) {
+      // This can only happen at the end of the format string.
+      CHECK_EQ(*p, 0);
+      break;
+    }
+    // Here the directive is valid. Do what it says.
+    if (dir.argIdx != -1) {
+      // Unsupported.
+      break;
+    }
+    if (dir.suppressed)
       continue;
+    int size = scanf_get_store_size(&dir);
+    if (size == SSS_INVALID)
+      break;
+    void *argp = va_arg(aq, void *);
+    if (dir.convSpecifier != 'n')
+      --n_inputs;
+    if (size == SSS_STRLEN) {
+      size = internal_strlen((const char *)argp) + 1;
     }
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
   }
-  va_end(aq);
 }
Index: libsanitizer/sanitizer_common/sanitizer_common.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_common.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_common.cc	(working copy)
@@ -14,6 +14,8 @@
 
 namespace __sanitizer {
 
+const char *SanitizerToolName = "SanitizerTool";
+
 uptr GetPageSizeCached() {
   static uptr PageSize;
   if (!PageSize)
@@ -64,7 +66,7 @@
   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 = internal_open(report_path_full.data(), true);
+  fd_t fd = OpenFile(report_path_full.data(), true);
   if (fd == kInvalidFd) {
     report_fd = kStderrFd;
     log_to_file = false;
@@ -103,7 +105,7 @@
   *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 = internal_open(file_name, /*write*/ false);
+    fd_t fd = OpenFile(file_name, /*write*/ false);
     if (fd == kInvalidFd) return 0;
     UnmapOrDie(*buff, *buff_size);
     *buff = (char*)MmapOrDie(size, __FUNCTION__);
@@ -188,6 +190,16 @@
   return (void*)res;
 }
 
+void ReportErrorSummary(const char *error_type, const char *file,
+                        int line, const char *function) {
+  const int kMaxSize = 1024;  // We don't want a summary too long.
+  InternalScopedBuffer<char> buff(kMaxSize);
+  internal_snprintf(buff.data(), kMaxSize, "%s: %s %s:%d %s",
+                    SanitizerToolName, error_type,
+                    file ? file : "??", line, function ? function : "??");
+  __sanitizer_report_error_summary(buff.data());
+}
+
 }  // namespace __sanitizer
 
 using namespace __sanitizer;  // NOLINT
@@ -220,4 +232,8 @@
   (void)reserved;
   PrepareForSandboxing();
 }
+
+void __sanitizer_report_error_summary(const char *error_summary) {
+  Printf("SUMMARY: %s\n", error_summary);
+}
 }  // extern "C"
Index: libsanitizer/sanitizer_common/sanitizer_lfstack.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_lfstack.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_lfstack.h	(working copy)
@@ -66,6 +66,6 @@
 
   atomic_uint64_t head_;
 };
-}
+}  // namespace __sanitizer
 
 #endif  // #ifndef SANITIZER_LFSTACK_H
Index: libsanitizer/sanitizer_common/sanitizer_posix.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_posix.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_posix.cc	(working copy)
@@ -56,12 +56,12 @@
     if (recursion_count) {
       // The Report() and CHECK calls below may call mmap recursively and fail.
       // If we went into recursion, just die.
-      RawWrite("AddressSanitizer is unable to mmap\n");
+      RawWrite("ERROR: Failed to mmap\n");
       Die();
     }
     recursion_count++;
-    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s: %s\n",
-           size, size, mem_type, strerror(errno));
+    Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %s\n",
+           SanitizerToolName, size, size, mem_type, strerror(errno));
     DumpProcessMap();
     CHECK("unable to mmap" && 0);
   }
@@ -72,8 +72,8 @@
   if (!addr || !size) return;
   int res = internal_munmap(addr, size);
   if (res != 0) {
-    Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
-           size, size, addr);
+    Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
+           SanitizerToolName, size, size, addr);
     CHECK("unable to unmap" && 0);
   }
 }
@@ -86,8 +86,9 @@
       MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
       -1, 0);
   if (p == (void*)-1)
-    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
-           size, size, fixed_addr, errno);
+    Report("ERROR: "
+           "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
+           SanitizerToolName, size, size, fixed_addr, errno);
   return p;
 }
 
@@ -99,8 +100,9 @@
       MAP_PRIVATE | MAP_ANON | MAP_FIXED,
       -1, 0);
   if (p == (void*)-1) {
-    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
-           size, size, fixed_addr, errno);
+    Report("ERROR:"
+           " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
+           SanitizerToolName, size, size, fixed_addr, errno);
     CHECK("unable to mmap" && 0);
   }
   return p;
@@ -118,7 +120,7 @@
 }
 
 void *MapFileToMemory(const char *file_name, uptr *buff_size) {
-  fd_t fd = internal_open(file_name, false);
+  fd_t fd = OpenFile(file_name, false);
   CHECK_NE(fd, kInvalidFd);
   uptr fsize = internal_filesize(fd);
   CHECK_NE(fsize, (uptr)-1);
@@ -187,7 +189,7 @@
   rlim.rlim_cur = limit;
   rlim.rlim_max = limit;
   if (setrlimit(RLIMIT_STACK, &rlim)) {
-    Report("setrlimit() failed %d\n", errno);
+    Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
     Die();
   }
   CHECK(!StackSizeIsUnlimited());
Index: libsanitizer/sanitizer_common/sanitizer_stackdepot.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_stackdepot.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_stackdepot.h	(working copy)
@@ -11,7 +11,7 @@
 #ifndef SANITIZER_STACKDEPOT_H
 #define SANITIZER_STACKDEPOT_H
 
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_internal_defs.h"
 
 namespace __sanitizer {
 
Index: libsanitizer/sanitizer_common/sanitizer_libc.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_libc.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_libc.cc	(working copy)
@@ -204,7 +204,7 @@
 }
 
 bool mem_is_zero(const char *beg, uptr size) {
-  CHECK_LE(size, 1UL << FIRST_32_SECOND_64(30, 40));  // Sanity check.
+  CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40));  // Sanity check.
   const char *end = beg + size;
   uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr));
   uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr));
Index: libsanitizer/sanitizer_common/sanitizer_quarantine.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_quarantine.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_quarantine.h	(working copy)
@@ -157,7 +157,7 @@
     atomic_store(&size_, Size() + add, memory_order_relaxed);
   }
 
-  QuarantineBatch *NOINLINE AllocBatch(Callback cb) {
+  NOINLINE QuarantineBatch* AllocBatch(Callback cb) {
     QuarantineBatch *b = (QuarantineBatch *)cb.Allocate(sizeof(*b));
     b->count = 0;
     b->size = 0;
@@ -165,6 +165,6 @@
     return b;
   }
 };
-}
+}  // namespace __sanitizer
 
 #endif  // #ifndef SANITIZER_QUARANTINE_H
Index: libsanitizer/sanitizer_common/sanitizer_libc.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_libc.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_libc.h	(working copy)
@@ -9,14 +9,13 @@
 // run-time libraries.
 // These tools can not use some of the libc functions directly because those
 // functions are intercepted. Instead, we implement a tiny subset of libc here.
-// NOTE: This file may be included into user code.
 //===----------------------------------------------------------------------===//
 #ifndef SANITIZER_LIBC_H
 #define SANITIZER_LIBC_H
 
 // ----------- ATTENTION -------------
 // This header should NOT include any other headers from sanitizer runtime.
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_internal_defs.h"
 
 namespace __sanitizer {
 
@@ -56,17 +55,24 @@
 int internal_munmap(void *addr, uptr length);
 
 // I/O
-typedef int fd_t;
 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);
 int internal_isatty(fd_t fd);
-fd_t internal_open(const char *filename, bool write);
+
+// 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_read(fd_t fd, void *buf, uptr count);
 uptr internal_write(fd_t fd, const void *buf, uptr count);
 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, ...);
Index: libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc	(working copy)
@@ -22,9 +22,13 @@
 
 #include <stdarg.h>
 
+#ifdef _WIN32
+#define va_copy(dst, src) ((dst) = (src))
+#endif // _WIN32
+
 #if SANITIZER_INTERCEPT_READ
 INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
-  void* ctx;
+  void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, count);
   SSIZE_T res = REAL(read)(fd, ptr, count);
   if (res > 0)
@@ -33,14 +37,14 @@
     COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
 }
-# define INIT_READ INTERCEPT_FUNCTION(read)
+#define INIT_READ INTERCEPT_FUNCTION(read)
 #else
-# define INIT_READ
+#define INIT_READ
 #endif
 
 #if SANITIZER_INTERCEPT_PREAD
 INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
-  void* ctx;
+  void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, offset);
   SSIZE_T res = REAL(pread)(fd, ptr, count, offset);
   if (res > 0)
@@ -49,14 +53,14 @@
     COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
 }
-# define INIT_PREAD INTERCEPT_FUNCTION(pread)
+#define INIT_PREAD INTERCEPT_FUNCTION(pread)
 #else
-# define INIT_PREAD
+#define INIT_PREAD
 #endif
 
 #if SANITIZER_INTERCEPT_PREAD64
 INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
-  void* ctx;
+  void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, offset);
   SSIZE_T res = REAL(pread64)(fd, ptr, count, offset);
   if (res > 0)
@@ -65,14 +69,14 @@
     COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
 }
-# define INIT_PREAD64 INTERCEPT_FUNCTION(pread64)
+#define INIT_PREAD64 INTERCEPT_FUNCTION(pread64)
 #else
-# define INIT_PREAD64
+#define INIT_PREAD64
 #endif
 
 #if SANITIZER_INTERCEPT_WRITE
 INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
-  void* ctx;
+  void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count);
   if (fd >= 0)
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
@@ -81,142 +85,154 @@
     COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
   return res;
 }
-# define INIT_WRITE INTERCEPT_FUNCTION(write)
+#define INIT_WRITE INTERCEPT_FUNCTION(write)
 #else
-# define INIT_WRITE
+#define INIT_WRITE
 #endif
 
 #if SANITIZER_INTERCEPT_PWRITE
-INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count) {
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count);
+INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count, offset);
   if (fd >= 0)
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
-  SSIZE_T res = REAL(pwrite)(fd, ptr, count);
+  SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset);
   if (res > 0)
     COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
   return res;
 }
-# define INIT_PWRITE INTERCEPT_FUNCTION(pwrite)
+#define INIT_PWRITE INTERCEPT_FUNCTION(pwrite)
 #else
-# define INIT_PWRITE
+#define INIT_PWRITE
 #endif
 
 #if SANITIZER_INTERCEPT_PWRITE64
-INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count) {
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count);
+INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count,
+            OFF64_T offset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count, offset);
   if (fd >= 0)
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
-  SSIZE_T res = REAL(pwrite64)(fd, ptr, count);
+  SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset);
   if (res > 0)
     COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
   return res;
 }
-# define INIT_PWRITE64 INTERCEPT_FUNCTION(pwrite64)
+#define INIT_PWRITE64 INTERCEPT_FUNCTION(pwrite64)
 #else
-# define INIT_PWRITE64
+#define INIT_PWRITE64
 #endif
 
 #if SANITIZER_INTERCEPT_PRCTL
-INTERCEPTOR(int, prctl, int option,
-            unsigned long arg2, unsigned long arg3,  // NOLINT
-            unsigned long arg4, unsigned long arg5) {  // NOLINT
-  void* ctx;
+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);
   static const int PR_SET_NAME = 15;
   int res = REAL(prctl(option, arg2, arg3, arg4, arg5));
   if (option == PR_SET_NAME) {
     char buff[16];
-    internal_strncpy(buff, (char*)arg2, 15);
+    internal_strncpy(buff, (char *)arg2, 15);
     buff[15] = 0;
     COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, buff);
   }
   return res;
 }
-# define INIT_PRCTL INTERCEPT_FUNCTION(prctl)
+#define INIT_PRCTL INTERCEPT_FUNCTION(prctl)
 #else
-# define INIT_PRCTL
-#endif  // SANITIZER_INTERCEPT_PRCTL
+#define INIT_PRCTL
+#endif // SANITIZER_INTERCEPT_PRCTL
 
-
 #if SANITIZER_INTERCEPT_SCANF
 
 #include "sanitizer_common_interceptors_scanf.inc"
 
-INTERCEPTOR(int, vscanf, const char *format, va_list ap) {  // NOLINT
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, vscanf, format, ap);
-  scanf_common(ctx, format, ap);
-  int res = REAL(vscanf)(format, ap);  // NOLINT
-  return res;
-}
+#define VSCANF_INTERCEPTOR_IMPL(vname, allowGnuMalloc, ...)                    \
+  {                                                                            \
+    void *ctx;                                                                 \
+    COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__);                         \
+    va_list aq;                                                                \
+    va_copy(aq, ap);                                                           \
+    int res = REAL(vname)(__VA_ARGS__);                                        \
+    if (res > 0)                                                               \
+      scanf_common(ctx, res, allowGnuMalloc, format, aq);                      \
+    va_end(aq);                                                                \
+    return res;                                                                \
+  }
 
-INTERCEPTOR(int, vsscanf, const char *str, const char *format,  // NOLINT
-    va_list ap) {
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, vsscanf, str, format, ap);
-  scanf_common(ctx, format, ap);
-  int res = REAL(vsscanf)(str, format, ap);  // NOLINT
-  // FIXME: read of str
-  return res;
-}
+INTERCEPTOR(int, vscanf, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vscanf, true, format, ap)
 
-INTERCEPTOR(int, vfscanf, void *stream, const char *format,  // NOLINT
-    va_list ap) {
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, vfscanf, stream, format, ap);
-  scanf_common(ctx, format, ap);
-  int res = REAL(vfscanf)(stream, format, ap);  // NOLINT
-  return res;
-}
+INTERCEPTOR(int, vsscanf, const char *str, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vsscanf, true, str, format, ap)
 
-INTERCEPTOR(int, scanf, const char *format, ...) {  // NOLINT
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, scanf, format);
-  va_list ap;
-  va_start(ap, format);
-  int res = vscanf(format, ap);  // NOLINT
-  va_end(ap);
-  return res;
-}
+INTERCEPTOR(int, vfscanf, void *stream, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vfscanf, true, stream, format, ap)
 
-INTERCEPTOR(int, fscanf, void* stream, const char *format, ...) {  // NOLINT
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, fscanf, stream, format);
-  va_list ap;
-  va_start(ap, format);
-  int res = vfscanf(stream, format, ap);  // NOLINT
-  va_end(ap);
-  return res;
-}
+INTERCEPTOR(int, __isoc99_vscanf, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vscanf, false, format, ap)
 
-INTERCEPTOR(int, sscanf, const char *str, const char *format, ...) {  // NOLINT
-  void* ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, sscanf, str, format);  // NOLINT
-  va_list ap;
-  va_start(ap, format);
-  int res = vsscanf(str, format, ap);  // NOLINT
-  va_end(ap);
-  return res;
-}
+INTERCEPTOR(int, __isoc99_vsscanf, const char *str, const char *format,
+            va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vsscanf, false, str, format, ap)
 
-#define INIT_SCANF \
-  INTERCEPT_FUNCTION(scanf);                    \
-  INTERCEPT_FUNCTION(sscanf);  /* NOLINT */     \
-  INTERCEPT_FUNCTION(fscanf);                   \
-  INTERCEPT_FUNCTION(vscanf);                   \
-  INTERCEPT_FUNCTION(vsscanf);                  \
-  INTERCEPT_FUNCTION(vfscanf)
+INTERCEPTOR(int, __isoc99_vfscanf, void *stream, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
 
+#define SCANF_INTERCEPTOR_IMPL(name, vname, ...)                               \
+  {                                                                            \
+    void *ctx;                                                                 \
+    COMMON_INTERCEPTOR_ENTER(ctx, name, __VA_ARGS__);                          \
+    va_list ap;                                                                \
+    va_start(ap, format);                                                      \
+    int res = vname(__VA_ARGS__, ap);                                          \
+    va_end(ap);                                                                \
+    return res;                                                                \
+  }
+
+INTERCEPTOR(int, scanf, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(scanf, vscanf, format)
+
+INTERCEPTOR(int, fscanf, void *stream, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
+
+INTERCEPTOR(int, sscanf, const char *str, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
+
+INTERCEPTOR(int, __isoc99_scanf, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
+
+INTERCEPTOR(int, __isoc99_fscanf, void *stream, const char *format, ...)
+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)
+
+#define INIT_SCANF                                                             \
+  INTERCEPT_FUNCTION(scanf);                                                   \
+  INTERCEPT_FUNCTION(sscanf);                                                  \
+  INTERCEPT_FUNCTION(fscanf);                                                  \
+  INTERCEPT_FUNCTION(vscanf);                                                  \
+  INTERCEPT_FUNCTION(vsscanf);                                                 \
+  INTERCEPT_FUNCTION(vfscanf);                                                 \
+  INTERCEPT_FUNCTION(__isoc99_scanf);                                          \
+  INTERCEPT_FUNCTION(__isoc99_sscanf);                                         \
+  INTERCEPT_FUNCTION(__isoc99_fscanf);                                         \
+  INTERCEPT_FUNCTION(__isoc99_vscanf);                                         \
+  INTERCEPT_FUNCTION(__isoc99_vsscanf);                                        \
+  INTERCEPT_FUNCTION(__isoc99_vfscanf);
+
 #else
 #define INIT_SCANF
 #endif
 
-#define SANITIZER_COMMON_INTERCEPTORS_INIT \
-  INIT_READ;                               \
-  INIT_PREAD;                              \
-  INIT_PREAD64;                            \
-  INIT_PRCTL;                              \
-  INIT_WRITE;                              \
+#define SANITIZER_COMMON_INTERCEPTORS_INIT                                     \
+  INIT_READ;                                                                   \
+  INIT_PREAD;                                                                  \
+  INIT_PREAD64;                                                                \
+  INIT_PRCTL;                                                                  \
+  INIT_WRITE;                                                                  \
+  INIT_PWRITE;                                                                 \
+  INIT_PWRITE64;                                                               \
   INIT_SCANF;
Index: libsanitizer/sanitizer_common/sanitizer_allocator.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_allocator.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_allocator.h	(working copy)
@@ -23,9 +23,9 @@
 
 // SizeClassMap maps allocation sizes into size classes and back.
 // Class 0 corresponds to size 0.
-// Classes 1 - 16 correspond to sizes 8 - 128 (size = class_id * 8).
-// Next 8 classes: 128 + i * 16 (i = 1 to 8).
+// Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
 // Next 8 classes: 256 + i * 32 (i = 1 to 8).
+// Next 8 classes: 512 + i * 64 (i = 1 to 8).
 // ...
 // Next 8 classes: 2^k + i * 2^(k-3) (i = 1 to 8).
 // Last class corresponds to kMaxSize = 1 << kMaxSizeLog.
@@ -40,33 +40,48 @@
 //  - (1 << kMaxBytesCachedLog) is the maximal number of bytes per size class.
 //
 // Part of output of SizeClassMap::Print():
-//    c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
-//    c01 => s: 8 diff: +8 00% l 3 cached: 256 2048; id 1
-//    c02 => s: 16 diff: +8 100% l 4 cached: 256 4096; id 2
-//    ...
-//    c07 => s: 56 diff: +8 16% l 5 cached: 256 14336; id 7
+// c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
+// c01 => s: 16 diff: +16 00% l 4 cached: 256 4096; id 1
+// c02 => s: 32 diff: +16 100% l 5 cached: 256 8192; id 2
+// c03 => s: 48 diff: +16 50% l 5 cached: 256 12288; id 3
+// c04 => s: 64 diff: +16 33% l 6 cached: 256 16384; id 4
+// c05 => s: 80 diff: +16 25% l 6 cached: 256 20480; id 5
+// c06 => s: 96 diff: +16 20% l 6 cached: 256 24576; id 6
+// c07 => s: 112 diff: +16 16% l 6 cached: 256 28672; id 7
 //
-//    c08 => s: 64 diff: +8 14% l 6 cached: 256 16384; id 8
-//    ...
-//    c15 => s: 120 diff: +8 07% l 6 cached: 256 30720; id 15
+// c08 => s: 128 diff: +16 14% l 7 cached: 256 32768; id 8
+// c09 => s: 144 diff: +16 12% l 7 cached: 256 36864; id 9
+// c10 => s: 160 diff: +16 11% l 7 cached: 256 40960; id 10
+// c11 => s: 176 diff: +16 10% l 7 cached: 256 45056; id 11
+// c12 => s: 192 diff: +16 09% l 7 cached: 256 49152; id 12
+// c13 => s: 208 diff: +16 08% l 7 cached: 256 53248; id 13
+// c14 => s: 224 diff: +16 07% l 7 cached: 256 57344; id 14
+// c15 => s: 240 diff: +16 07% l 7 cached: 256 61440; id 15
 //
-//    c16 => s: 128 diff: +8 06% l 7 cached: 256 32768; id 16
-//    c17 => s: 144 diff: +16 12% l 7 cached: 227 32688; id 17
-//    ...
-//    c23 => s: 240 diff: +16 07% l 7 cached: 136 32640; id 23
+// c16 => s: 256 diff: +16 06% l 8 cached: 256 65536; id 16
+// c17 => s: 288 diff: +32 12% l 8 cached: 227 65376; id 17
+// c18 => s: 320 diff: +32 11% l 8 cached: 204 65280; id 18
+// c19 => s: 352 diff: +32 10% l 8 cached: 186 65472; id 19
+// c20 => s: 384 diff: +32 09% l 8 cached: 170 65280; id 20
+// c21 => s: 416 diff: +32 08% l 8 cached: 157 65312; id 21
+// c22 => s: 448 diff: +32 07% l 8 cached: 146 65408; id 22
+// c23 => s: 480 diff: +32 07% l 8 cached: 136 65280; id 23
 //
-//    c24 => s: 256 diff: +16 06% l 8 cached: 128 32768; id 24
-//    c25 => s: 288 diff: +32 12% l 8 cached: 113 32544; id 25
-//    ...
-//    c31 => s: 480 diff: +32 07% l 8 cached: 68 32640; id 31
+// c24 => s: 512 diff: +32 06% l 9 cached: 128 65536; id 24
+// c25 => s: 576 diff: +64 12% l 9 cached: 113 65088; id 25
+// c26 => s: 640 diff: +64 11% l 9 cached: 102 65280; id 26
+// c27 => s: 704 diff: +64 10% l 9 cached: 93 65472; id 27
+// c28 => s: 768 diff: +64 09% l 9 cached: 85 65280; id 28
+// c29 => s: 832 diff: +64 08% l 9 cached: 78 64896; id 29
+// c30 => s: 896 diff: +64 07% l 9 cached: 73 65408; id 30
+// c31 => s: 960 diff: +64 07% l 9 cached: 68 65280; id 31
 //
-//    c32 => s: 512 diff: +32 06% l 9 cached: 64 32768; id 32
+// c32 => s: 1024 diff: +64 06% l 10 cached: 64 65536; id 32
 
-
 template <uptr kMaxSizeLog, uptr kMaxNumCachedT, uptr kMaxBytesCachedLog,
           uptr kMinBatchClassT>
 class SizeClassMap {
-  static const uptr kMinSizeLog = 3;
+  static const uptr kMinSizeLog = 4;
   static const uptr kMidSizeLog = kMinSizeLog + 4;
   static const uptr kMinSize = 1 << kMinSizeLog;
   static const uptr kMidSize = 1 << kMidSizeLog;
@@ -104,7 +119,7 @@
     if (size <= kMidSize)
       return (size + kMinSize - 1) >> kMinSizeLog;
     if (size > kMaxSize) return 0;
-    uptr l = SANITIZER_WORDSIZE - 1 - __builtin_clzl(size);
+    uptr l = MostSignificantSetBitIndex(size);
     uptr hbits = (size >> (l - S)) & M;
     uptr lbits = size & ((1 << (l - S)) - 1);
     uptr l1 = l - kMidSizeLog;
@@ -114,7 +129,7 @@
   static uptr MaxCached(uptr class_id) {
     if (class_id == 0) return 0;
     uptr n = (1UL << kMaxBytesCachedLog) / Size(class_id);
-    return Max(1UL, Min(kMaxNumCached, n));
+    return Max<uptr>(1, Min(kMaxNumCached, n));
   }
 
   static void Print() {
@@ -126,7 +141,7 @@
         Printf("\n");
       uptr d = s - prev_s;
       uptr p = prev_s ? (d * 100 / prev_s) : 0;
-      uptr l = SANITIZER_WORDSIZE - 1 - __builtin_clzl(s);
+      uptr l = MostSignificantSetBitIndex(s);
       uptr cached = MaxCached(i) * s;
       Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd "
              "cached: %zd %zd; id %zd\n",
@@ -172,12 +187,92 @@
   }
 };
 
-typedef SizeClassMap<17, 256, 16, FIRST_32_SECOND_64(33, 36)>
+typedef SizeClassMap<17, 256, 16, FIRST_32_SECOND_64(25, 28)>
     DefaultSizeClassMap;
-typedef SizeClassMap<17, 64, 14, FIRST_32_SECOND_64(25, 28)>
+typedef SizeClassMap<17, 64, 14, FIRST_32_SECOND_64(17, 20)>
     CompactSizeClassMap;
 template<class SizeClassAllocator> struct SizeClassAllocatorLocalCache;
 
+// Memory allocator statistics
+enum AllocatorStat {
+  AllocatorStatMalloced,
+  AllocatorStatFreed,
+  AllocatorStatMmapped,
+  AllocatorStatUnmapped,
+  AllocatorStatCount
+};
+
+typedef u64 AllocatorStatCounters[AllocatorStatCount];
+
+// Per-thread stats, live in per-thread cache.
+class AllocatorStats {
+ public:
+  void Init() {
+    internal_memset(this, 0, sizeof(*this));
+  }
+
+  void Add(AllocatorStat i, u64 v) {
+    v += atomic_load(&stats_[i], memory_order_relaxed);
+    atomic_store(&stats_[i], v, memory_order_relaxed);
+  }
+
+  void Set(AllocatorStat i, u64 v) {
+    atomic_store(&stats_[i], v, memory_order_relaxed);
+  }
+
+  u64 Get(AllocatorStat i) const {
+    return atomic_load(&stats_[i], memory_order_relaxed);
+  }
+
+ private:
+  friend class AllocatorGlobalStats;
+  AllocatorStats *next_;
+  AllocatorStats *prev_;
+  atomic_uint64_t stats_[AllocatorStatCount];
+};
+
+// Global stats, used for aggregation and querying.
+class AllocatorGlobalStats : public AllocatorStats {
+ public:
+  void Init() {
+    internal_memset(this, 0, sizeof(*this));
+    next_ = this;
+    prev_ = this;
+  }
+
+  void Register(AllocatorStats *s) {
+    SpinMutexLock l(&mu_);
+    s->next_ = next_;
+    s->prev_ = this;
+    next_->prev_ = s;
+    next_ = s;
+  }
+
+  void Unregister(AllocatorStats *s) {
+    SpinMutexLock l(&mu_);
+    s->prev_->next_ = s->next_;
+    s->next_->prev_ = s->prev_;
+    for (int i = 0; i < AllocatorStatCount; i++)
+      Add(AllocatorStat(i), s->Get(AllocatorStat(i)));
+  }
+
+  void Get(AllocatorStatCounters s) const {
+    internal_memset(s, 0, AllocatorStatCount * sizeof(u64));
+    SpinMutexLock l(&mu_);
+    const AllocatorStats *stats = this;
+    for (;;) {
+      for (int i = 0; i < AllocatorStatCount; i++)
+        s[i] += stats->Get(AllocatorStat(i));
+      stats = stats->next_;
+      if (stats == this)
+        break;
+    }
+  }
+
+ private:
+  mutable SpinMutex mu_;
+};
+
 // Allocators call these callbacks on mmap/munmap.
 struct NoOpMapUnmapCallback {
   void OnMap(uptr p, uptr size) const { }
@@ -231,17 +326,18 @@
       alignment <= SizeClassMap::kMaxSize;
   }
 
-  Batch *NOINLINE AllocateBatch(AllocatorCache *c, uptr class_id) {
+  NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
+                                uptr class_id) {
     CHECK_LT(class_id, kNumClasses);
     RegionInfo *region = GetRegionInfo(class_id);
     Batch *b = region->free_list.Pop();
     if (b == 0)
-      b = PopulateFreeList(c, class_id, region);
+      b = PopulateFreeList(stat, c, class_id, region);
     region->n_allocated += b->count;
     return b;
   }
 
-  void NOINLINE DeallocateBatch(uptr class_id, Batch *b) {
+  NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
     RegionInfo *region = GetRegionInfo(class_id);
     region->free_list.Push(b);
     region->n_freed += b->count;
@@ -320,6 +416,20 @@
     }
   }
 
+  // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+  // introspection API.
+  void ForceLock() {
+    for (uptr i = 0; i < kNumClasses; i++) {
+      GetRegionInfo(i)->mutex.Lock();
+    }
+  }
+
+  void ForceUnlock() {
+    for (int i = (int)kNumClasses - 1; i >= 0; i--) {
+      GetRegionInfo(i)->mutex.Unlock();
+    }
+  }
+
   typedef SizeClassMap SizeClassMapT;
   static const uptr kNumClasses = SizeClassMap::kNumClasses;
   static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
@@ -334,7 +444,7 @@
   // or with one element if its size is greater.
   static const uptr kPopulateSize = 1 << 14;
   // Call mmap for user memory with at least this size.
-  static const uptr kUserMapSize = 1 << 15;
+  static const uptr kUserMapSize = 1 << 16;
   // Call mmap for metadata memory with at least this size.
   static const uptr kMetaMapSize = 1 << 16;
 
@@ -368,8 +478,8 @@
     return offset / (u32)size;
   }
 
-  Batch *NOINLINE PopulateFreeList(AllocatorCache *c, uptr class_id,
-                                   RegionInfo *region) {
+  NOINLINE Batch* PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+                                   uptr class_id, RegionInfo *region) {
     BlockingMutexLock l(&region->mutex);
     Batch *b = region->free_list.Pop();
     if (b)
@@ -386,6 +496,7 @@
         map_size += kUserMapSize;
       CHECK_GE(region->mapped_user + map_size, end_idx);
       MapWithCallback(region_beg + region->mapped_user, map_size);
+      stat->Add(AllocatorStatMmapped, map_size);
       region->mapped_user += map_size;
     }
     uptr total_count = (region->mapped_user - beg_idx - size)
@@ -467,6 +578,7 @@
     MapUnmapCallback().OnMap((uptr)res, size);
     return res;
   }
+
   void UnmapWithCallback(uptr beg, uptr size) {
     MapUnmapCallback().OnUnmap(beg, size);
     UnmapOrDie(reinterpret_cast<void *>(beg), size);
@@ -488,19 +600,20 @@
     return reinterpret_cast<void*>(meta);
   }
 
-  Batch *NOINLINE AllocateBatch(AllocatorCache *c, uptr class_id) {
+  NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
+                                uptr class_id) {
     CHECK_LT(class_id, kNumClasses);
     SizeClassInfo *sci = GetSizeClassInfo(class_id);
     SpinMutexLock l(&sci->mutex);
     if (sci->free_list.empty())
-      PopulateFreeList(c, sci, class_id);
+      PopulateFreeList(stat, c, sci, class_id);
     CHECK(!sci->free_list.empty());
     Batch *b = sci->free_list.front();
     sci->free_list.pop_front();
     return b;
   }
 
-  void NOINLINE DeallocateBatch(uptr class_id, Batch *b) {
+  NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
     CHECK_LT(class_id, kNumClasses);
     SizeClassInfo *sci = GetSizeClassInfo(class_id);
     SpinMutexLock l(&sci->mutex);
@@ -549,6 +662,20 @@
     UnmapWithCallback(reinterpret_cast<uptr>(state_), sizeof(State));
   }
 
+  // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+  // introspection API.
+  void ForceLock() {
+    for (uptr i = 0; i < kNumClasses; i++) {
+      GetSizeClassInfo(i)->mutex.Lock();
+    }
+  }
+
+  void ForceUnlock() {
+    for (int i = kNumClasses - 1; i >= 0; i--) {
+      GetSizeClassInfo(i)->mutex.Unlock();
+    }
+  }
+
   void PrintStats() {
   }
 
@@ -577,11 +704,12 @@
     return mem & ~(kRegionSize - 1);
   }
 
-  uptr AllocateRegion(uptr class_id) {
+  uptr AllocateRegion(AllocatorStats *stat, uptr class_id) {
     CHECK_LT(class_id, kNumClasses);
     uptr res = reinterpret_cast<uptr>(MmapAlignedOrDie(kRegionSize, kRegionSize,
                                       "SizeClassAllocator32"));
     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;
@@ -593,9 +721,10 @@
     return &state_->size_class_info_array[class_id];
   }
 
-  void PopulateFreeList(AllocatorCache *c, SizeClassInfo *sci, uptr class_id) {
+  void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+                        SizeClassInfo *sci, uptr class_id) {
     uptr size = SizeClassMap::Size(class_id);
-    uptr reg = AllocateRegion(class_id);
+    uptr reg = AllocateRegion(stat, class_id);
     uptr n_chunks = kRegionSize / (size + kMetadataSize);
     uptr max_count = SizeClassMap::MaxCached(class_id);
     Batch *b = 0;
@@ -632,14 +761,22 @@
   typedef SizeClassAllocator Allocator;
   static const uptr kNumClasses = SizeClassAllocator::kNumClasses;
 
-  // Don't need to call Init if the object is a global (i.e. zero-initialized).
-  void Init() {
-    internal_memset(this, 0, sizeof(*this));
+  void Init(AllocatorGlobalStats *s) {
+    stats_.Init();
+    if (s)
+      s->Register(&stats_);
   }
 
+  void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) {
+    Drain(allocator);
+    if (s)
+      s->Unregister(&stats_);
+  }
+
   void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
     CHECK_NE(class_id, 0UL);
     CHECK_LT(class_id, kNumClasses);
+    stats_.Add(AllocatorStatMalloced, SizeClassMap::Size(class_id));
     PerClass *c = &per_class_[class_id];
     if (UNLIKELY(c->count == 0))
       Refill(allocator, class_id);
@@ -651,6 +788,7 @@
   void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) {
     CHECK_NE(class_id, 0UL);
     CHECK_LT(class_id, kNumClasses);
+    stats_.Add(AllocatorStatFreed, SizeClassMap::Size(class_id));
     PerClass *c = &per_class_[class_id];
     if (UNLIKELY(c->count == c->max_count))
       Drain(allocator, class_id);
@@ -674,6 +812,7 @@
     void *batch[2 * SizeClassMap::kMaxNumCached];
   };
   PerClass per_class_[kNumClasses];
+  AllocatorStats stats_;
 
   void InitCache() {
     if (per_class_[0].max_count)
@@ -684,10 +823,11 @@
     }
   }
 
-  void NOINLINE Refill(SizeClassAllocator *allocator, uptr class_id) {
+  NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) {
     InitCache();
     PerClass *c = &per_class_[class_id];
-    Batch *b = allocator->AllocateBatch(this, class_id);
+    Batch *b = allocator->AllocateBatch(&stats_, this, class_id);
+    CHECK_GT(b->count, 0);
     for (uptr i = 0; i < b->count; i++)
       c->batch[i] = b->batch[i];
     c->count = b->count;
@@ -695,7 +835,7 @@
       Deallocate(allocator, SizeClassMap::ClassID(sizeof(Batch)), b);
   }
 
-  void NOINLINE Drain(SizeClassAllocator *allocator, uptr class_id) {
+  NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) {
     InitCache();
     PerClass *c = &per_class_[class_id];
     Batch *b;
@@ -710,7 +850,7 @@
     }
     b->count = cnt;
     c->count -= cnt;
-    allocator->DeallocateBatch(class_id, b);
+    allocator->DeallocateBatch(&stats_, class_id, b);
   }
 };
 
@@ -725,7 +865,7 @@
     page_size_ = GetPageSizeCached();
   }
 
-  void *Allocate(uptr size, uptr alignment) {
+  void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) {
     CHECK(IsPowerOfTwo(alignment));
     uptr map_size = RoundUpMapSize(size);
     if (alignment > page_size_)
@@ -744,7 +884,7 @@
     h->size = size;
     h->map_beg = map_beg;
     h->map_size = map_size;
-    uptr size_log = SANITIZER_WORDSIZE - __builtin_clzl(map_size) - 1;
+    uptr size_log = MostSignificantSetBitIndex(map_size);
     CHECK_LT(size_log, ARRAY_SIZE(stats.by_size_log));
     {
       SpinMutexLock l(&mutex_);
@@ -756,11 +896,13 @@
       stats.currently_allocated += map_size;
       stats.max_allocated = Max(stats.max_allocated, stats.currently_allocated);
       stats.by_size_log[size_log]++;
+      stat->Add(AllocatorStatMalloced, map_size);
+      stat->Add(AllocatorStatMmapped, map_size);
     }
     return reinterpret_cast<void*>(res);
   }
 
-  void Deallocate(void *p) {
+  void Deallocate(AllocatorStats *stat, void *p) {
     Header *h = GetHeader(p);
     {
       SpinMutexLock l(&mutex_);
@@ -772,6 +914,8 @@
       n_chunks_--;
       stats.n_frees++;
       stats.currently_allocated -= h->map_size;
+      stat->Add(AllocatorStatFreed, h->map_size);
+      stat->Add(AllocatorStatUnmapped, h->map_size);
     }
     MapUnmapCallback().OnUnmap(h->map_beg, h->map_size);
     UnmapOrDie(reinterpret_cast<void*>(h->map_beg), h->map_size);
@@ -838,6 +982,16 @@
     Printf("\n");
   }
 
+  // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+  // introspection API.
+  void ForceLock() {
+    mutex_.Lock();
+  }
+
+  void ForceUnlock() {
+    mutex_.Unlock();
+  }
+
  private:
   static const int kMaxNumChunks = 1 << FIRST_32_SECOND_64(15, 18);
   struct Header {
@@ -884,6 +1038,7 @@
   void Init() {
     primary_.Init();
     secondary_.Init();
+    stats_.Init();
   }
 
   void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
@@ -899,7 +1054,7 @@
     if (primary_.CanAllocate(size, alignment))
       res = cache->Allocate(&primary_, primary_.ClassID(size));
     else
-      res = secondary_.Allocate(size, alignment);
+      res = secondary_.Allocate(&stats_, size, alignment);
     if (alignment > 8)
       CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
     if (cleared && res)
@@ -912,7 +1067,7 @@
     if (primary_.PointerIsMine(p))
       cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
     else
-      secondary_.Deallocate(p);
+      secondary_.Deallocate(&stats_, p);
   }
 
   void *Reallocate(AllocatorCache *cache, void *p, uptr new_size,
@@ -967,20 +1122,48 @@
 
   void TestOnlyUnmap() { primary_.TestOnlyUnmap(); }
 
+  void InitCache(AllocatorCache *cache) {
+    cache->Init(&stats_);
+  }
+
+  void DestroyCache(AllocatorCache *cache) {
+    cache->Destroy(&primary_, &stats_);
+  }
+
   void SwallowCache(AllocatorCache *cache) {
     cache->Drain(&primary_);
   }
 
+  void GetStats(AllocatorStatCounters s) const {
+    stats_.Get(s);
+  }
+
   void PrintStats() {
     primary_.PrintStats();
     secondary_.PrintStats();
   }
 
+  // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+  // introspection API.
+  void ForceLock() {
+    primary_.ForceLock();
+    secondary_.ForceLock();
+  }
+
+  void ForceUnlock() {
+    secondary_.ForceUnlock();
+    primary_.ForceUnlock();
+  }
+
  private:
   PrimaryAllocator primary_;
   SecondaryAllocator secondary_;
+  AllocatorGlobalStats stats_;
 };
 
+// Returns true if calloc(size, n) should return 0 due to overflow in size*n.
+bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n);
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_ALLOCATOR_H
Index: libsanitizer/sanitizer_common/sanitizer_stacktrace.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_stacktrace.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_stacktrace.h	(working copy)
@@ -55,6 +55,10 @@
                               u32 *compressed, uptr size);
 };
 
+
+const char *StripPathPrefix(const char *filepath,
+                            const char *strip_file_prefix);
+
 }  // namespace __sanitizer
 
 // Use this macro if you want to print stack trace with the caller
Index: libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h	(working copy)
@@ -33,4 +33,4 @@
 # define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID
 # define SANITIZER_INTERCEPT_PRCTL   SI_LINUX_NOT_ANDROID
 
-# define SANITIZER_INTERCEPT_SCANF 0
+# define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
Index: libsanitizer/sanitizer_common/sanitizer_common.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_common.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_common.h	(working copy)
@@ -17,6 +17,7 @@
 #include "sanitizer_internal_defs.h"
 
 namespace __sanitizer {
+struct StackTrace;
 
 // Constants.
 const uptr kWordSize = SANITIZER_WORDSIZE / 8;
@@ -28,6 +29,8 @@
 const uptr kCacheLineSize = 64;
 #endif
 
+extern const char *SanitizerToolName;  // Can be changed by the tool.
+
 uptr GetPageSize();
 uptr GetPageSizeCached();
 uptr GetMmapGranularity();
@@ -103,6 +106,7 @@
 void Report(const char *format, ...);
 void SetPrintfAndReportCallback(void (*callback)(const char *));
 
+fd_t 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',
@@ -152,20 +156,79 @@
                                        u64, u64);
 void SetCheckFailedCallback(CheckFailedCallbackType callback);
 
+// Construct a one-line string like
+//  SanitizerToolName: error_type file:line function
+// and call __sanitizer_report_error_summary on it.
+void ReportErrorSummary(const char *error_type, const char *file,
+                        int line, const char *function);
+
 // Math
+#if defined(_WIN32) && !defined(__clang__)
+extern "C" {
+unsigned char _BitScanForward(unsigned long *index, unsigned long mask);  // NOLINT
+unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);  // NOLINT
+#if defined(_WIN64)
+unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask);  // NOLINT
+unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask);  // NOLINT
+#endif
+}
+#endif
+
+INLINE uptr MostSignificantSetBitIndex(uptr x) {
+  CHECK(x != 0);
+  unsigned long up;  // NOLINT
+#if !defined(_WIN32) || defined(__clang__)
+  up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x);
+#elif defined(_WIN64)
+  _BitScanReverse64(&up, x);
+#else
+  _BitScanReverse(&up, x);
+#endif
+  return up;
+}
+
 INLINE bool IsPowerOfTwo(uptr x) {
   return (x & (x - 1)) == 0;
 }
+
+INLINE uptr RoundUpToPowerOfTwo(uptr size) {
+  CHECK(size);
+  if (IsPowerOfTwo(size)) return size;
+
+  uptr up = MostSignificantSetBitIndex(size);
+  CHECK(size < (1ULL << (up + 1)));
+  CHECK(size > (1ULL << up));
+  return 1UL << (up + 1);
+}
+
 INLINE uptr RoundUpTo(uptr size, uptr boundary) {
   CHECK(IsPowerOfTwo(boundary));
   return (size + boundary - 1) & ~(boundary - 1);
 }
+
 INLINE uptr RoundDownTo(uptr x, uptr boundary) {
   return x & ~(boundary - 1);
 }
+
 INLINE bool IsAligned(uptr a, uptr alignment) {
   return (a & (alignment - 1)) == 0;
 }
+
+INLINE uptr Log2(uptr x) {
+  CHECK(IsPowerOfTwo(x));
+#if !defined(_WIN32) || defined(__clang__)
+  return __builtin_ctzl(x);
+#elif defined(_WIN64)
+  unsigned long ret;  // NOLINT
+  _BitScanForward64(&ret, x);
+  return ret;
+#else
+  unsigned long ret;  // NOLINT
+  _BitScanForward(&ret, x);
+  return ret;
+#endif
+}
+
 // Don't use std::min, std::max or std::swap, to minimize dependency
 // on libstdc++.
 template<class T> T Min(T a, T b) { return a < b ? a : b; }
Index: libsanitizer/sanitizer_common/sanitizer_win.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_win.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_win.cc	(working copy)
@@ -95,6 +95,11 @@
                       MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
 }
 
+void FlushUnneededShadowMemory(uptr addr, uptr size) {
+  // This is almost useless on 32-bits.
+  // FIXME: add madvice-analog when we move to 64-bits.
+}
+
 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
   // FIXME: shall we do anything here on Windows?
   return true;
@@ -189,10 +194,18 @@
   return _isatty(fd);
 }
 
-fd_t internal_open(const char *filename, bool write) {
+fd_t internal_open(const char *filename, int flags) {
   UNIMPLEMENTED();
 }
 
+fd_t internal_open(const char *filename, int flags, u32 mode) {
+  UNIMPLEMENTED();
+}
+
+fd_t OpenFile(const char *filename, bool write) {
+  UNIMPLEMENTED();
+}
+
 uptr internal_read(fd_t fd, void *buf, uptr count) {
   UNIMPLEMENTED();
 }
@@ -209,6 +222,18 @@
   return ret;
 }
 
+int internal_stat(const char *path, void *buf) {
+  UNIMPLEMENTED();
+}
+
+int internal_lstat(const char *path, void *buf) {
+  UNIMPLEMENTED();
+}
+
+int internal_fstat(fd_t fd, void *buf) {
+  UNIMPLEMENTED();
+}
+
 uptr internal_filesize(fd_t fd) {
   UNIMPLEMENTED();
 }
@@ -227,10 +252,8 @@
 }
 
 // ---------------------- BlockingMutex ---------------- {{{1
-enum LockState {
-  LOCK_UNINITIALIZED = 0,
-  LOCK_READY = -1,
-};
+const uptr LOCK_UNINITIALIZED = 0;
+const uptr LOCK_READY = (uptr)-1;
 
 BlockingMutex::BlockingMutex(LinkerInitialized li) {
   // FIXME: see comments in BlockingMutex::Lock() for the details.
@@ -252,12 +275,12 @@
     // locks while we're starting in one thread to avoid double-init races.
   }
   EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
-  CHECK(owner_ == LOCK_READY);
+  CHECK_EQ(owner_, LOCK_READY);
   owner_ = GetThreadSelf();
 }
 
 void BlockingMutex::Unlock() {
-  CHECK(owner_ == GetThreadSelf());
+  CHECK_EQ(owner_, GetThreadSelf());
   owner_ = LOCK_READY;
   LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
 }
Index: libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_symbolizer.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_symbolizer.cc	(working copy)
@@ -174,6 +174,53 @@
 
 static LowLevelAllocator symbolizer_allocator;  // Linker initialized.
 
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
+                                char *Buffer, int MaxLength);
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
+                                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) {
+      void *mem = symbolizer_allocator.Allocate(sizeof(InternalSymbolizer));
+      return new(mem) InternalSymbolizer();
+    }
+    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;
+    if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize))
+      return buffer_;
+    return 0;
+  }
+
+ private:
+  InternalSymbolizer() { }
+
+  static const int kBufferSize = 16 * 1024;
+  char buffer_[kBufferSize];
+};
+#else  // SANITIZER_SUPPORTS_WEAK_HOOKS
+
+class InternalSymbolizer {
+ public:
+  static InternalSymbolizer *get() { return 0; }
+  char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+    return 0;
+  }
+};
+
+#endif  // SANITIZER_SUPPORTS_WEAK_HOOKS
+
 class Symbolizer {
  public:
   uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
@@ -266,8 +313,23 @@
     return true;
   }
 
+  bool IsSymbolizerAvailable() {
+    if (internal_symbolizer_ == 0)
+      internal_symbolizer_ = InternalSymbolizer::get();
+    return internal_symbolizer_ || external_symbolizer_;
+  }
+
  private:
   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+    // First, try to use internal symbolizer.
+    if (internal_symbolizer_ == 0) {
+      internal_symbolizer_ = InternalSymbolizer::get();
+    }
+    if (internal_symbolizer_) {
+      return internal_symbolizer_->SendCommand(is_data, module_name,
+                                               module_offset);
+    }
+    // Otherwise, fall back to external symbolizer.
     if (external_symbolizer_ == 0) {
       ReportExternalSymbolizerError(
           "WARNING: Trying to symbolize code, but external "
@@ -322,6 +384,7 @@
   uptr n_modules_;
 
   ExternalSymbolizer *external_symbolizer_;  // Leaked.
+  InternalSymbolizer *internal_symbolizer_;  // Leaked.
 };
 
 static Symbolizer symbolizer;  // Linker initialized.
@@ -338,4 +401,8 @@
   return symbolizer.InitializeExternalSymbolizer(path_to_symbolizer);
 }
 
+bool IsSymbolizerAvailable() {
+  return symbolizer.IsSymbolizerAvailable();
+}
+
 }  // namespace __sanitizer
Index: libsanitizer/sanitizer_common/sanitizer_linux.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_linux.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_linux.cc	(working copy)
@@ -28,12 +28,15 @@
 #include <sys/syscall.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <sys/prctl.h>
 #include <unistd.h>
 #include <unwind.h>
 #include <errno.h>
-#include <sys/prctl.h>
-#include <linux/futex.h>
 
+// <linux/futex.h> is broken on some linux distributions.
+const int FUTEX_WAIT = 0;
+const int FUTEX_WAKE = 1;
+
 // Are we using 32-bit or 64-bit syscalls?
 // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
 // but it still needs to use 64-bit syscalls.
@@ -63,8 +66,16 @@
   return syscall(__NR_close, fd);
 }
 
-fd_t internal_open(const char *filename, bool write) {
-  return syscall(__NR_open, filename,
+fd_t internal_open(const char *filename, int flags) {
+  return syscall(__NR_open, filename, flags);
+}
+
+fd_t internal_open(const char *filename, int flags, u32 mode) {
+  return syscall(__NR_open, filename, flags, mode);
+}
+
+fd_t OpenFile(const char *filename, bool write) {
+  return internal_open(filename,
       write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
 }
 
@@ -80,16 +91,38 @@
   return res;
 }
 
+int internal_stat(const char *path, void *buf) {
+#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
+  return syscall(__NR_stat, path, buf);
+#else
+  return syscall(__NR_stat64, path, buf);
+#endif
+}
+
+int internal_lstat(const char *path, void *buf) {
+#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
+  return syscall(__NR_lstat, path, buf);
+#else
+  return syscall(__NR_lstat64, path, buf);
+#endif
+}
+
+int internal_fstat(fd_t fd, void *buf) {
+#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
+  return syscall(__NR_fstat, fd, buf);
+#else
+  return syscall(__NR_fstat64, fd, buf);
+#endif
+}
+
 uptr internal_filesize(fd_t fd) {
 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
   struct stat st;
-  if (syscall(__NR_fstat, fd, &st))
-    return -1;
 #else
   struct stat64 st;
-  if (syscall(__NR_fstat64, fd, &st))
+#endif
+  if (internal_fstat(fd, &st))
     return -1;
-#endif
   return (uptr)st.st_size;
 }
 
Index: libsanitizer/sanitizer_common/sanitizer_mac.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_mac.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_mac.cc	(working copy)
@@ -11,6 +11,12 @@
 //===----------------------------------------------------------------------===//
 
 #ifdef __APPLE__
+// 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
+#define _DARWIN_USE_64_BIT_INODE 1
+#endif
+#include <stdio.h>
 
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
@@ -46,11 +52,19 @@
   return close(fd);
 }
 
-fd_t internal_open(const char *filename, bool write) {
-  return open(filename,
-              write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
+fd_t internal_open(const char *filename, int flags) {
+  return open(filename, flags);
 }
 
+fd_t internal_open(const char *filename, int flags, u32 mode) {
+  return open(filename, flags, mode);
+}
+
+fd_t OpenFile(const char *filename, bool write) {
+  return internal_open(filename,
+      write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
+}
+
 uptr internal_read(fd_t fd, void *buf, uptr count) {
   return read(fd, buf, count);
 }
@@ -59,9 +73,21 @@
   return write(fd, buf, count);
 }
 
+int internal_stat(const char *path, void *buf) {
+  return stat(path, (struct stat *)buf);
+}
+
+int internal_lstat(const char *path, void *buf) {
+  return lstat(path, (struct stat *)buf);
+}
+
+int internal_fstat(fd_t fd, void *buf) {
+  return fstat(fd, (struct stat *)buf);
+}
+
 uptr internal_filesize(fd_t fd) {
   struct stat st;
-  if (fstat(fd, &st))
+  if (internal_fstat(fd, &st))
     return -1;
   return (uptr)st.st_size;
 }
Index: libsanitizer/sanitizer_common/sanitizer_symbolizer.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_symbolizer.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_symbolizer.h	(working copy)
@@ -67,6 +67,8 @@
 uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames);
 bool SymbolizeData(uptr address, DataInfo *info);
 
+bool IsSymbolizerAvailable();
+
 // Attempts to demangle the provided C++ mangled name.
 const char *Demangle(const char *Name);
 
Index: libsanitizer/sanitizer_common/sanitizer_internal_defs.h
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_internal_defs.h	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_internal_defs.h	(working copy)
@@ -11,7 +11,85 @@
 #ifndef SANITIZER_DEFS_H
 #define SANITIZER_DEFS_H
 
-#include "sanitizer/common_interface_defs.h"
+#if defined(_WIN32)
+// FIXME find out what we need on Windows. __declspec(dllexport) ?
+# define SANITIZER_INTERFACE_ATTRIBUTE
+# define SANITIZER_WEAK_ATTRIBUTE
+#elif defined(SANITIZER_GO)
+# define SANITIZER_INTERFACE_ATTRIBUTE
+# define SANITIZER_WEAK_ATTRIBUTE
+#else
+# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
+# define SANITIZER_WEAK_ATTRIBUTE  __attribute__((weak))
+#endif
+
+#ifdef __linux__
+# define SANITIZER_SUPPORTS_WEAK_HOOKS 1
+#else
+# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
+#endif
+
+// __has_feature
+#if !defined(__has_feature)
+# define __has_feature(x) 0
+#endif
+
+// For portability reasons we do not include stddef.h, stdint.h or any other
+// system header, but we do need some basic types that are not defined
+// in a portable way by the language itself.
+namespace __sanitizer {
+
+#if defined(_WIN64)
+// 64-bit Windows uses LLP64 data model.
+typedef unsigned long long uptr;  // NOLINT
+typedef signed   long long sptr;  // NOLINT
+#else
+typedef unsigned long uptr;  // NOLINT
+typedef signed   long sptr;  // NOLINT
+#endif  // defined(_WIN64)
+#if defined(__x86_64__)
+// Since x32 uses ILP32 data model in 64-bit hardware mode,  we must use
+// 64-bit pointer to unwind stack frame.
+typedef unsigned long long uhwptr;  // NOLINT
+#else
+typedef uptr uhwptr;   // NOLINT
+#endif
+typedef unsigned char u8;
+typedef unsigned short u16;  // NOLINT
+typedef unsigned int u32;
+typedef unsigned long long u64;  // NOLINT
+typedef signed   char s8;
+typedef signed   short s16;  // NOLINT
+typedef signed   int s32;
+typedef signed   long long s64;  // NOLINT
+typedef int fd_t;
+
+}  // namespace __sanitizer
+
+extern "C" {
+  // Tell the tools to write their reports to "path.<pid>" instead of stderr.
+  void __sanitizer_set_report_path(const char *path)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // Tell the tools to write their reports to given file descriptor instead of
+  // stderr.
+  void __sanitizer_set_report_fd(int fd)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // Notify the tools that the sandbox is going to be turned on. The reserved
+  // parameter will be used in the future to hold a structure with functions
+  // that the tools may call to bypass the sandbox.
+  void __sanitizer_sandbox_on_notify(void *reserved)
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // This function is called by the tool when it has just finished reporting
+  // an error. 'error_summary' is a one-line string that summarizes
+  // the error message. This function can be overridden by the client.
+  void __sanitizer_report_error_summary(const char *error_summary)
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+}  // extern "C"
+
+
 using namespace __sanitizer;  // NOLINT
 // ----------- ATTENTION -------------
 // This header should NOT include any other headers to avoid portability issues.
Index: libsanitizer/sanitizer_common/sanitizer_allocator.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_allocator.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_allocator.cc	(working copy)
@@ -73,4 +73,10 @@
   low_level_alloc_callback = callback;
 }
 
+bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) {
+  if (!size) return false;
+  uptr max = (uptr)-1L;
+  return (max / size) < n;
+}
+
 }  // namespace __sanitizer
Index: libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
===================================================================
--- libsanitizer/sanitizer_common/sanitizer_stacktrace.cc	(revision 195997)
+++ libsanitizer/sanitizer_common/sanitizer_stacktrace.cc	(working copy)
@@ -15,8 +15,9 @@
 #include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
-static const char *StripPathPrefix(const char *filepath,
-                                   const char *strip_file_prefix) {
+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);
   return filepath;
Index: libsanitizer/asan/asan_allocator.cc
===================================================================
--- libsanitizer/asan/asan_allocator.cc	(revision 195997)
+++ libsanitizer/asan/asan_allocator.cc	(working copy)
@@ -32,7 +32,7 @@
 #include "asan_report.h"
 #include "asan_thread.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
+#include "sanitizer_common/sanitizer_allocator.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_mutex.h"
 
@@ -367,7 +367,7 @@
         left_chunk->chunk_state != CHUNK_AVAILABLE)
       return left_chunk;
     // Choose based on offset.
-    uptr l_offset = 0, r_offset = 0;
+    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)
@@ -387,7 +387,7 @@
     CHECK(m->chunk_state == CHUNK_ALLOCATED ||
           m->chunk_state == CHUNK_AVAILABLE ||
           m->chunk_state == CHUNK_QUARANTINE);
-    uptr offset = 0;
+    sptr offset = 0;
     AsanChunkView m_view(m);
     if (m_view.AddrIsInside(addr, 1, &offset))
       return m;
@@ -685,6 +685,8 @@
 
 namespace __asan {
 
+void InitializeAllocator() { }
+
 void PrintInternalAllocatorStats() {
 }
 
@@ -710,6 +712,7 @@
 }
 
 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);
Index: libsanitizer/asan/asan_interceptors.cc
===================================================================
--- libsanitizer/asan/asan_interceptors.cc	(revision 195997)
+++ libsanitizer/asan/asan_interceptors.cc	(working copy)
@@ -20,7 +20,6 @@
 #include "asan_stats.h"
 #include "asan_thread_registry.h"
 #include "interception/interception.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
 namespace __asan {
@@ -30,12 +29,14 @@
 // that no extra frames are created, and stack trace contains
 // relevant information only.
 // We check all shadow bytes.
-#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do {                  \
-  if (uptr __ptr = __asan_region_is_poisoned((uptr)(offset), size)) {    \
-    GET_CURRENT_PC_BP_SP;                                                \
-    __asan_report_error(pc, bp, sp, __ptr, isWrite, /* access_size */1); \
-  }                                                                      \
-} while (0)
+#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do {                 \
+    uptr __offset = (uptr)(offset);                                     \
+    uptr __size = (uptr)(size);                                         \
+    if (__asan_region_is_poisoned(__offset, __size)) {                  \
+      GET_CURRENT_PC_BP_SP;                                             \
+      __asan_report_error(pc, bp, sp, __offset, isWrite, __size);       \
+    }                                                                   \
+  } 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);
@@ -275,13 +276,9 @@
     ASAN_READ_RANGE(from, size);
     ASAN_WRITE_RANGE(to, size);
   }
-#if MAC_INTERPOSE_FUNCTIONS
   // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8.
   // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
   return internal_memcpy(to, from, size);
-#else
-  return REAL(memcpy)(to, from, size);
-#endif
 }
 
 INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
@@ -294,13 +291,9 @@
     ASAN_READ_RANGE(from, size);
     ASAN_WRITE_RANGE(to, size);
   }
-#if MAC_INTERPOSE_FUNCTIONS
   // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8.
   // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
   return internal_memmove(to, from, size);
-#else
-  return REAL(memmove)(to, from, size);
-#endif
 }
 
 INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
@@ -398,7 +391,7 @@
 }
 
 INTERCEPTOR(char*, strcpy, char *to, const char *from) {  // NOLINT
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
   if (!asan_inited) return REAL(strcpy)(to, from);  // NOLINT
 #endif
   // strcpy is called from malloc_default_purgeable_zone()
@@ -418,7 +411,7 @@
 
 #if ASAN_INTERCEPT_STRDUP
 INTERCEPTOR(char*, strdup, const char *s) {
-#if MAC_INTERPOSE_FUNCTIONS
+#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
@@ -559,7 +552,7 @@
 }
 
 INTERCEPTOR(int, atoi, const char *nptr) {
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
   if (!asan_inited) return REAL(atoi)(nptr);
 #endif
   ENSURE_ASAN_INITED();
@@ -578,7 +571,7 @@
 }
 
 INTERCEPTOR(long, atol, const char *nptr) {  // NOLINT
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
   if (!asan_inited) return REAL(atol)(nptr);
 #endif
   ENSURE_ASAN_INITED();
@@ -659,10 +652,9 @@
   static bool was_called_once;
   CHECK(was_called_once == false);
   was_called_once = true;
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
   return;
-#endif
-
+#else
   SANITIZER_COMMON_INTERCEPTORS_INIT;
 
   // Intercept mem* functions.
@@ -671,12 +663,6 @@
   ASAN_INTERCEPT_FUNC(memset);
   if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
     ASAN_INTERCEPT_FUNC(memcpy);
-  } else {
-#if !MAC_INTERPOSE_FUNCTIONS
-    // If we're using dynamic interceptors on Mac, these two are just plain
-    // functions.
-    internal_memcpy(&REAL(memcpy), &REAL(memmove), sizeof(REAL(memmove)));
-#endif
   }
 
   // Intercept str* functions.
@@ -698,12 +684,8 @@
 #if ASAN_INTERCEPT_STRNLEN
   ASAN_INTERCEPT_FUNC(strnlen);
 #endif
-#if ASAN_INTERCEPT_INDEX
-# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
+#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
   ASAN_INTERCEPT_FUNC(index);
-# else
-  CHECK(OVERRIDE_FUNCTION(index, WRAP(strchr)));
-# endif
 #endif
 
   ASAN_INTERCEPT_FUNC(atoi);
@@ -753,14 +735,10 @@
   InitializeWindowsInterceptors();
 #endif
 
-  // Some Mac-specific interceptors.
-#if defined(__APPLE__)
-  InitializeMacInterceptors();
-#endif
-
   if (flags()->verbosity > 0) {
     Report("AddressSanitizer: libc interceptors initialized\n");
   }
+#endif  // __APPLE__
 }
 
 }  // namespace __asan
Index: libsanitizer/asan/asan_allocator.h
===================================================================
--- libsanitizer/asan/asan_allocator.h	(revision 195997)
+++ libsanitizer/asan/asan_allocator.h	(working copy)
@@ -22,7 +22,7 @@
 // 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
-# if ASAN_LINUX && !ASAN_ANDROID
+# if (ASAN_LINUX && !ASAN_ANDROID) || ASAN_MAC || ASAN_WINDOWS
 #  define ASAN_ALLOCATOR_VERSION 2
 # else
 #  define ASAN_ALLOCATOR_VERSION 1
@@ -40,6 +40,8 @@
 static const uptr kNumberOfSizeClasses = 255;
 struct AsanChunk;
 
+void InitializeAllocator();
+
 class AsanChunkView {
  public:
   explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
@@ -51,14 +53,14 @@
   uptr FreeTid();
   void GetAllocStack(StackTrace *stack);
   void GetFreeStack(StackTrace *stack);
-  bool AddrIsInside(uptr addr, uptr access_size, uptr *offset) {
+  bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
     if (addr >= Beg() && (addr + access_size) <= End()) {
       *offset = addr - Beg();
       return true;
     }
     return false;
   }
-  bool AddrIsAtLeft(uptr addr, uptr access_size, uptr *offset) {
+  bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) {
     (void)access_size;
     if (addr < Beg()) {
       *offset = Beg() - addr;
@@ -66,12 +68,9 @@
     }
     return false;
   }
-  bool AddrIsAtRight(uptr addr, uptr access_size, uptr *offset) {
-    if (addr + access_size >= End()) {
-      if (addr <= End())
-        *offset = 0;
-      else
-        *offset = addr - End();
+  bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) {
+    if (addr + access_size > End()) {
+      *offset = addr - End();
       return true;
     }
     return false;
@@ -225,50 +224,5 @@
 
 void PrintInternalAllocatorStats();
 
-// Log2 and RoundUpToPowerOfTwo should be inlined for performance.
-#if defined(_WIN32) && !defined(__clang__)
-extern "C" {
-unsigned char _BitScanForward(unsigned long *index, unsigned long mask);  // NOLINT
-unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);  // NOLINT
-#if defined(_WIN64)
-unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask);  // NOLINT
-unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask);  // NOLINT
-#endif
-}
-#endif
-
-static inline uptr Log2(uptr x) {
-  CHECK(IsPowerOfTwo(x));
-#if !defined(_WIN32) || defined(__clang__)
-  return __builtin_ctzl(x);
-#elif defined(_WIN64)
-  unsigned long ret;  // NOLINT
-  _BitScanForward64(&ret, x);
-  return ret;
-#else
-  unsigned long ret;  // NOLINT
-  _BitScanForward(&ret, x);
-  return ret;
-#endif
-}
-
-static inline uptr RoundUpToPowerOfTwo(uptr size) {
-  CHECK(size);
-  if (IsPowerOfTwo(size)) return size;
-
-  unsigned long up;  // NOLINT
-#if !defined(_WIN32) || defined(__clang__)
-  up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(size);
-#elif defined(_WIN64)
-  _BitScanReverse64(&up, size);
-#else
-  _BitScanReverse(&up, size);
-#endif
-  CHECK(size < (1ULL << (up + 1)));
-  CHECK(size > (1ULL << up));
-  return 1UL << (up + 1);
-}
-
-
 }  // namespace __asan
 #endif  // ASAN_ALLOCATOR_H
Index: libsanitizer/asan/asan_fake_stack.cc
===================================================================
--- libsanitizer/asan/asan_fake_stack.cc	(revision 195997)
+++ libsanitizer/asan/asan_fake_stack.cc	(working copy)
@@ -12,7 +12,6 @@
 #include "asan_allocator.h"
 #include "asan_thread.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
 
 namespace __asan {
 
Index: libsanitizer/asan/asan_flags.h
===================================================================
--- libsanitizer/asan/asan_flags.h	(revision 195997)
+++ libsanitizer/asan/asan_flags.h	(working copy)
@@ -13,7 +13,7 @@
 #ifndef ASAN_FLAGS_H
 #define ASAN_FLAGS_H
 
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
 
 // ASan flag values can be defined in three ways:
 // 1) initialized with default values at startup.
@@ -50,8 +50,6 @@
   bool replace_str;
   // If set, uses custom wrappers for memset/memcpy/memmove intinsics.
   bool replace_intrin;
-  // Used on Mac only. See comments in asan_mac.cc and asan_malloc_mac.cc.
-  bool replace_cfallocator;
   // Used on Mac only.
   bool mac_ignore_invalid_free;
   // ASan allocator flag. See asan_allocator.cc.
@@ -77,6 +75,10 @@
   bool unmap_shadow_on_exit;
   // If set, calls abort() instead of _exit() after printing an error report.
   bool abort_on_error;
+  // Print various statistics after printing an error message or if atexit=1.
+  bool print_stats;
+  // Print the legend for the shadow bytes.
+  bool print_legend;
   // If set, prints ASan exit stats even after program terminates successfully.
   bool atexit;
   // By default, disable core dumper on 64-bit - it makes little sense
Index: libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc
===================================================================
--- libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc	(revision 195997)
+++ libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc	(working copy)
@@ -17,11 +17,6 @@
 
 namespace __asan {
 
-#if !MAC_INTERPOSE_FUNCTIONS
-# error \
-  Dynamic interposing library should be built with -DMAC_INTERPOSE_FUNCTIONS
-#endif
-
 #define INTERPOSE_FUNCTION(function) \
     { reinterpret_cast<const uptr>(WRAP(function)), \
       reinterpret_cast<const uptr>(function) }
Index: libsanitizer/asan/asan_stats.cc
===================================================================
--- libsanitizer/asan/asan_stats.cc	(revision 195997)
+++ libsanitizer/asan/asan_stats.cc	(working copy)
@@ -13,7 +13,6 @@
 #include "asan_internal.h"
 #include "asan_stats.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 
 namespace __asan {
Index: libsanitizer/asan/asan_interface_internal.h
===================================================================
--- libsanitizer/asan/asan_interface_internal.h	(revision 0)
+++ libsanitizer/asan/asan_interface_internal.h	(revision 0)
@@ -0,0 +1,133 @@
+//===-- asan_interface_internal.h -------------------------------*- C++ -*-===//
+//
+// 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.
+//
+// This header can be included by the instrumented program to fetch
+// data (mostly allocator statistics) from ASan runtime library.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERFACE_INTERNAL_H
+#define ASAN_INTERFACE_INTERNAL_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+using __sanitizer::uptr;
+
+extern "C" {
+  // This function should be called at the very beginning of the process,
+  // before any instrumented code is executed and before any call to malloc.
+  // 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_v1() SANITIZER_INTERFACE_ATTRIBUTE;
+  #define __asan_init __asan_init_v1
+
+  // This structure describes an instrumented global variable.
+  struct __asan_global {
+    uptr beg;                // The address of the global.
+    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.
+    uptr has_dynamic_init;   // Non-zero if the global has dynamic initializer.
+  };
+
+  // These two functions should be called by the instrumented code.
+  // 'globals' is an array of structures describing 'n' globals.
+  void __asan_register_globals(__asan_global *globals, uptr n)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_unregister_globals(__asan_global *globals, uptr n)
+      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)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_after_dynamic_init()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // These two functions are used by the instrumented code in the
+  // use-after-return mode. __asan_stack_malloc allocates size bytes of
+  // fake stack and __asan_stack_free poisons it. real_stack is a pointer to
+  // the real stack region.
+  uptr __asan_stack_malloc(uptr size, uptr real_stack)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_stack_free(uptr ptr, uptr size, uptr real_stack)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // These two functions are used by instrumented code in the
+  // use-after-scope mode. They mark memory for local variables as
+  // unaddressable when they leave scope and addressable before the
+  // function exits.
+  void __asan_poison_stack_memory(uptr addr, uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_unpoison_stack_memory(uptr addr, uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  // Performs cleanup before a NoReturn function. Must be called before things
+  // like _exit and execl to avoid false positives on stack.
+  void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE;
+
+  void __asan_poison_memory_region(void const volatile *addr, uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_unpoison_memory_region(void const volatile *addr, uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  bool __asan_address_is_poisoned(void const volatile *addr)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  uptr __asan_region_is_poisoned(uptr beg, uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  void __asan_describe_address(uptr addr)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  void __asan_report_error(uptr pc, uptr bp, uptr sp,
+                           uptr addr, bool is_write, uptr access_size)
+    SANITIZER_INTERFACE_ATTRIBUTE;
+
+  int __asan_set_error_exit_code(int exit_code)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_set_death_callback(void (*callback)(void))
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_set_error_report_callback(void (*callback)(const char*))
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  /* OPTIONAL */ void __asan_on_error()
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+  /* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
+                                       int out_size)
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+  uptr __asan_get_estimated_allocated_size(uptr size)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  bool __asan_get_ownership(const void *p)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  uptr __asan_get_allocated_size(const void *p)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  uptr __asan_get_current_allocated_bytes()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  uptr __asan_get_heap_size()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  uptr __asan_get_free_bytes()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  uptr __asan_get_unmapped_bytes()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_print_accumulated_stats()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
+  /* OPTIONAL */ const char* __asan_default_options()
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+  /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size)
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  /* OPTIONAL */ void __asan_free_hook(void *ptr)
+      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+}  // extern "C"
+
+#endif  // ASAN_INTERFACE_INTERNAL_H
Index: libsanitizer/asan/asan_intercepted_functions.h
===================================================================
--- libsanitizer/asan/asan_intercepted_functions.h	(revision 195997)
+++ libsanitizer/asan/asan_intercepted_functions.h	(working copy)
@@ -17,6 +17,7 @@
 #include "sanitizer_common/sanitizer_platform_interceptors.h"
 
 #include <stdarg.h>
+#include <stddef.h>
 
 using __sanitizer::uptr;
 
@@ -64,9 +65,7 @@
 # define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
 #endif
 
-// On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it
-// there.
-#if !defined(_WIN32) && (!defined(__APPLE__) || MAC_INTERPOSE_FUNCTIONS)
+#if !defined(_WIN32)
 # define ASAN_INTERCEPT_SIGLONGJMP 1
 #else
 # define ASAN_INTERCEPT_SIGLONGJMP 0
@@ -169,7 +168,8 @@
 DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, write, int fd, void *ptr, SIZE_T count);
 # endif
 # if SANITIZER_INTERCEPT_PWRITE
-DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count);
+DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pwrite,
+                             int fd, void *ptr, SIZE_T count, OFF_T offset);
 # endif
 
 # if ASAN_INTERCEPT_MLOCKX
@@ -193,6 +193,8 @@
                              void *(*start_routine)(void*), void *arg);
 # endif
 
+// stdio.h
+# if SANITIZER_INTERCEPT_SCANF
 DECLARE_FUNCTION_AND_WRAPPER(int, vscanf, const char *format, va_list ap);
 DECLARE_FUNCTION_AND_WRAPPER(int, vsscanf, const char *str, const char *format,
                              va_list ap);
@@ -203,6 +205,18 @@
                              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__)
 typedef void* pthread_workqueue_t;
@@ -231,7 +245,7 @@
                              dispatch_group_t group, dispatch_queue_t dq,
                              void *ctxt, dispatch_function_t func);
 
-#  if MAC_INTERPOSE_FUNCTIONS && !defined(MISSING_BLOCKS_SUPPORT)
+#  if !defined(MISSING_BLOCKS_SUPPORT)
 DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_group_async,
                              dispatch_group_t dg,
                              dispatch_queue_t dq, void (^work)(void));
@@ -243,7 +257,7 @@
                              dispatch_source_t ds, void (^work)(void));
 DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_source_set_cancel_handler,
                              dispatch_source_t ds, void (^work)(void));
-#  endif  // MAC_INTERPOSE_FUNCTIONS
+#  endif  // MISSING_BLOCKS_SUPPORT
 
 typedef void malloc_zone_t;
 typedef size_t vm_size_t;
Index: libsanitizer/asan/asan_rtl.cc
===================================================================
--- libsanitizer/asan/asan_rtl.cc	(revision 195997)
+++ libsanitizer/asan/asan_rtl.cc	(working copy)
@@ -18,7 +18,6 @@
 #include "asan_stats.h"
 #include "asan_thread.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_libc.h"
@@ -83,7 +82,6 @@
 
   ParseFlag(str, &f->replace_str, "replace_str");
   ParseFlag(str, &f->replace_intrin, "replace_intrin");
-  ParseFlag(str, &f->replace_cfallocator, "replace_cfallocator");
   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");
@@ -95,6 +93,8 @@
   ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size");
   ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit");
   ParseFlag(str, &f->abort_on_error, "abort_on_error");
+  ParseFlag(str, &f->print_stats, "print_stats");
+  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");
@@ -121,7 +121,6 @@
   f->malloc_context_size = kDeafultMallocContextSize;
   f->replace_str = true;
   f->replace_intrin = true;
-  f->replace_cfallocator = true;
   f->mac_ignore_invalid_free = false;
   f->use_fake_stack = true;
   f->max_malloc_fill_size = 0;
@@ -133,6 +132,8 @@
   f->check_malloc_usable_size = true;
   f->unmap_shadow_on_exit = false;
   f->abort_on_error = false;
+  f->print_stats = false;
+  f->print_legend = true;
   f->atexit = false;
   f->disable_core = (SANITIZER_WORDSIZE == 64);
   f->strip_path_prefix = "";
@@ -142,9 +143,7 @@
   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->alloc_dealloc_mismatch = true;
   f->use_stack_depot = true;  // Only affects allocator2.
 
   // Override from user-specified string.
@@ -162,6 +161,7 @@
 int asan_inited;
 bool asan_init_is_running;
 void (*death_callback)(void);
+uptr kHighMemEnd;
 
 // -------------------------- Misc ---------------- {{{1
 void ShowStatsAndAbort() {
@@ -261,6 +261,24 @@
   __asan_print_accumulated_stats();
 }
 
+static void InitializeHighMemEnd() {
+#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
+}
+
 }  // namespace __asan
 
 // ---------------------- Interface ---------------- {{{1
@@ -295,8 +313,10 @@
 
 void __asan_init() {
   if (asan_inited) return;
+  SanitizerToolName = "AddressSanitizer";
   CHECK(!asan_init_is_running && "ASan init calls itself!");
   asan_init_is_running = true;
+  InitializeHighMemEnd();
 
   // Make sure we are not statically linked.
   AsanDoesNotSupportStaticLinkage();
@@ -400,6 +420,8 @@
   asanThreadRegistry().GetMain()->ThreadStart();
   force_interface_symbols();  // no-op.
 
+  InitializeAllocator();
+
   if (flags()->verbosity) {
     Report("AddressSanitizer Init done\n");
   }
Index: libsanitizer/asan/asan_poisoning.cc
===================================================================
--- libsanitizer/asan/asan_poisoning.cc	(revision 195997)
+++ libsanitizer/asan/asan_poisoning.cc	(working copy)
@@ -13,7 +13,6 @@
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_mapping.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
 namespace __asan {
Index: libsanitizer/asan/asan_new_delete.cc
===================================================================
--- libsanitizer/asan/asan_new_delete.cc	(revision 195997)
+++ libsanitizer/asan/asan_new_delete.cc	(working copy)
@@ -25,9 +25,9 @@
 
 using namespace __asan;  // NOLINT
 
-// On Mac and Android new() goes through malloc interceptors.
+// On Android new() goes through malloc interceptors.
 // See also https://code.google.com/p/address-sanitizer/issues/detail?id=131.
-#if !ASAN_ANDROID && !ASAN_MAC
+#if !ASAN_ANDROID
 
 // Fake std::nothrow_t to avoid including <new>.
 namespace std {
Index: libsanitizer/asan/asan_report.h
===================================================================
--- libsanitizer/asan/asan_report.h	(revision 195997)
+++ libsanitizer/asan/asan_report.h	(working copy)
@@ -13,15 +13,15 @@
 #include "asan_allocator.h"
 #include "asan_internal.h"
 #include "asan_thread.h"
-#include "sanitizer/asan_interface.h"
 
 namespace __asan {
 
 // The following functions prints address description depending
 // on the memory type (shadow/heap/stack/global).
 void DescribeHeapAddress(uptr addr, uptr access_size);
-bool DescribeAddressIfGlobal(uptr addr);
-bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g);
+bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
+bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
+                                     const __asan_global &g);
 bool DescribeAddressIfShadow(uptr addr);
 bool DescribeAddressIfStack(uptr addr, uptr access_size);
 // Determines memory type on its own.
Index: libsanitizer/asan/asan_internal.h
===================================================================
--- libsanitizer/asan/asan_internal.h	(revision 195997)
+++ libsanitizer/asan/asan_internal.h	(working copy)
@@ -13,6 +13,7 @@
 #define ASAN_INTERNAL_H
 
 #include "asan_flags.h"
+#include "asan_interface_internal.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
Index: libsanitizer/asan/asan_globals.cc
===================================================================
--- libsanitizer/asan/asan_globals.cc	(revision 195997)
+++ libsanitizer/asan/asan_globals.cc	(working copy)
@@ -16,7 +16,6 @@
 #include "asan_stack.h"
 #include "asan_stats.h"
 #include "asan_thread.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_mutex.h"
 
 namespace __asan {
@@ -34,26 +33,20 @@
 static ListOfGlobals *list_of_dynamic_init_globals;
 
 void PoisonRedZones(const Global &g)  {
-  uptr shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE;
-  CHECK(shadow_rz_size == 1 || shadow_rz_size == 2 || shadow_rz_size == 4);
-  // full right redzone
-  uptr g_aligned_size = kGlobalAndStackRedzone *
-      ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone);
-  PoisonShadow(g.beg + g_aligned_size,
-               kGlobalAndStackRedzone, kAsanGlobalRedzoneMagic);
-  if ((g.size % kGlobalAndStackRedzone) != 0) {
+  uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
+  PoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
+               kAsanGlobalRedzoneMagic);
+  if (g.size != aligned_size) {
     // partial right redzone
-    u64 g_aligned_down_size = kGlobalAndStackRedzone *
-        (g.size / kGlobalAndStackRedzone);
-    CHECK(g_aligned_down_size == g_aligned_size - kGlobalAndStackRedzone);
-    PoisonShadowPartialRightRedzone(g.beg + g_aligned_down_size,
-                                    g.size % kGlobalAndStackRedzone,
-                                    kGlobalAndStackRedzone,
-                                    kAsanGlobalRedzoneMagic);
+    PoisonShadowPartialRightRedzone(
+        g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
+        g.size % SHADOW_GRANULARITY,
+        SHADOW_GRANULARITY,
+        kAsanGlobalRedzoneMagic);
   }
 }
 
-bool DescribeAddressIfGlobal(uptr addr) {
+bool DescribeAddressIfGlobal(uptr addr, uptr size) {
   if (!flags()->report_globals) return false;
   BlockingMutexLock lock(&mu_for_globals);
   bool res = false;
@@ -62,7 +55,7 @@
     if (flags()->report_globals >= 2)
       Report("Search Global: beg=%p size=%zu name=%s\n",
              (void*)g.beg, g.size, (char*)g.name);
-    res |= DescribeAddressRelativeToGlobal(addr, g);
+    res |= DescribeAddressRelativeToGlobal(addr, size, g);
   }
   return res;
 }
Index: libsanitizer/asan/asan_interceptors.h
===================================================================
--- libsanitizer/asan/asan_interceptors.h	(revision 195997)
+++ libsanitizer/asan/asan_interceptors.h	(working copy)
@@ -30,9 +30,6 @@
 namespace __asan {
 
 void InitializeAsanInterceptors();
-#if defined(__APPLE__)
-void InitializeMacInterceptors();
-#endif  // __APPLE__
 
 }  // namespace __asan
 
Index: libsanitizer/asan/asan_malloc_linux.cc
===================================================================
--- libsanitizer/asan/asan_malloc_linux.cc	(revision 195997)
+++ libsanitizer/asan/asan_malloc_linux.cc	(working copy)
@@ -18,7 +18,6 @@
 #include "asan_internal.h"
 #include "asan_stack.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
 
 #if ASAN_ANDROID
 DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
Index: libsanitizer/asan/asan_mapping.h
===================================================================
--- libsanitizer/asan/asan_mapping.h	(revision 195997)
+++ libsanitizer/asan/asan_mapping.h	(working copy)
@@ -1,5 +1,7 @@
 //===-- 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.
 //
@@ -34,27 +36,20 @@
 #   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
 #endif  // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
 
 #define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
-#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) | (SHADOW_OFFSET))
+#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
 #define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
 
-#if SANITIZER_WORDSIZE == 64
-# if defined(__powerpc64__)
-  static const uptr kHighMemEnd = 0x00000fffffffffffUL;
-# else
-  static const uptr kHighMemEnd = 0x00007fffffffffffUL;
-# endif
-#else  // SANITIZER_WORDSIZE == 32
-  static const uptr kHighMemEnd = 0xffffffff;
-#endif  // SANITIZER_WORDSIZE
-
-
 #define kLowMemBeg      0
 #define kLowMemEnd      (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
 
@@ -74,11 +69,11 @@
                                        : kZeroBaseShadowStart)
 #define kShadowGapEnd   (kHighShadowBeg - 1)
 
-#define kGlobalAndStackRedzone \
-      (SHADOW_GRANULARITY < 32 ? 32 : SHADOW_GRANULARITY)
-
 namespace __asan {
 
+SANITIZER_INTERFACE_ATTRIBUTE
+extern uptr kHighMemEnd;  // Initialized in __asan_init.
+
 static inline bool AddrIsInLowMem(uptr a) {
   return a < kLowMemEnd;
 }
Index: libsanitizer/asan/asan_mac.cc
===================================================================
--- libsanitizer/asan/asan_mac.cc	(revision 195997)
+++ libsanitizer/asan/asan_mac.cc	(working copy)
@@ -89,10 +89,9 @@
 
 void MaybeReexec() {
   if (!flags()->allow_reexec) return;
-#if MAC_INTERPOSE_FUNCTIONS
-  // If the program is linked with the dynamic ASan runtime library, make sure
-  // the library is preloaded so that the wrappers work. If it is not, set
-  // DYLD_INSERT_LIBRARIES and re-exec ourselves.
+  // Make sure the dynamic ASan runtime library is preloaded so that the
+  // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec
+  // ourselves.
   Dl_info info;
   CHECK(dladdr((void*)((uptr)__asan_init), &info));
   const char *dyld_insert_libraries = GetEnv(kDyldInsertLibraries);
@@ -114,8 +113,6 @@
     }
     execv(program_name, *_NSGetArgv());
   }
-#endif  // MAC_INTERPOSE_FUNCTIONS
-  // If we're not using the dynamic runtime, do nothing.
 }
 
 // No-op. Mac does not support static linkage anyway.
@@ -146,57 +143,6 @@
   UNIMPLEMENTED();
 }
 
-// The range of pages to be used for escape islands.
-// TODO(glider): instead of mapping a fixed range we must find a range of
-// unmapped pages in vmmap and take them.
-// These constants were chosen empirically and may not work if the shadow
-// memory layout changes. Unfortunately they do necessarily depend on
-// kHighMemBeg or kHighMemEnd.
-static void *island_allocator_pos = 0;
-
-#if SANITIZER_WORDSIZE == 32
-# define kIslandEnd (0xffdf0000 - GetPageSizeCached())
-# define kIslandBeg (kIslandEnd - 256 * GetPageSizeCached())
-#else
-# define kIslandEnd (0x7fffffdf0000 - GetPageSizeCached())
-# define kIslandBeg (kIslandEnd - 256 * GetPageSizeCached())
-#endif
-
-extern "C"
-mach_error_t __interception_allocate_island(void **ptr,
-                                            uptr unused_size,
-                                            void *unused_hint) {
-  if (!island_allocator_pos) {
-    island_allocator_pos =
-        internal_mmap((void*)kIslandBeg, kIslandEnd - kIslandBeg,
-                      PROT_READ | PROT_WRITE | PROT_EXEC,
-                      MAP_PRIVATE | MAP_ANON | MAP_FIXED,
-                      -1, 0);
-    if (island_allocator_pos != (void*)kIslandBeg) {
-      return KERN_NO_SPACE;
-    }
-    if (flags()->verbosity) {
-      Report("Mapped pages %p--%p for branch islands.\n",
-             (void*)kIslandBeg, (void*)kIslandEnd);
-    }
-    // Should not be very performance-critical.
-    internal_memset(island_allocator_pos, 0xCC, kIslandEnd - kIslandBeg);
-  };
-  *ptr = island_allocator_pos;
-  island_allocator_pos = (char*)island_allocator_pos + GetPageSizeCached();
-  if (flags()->verbosity) {
-    Report("Branch island allocated at %p\n", *ptr);
-  }
-  return err_none;
-}
-
-extern "C"
-mach_error_t __interception_deallocate_island(void *ptr) {
-  // Do nothing.
-  // TODO(glider): allow to free and reuse the island memory.
-  return err_none;
-}
-
 // Support for the following functions from libdispatch on Mac OS:
 //   dispatch_async_f()
 //   dispatch_async()
@@ -350,14 +296,7 @@
                                asan_dispatch_call_block_and_release);
 }
 
-#if MAC_INTERPOSE_FUNCTIONS && !defined(MISSING_BLOCKS_SUPPORT)
-// dispatch_async, dispatch_group_async and others tailcall the corresponding
-// dispatch_*_f functions. When wrapping functions with mach_override, those
-// dispatch_*_f are intercepted automatically. But with dylib interposition
-// this does not work, because the calls within the same library are not
-// interposed.
-// Therefore we need to re-implement dispatch_async and friends.
-
+#if !defined(MISSING_BLOCKS_SUPPORT)
 extern "C" {
 // FIXME: consolidate these declarations with asan_intercepted_functions.h.
 void dispatch_async(dispatch_queue_t dq, void(^work)(void));
@@ -410,16 +349,4 @@
 }
 #endif
 
-namespace __asan {
-
-void InitializeMacInterceptors() {
-  CHECK(INTERCEPT_FUNCTION(dispatch_async_f));
-  CHECK(INTERCEPT_FUNCTION(dispatch_sync_f));
-  CHECK(INTERCEPT_FUNCTION(dispatch_after_f));
-  CHECK(INTERCEPT_FUNCTION(dispatch_barrier_async_f));
-  CHECK(INTERCEPT_FUNCTION(dispatch_group_async_f));
-}
-
-}  // namespace __asan
-
 #endif  // __APPLE__
Index: libsanitizer/asan/asan_allocator2.cc
===================================================================
--- libsanitizer/asan/asan_allocator2.cc	(revision 195997)
+++ libsanitizer/asan/asan_allocator2.cc	(working copy)
@@ -20,7 +20,6 @@
 #include "asan_report.h"
 #include "asan_thread.h"
 #include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_allocator.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_list.h"
@@ -55,7 +54,11 @@
 };
 
 #if SANITIZER_WORDSIZE == 64
+#if defined(__powerpc64__)
+const uptr kAllocatorSpace =  0xa0000000000ULL;
+#else
 const uptr kAllocatorSpace = 0x600000000000ULL;
+#endif
 const uptr kAllocatorSize  =  0x10000000000ULL;  // 1T.
 typedef DefaultSizeClassMap SizeClassMap;
 typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
@@ -89,8 +92,6 @@
 static const uptr kMaxThreadLocalQuarantine =
   FIRST_32_SECOND_64(1 << 18, 1 << 20);
 
-static const uptr kReturnOnZeroMalloc = 2048;  // Zero page is protected.
-
 // 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.
@@ -112,7 +113,7 @@
   CHECK_GE(rz_size, 16);
   CHECK_LE(rz_size, 2048);
   CHECK(IsPowerOfTwo(rz_size));
-  u32 res = __builtin_ctz(rz_size) - 4;
+  u32 res = Log2(rz_size) - 4;
   CHECK_EQ(rz_size, RZLog2Size(res));
   return res;
 }
@@ -289,27 +290,26 @@
   AllocatorCache *cache_;
 };
 
-static void Init() {
-  static int inited = 0;
-  if (inited) return;
-  __asan_init();
-  inited = true;  // this must happen before any threads are created.
+void InitializeAllocator() {
   allocator.Init();
   quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
 }
 
 static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
                       AllocType alloc_type) {
-  Init();
+  if (!asan_inited)
+    __asan_init();
   CHECK(stack);
   const uptr min_alignment = SHADOW_GRANULARITY;
   if (alignment < min_alignment)
     alignment = min_alignment;
   if (size == 0) {
-    if (alignment <= kReturnOnZeroMalloc)
-      return reinterpret_cast<void *>(kReturnOnZeroMalloc);
-    else
-      return 0;  // 0 bytes with large alignment requested. Just return 0.
+    // We'd be happy to avoid allocating memory for zero-size requests, but
+    // some programs/tests depend on this behavior and assume that malloc would
+    // not return NULL even for zero-size allocations. Moreover, it looks like
+    // operator new should never return NULL, and results of consecutive "new"
+    // calls must be different even if the allocated size is zero.
+    size = 1;
   }
   CHECK(IsPowerOfTwo(alignment));
   uptr rz_log = ComputeRZLog(size);
@@ -415,7 +415,8 @@
 
 static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
   uptr p = reinterpret_cast<uptr>(ptr);
-  if (p == 0 || p == kReturnOnZeroMalloc) return;
+  if (p == 0) return;
+  ASAN_FREE_HOOK(ptr);
   uptr chunk_beg = p - kChunkHeaderSize;
   AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
 
@@ -465,8 +466,6 @@
     quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac),
                    m, m->UsedSize());
   }
-
-  ASAN_FREE_HOOK(ptr);
 }
 
 static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
@@ -546,7 +545,7 @@
       return right_chunk;
   }
   // Same chunk_state: choose based on offset.
-  uptr l_offset = 0, r_offset = 0;
+  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)
@@ -557,7 +556,7 @@
 AsanChunkView FindHeapChunkByAddress(uptr addr) {
   AsanChunk *m1 = GetAsanChunkByAddr(addr);
   if (!m1) return AsanChunkView(m1);
-  uptr offset = 0;
+  sptr offset = 0;
   if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) {
     // The address is in the chunk's left redzone, so maybe it is actually
     // a right buffer overflow from the other chunk to the left.
@@ -601,6 +600,7 @@
 }
 
 void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
+  if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
   void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC);
   if (ptr)
     REAL(memset)(ptr, 0, nmemb * size);
@@ -649,16 +649,17 @@
 }
 
 uptr asan_mz_size(const void *ptr) {
-  UNIMPLEMENTED();
-  return 0;
+  return AllocationSize(reinterpret_cast<uptr>(ptr));
 }
 
 void asan_mz_force_lock() {
-  UNIMPLEMENTED();
+  allocator.ForceLock();
+  fallback_mutex.Lock();
 }
 
 void asan_mz_force_unlock() {
-  UNIMPLEMENTED();
+  fallback_mutex.Unlock();
+  allocator.ForceUnlock();
 }
 
 }  // namespace __asan
@@ -674,7 +675,7 @@
 
 bool __asan_get_ownership(const void *p) {
   uptr ptr = reinterpret_cast<uptr>(p);
-  return (ptr == kReturnOnZeroMalloc) || (AllocationSize(ptr) > 0);
+  return (AllocationSize(ptr) > 0);
 }
 
 uptr __asan_get_allocated_size(const void *p) {
@@ -682,7 +683,7 @@
   uptr ptr = reinterpret_cast<uptr>(p);
   uptr allocated_size = AllocationSize(ptr);
   // Die if p is not malloced or if it is already freed.
-  if (allocated_size == 0 && ptr != kReturnOnZeroMalloc) {
+  if (allocated_size == 0) {
     GET_STACK_TRACE_FATAL_HERE;
     ReportAsanGetAllocatedSizeNotOwned(ptr, &stack);
   }
Index: libsanitizer/asan/asan_stack.cc
===================================================================
--- libsanitizer/asan/asan_stack.cc	(revision 195997)
+++ libsanitizer/asan/asan_stack.cc	(working copy)
@@ -9,9 +9,9 @@
 //
 // Code for ASan stack trace.
 //===----------------------------------------------------------------------===//
+#include "asan_internal.h"
 #include "asan_flags.h"
 #include "asan_stack.h"
-#include "sanitizer/asan_interface.h"
 
 namespace __asan {
 
Index: libsanitizer/asan/asan_report.cc
===================================================================
--- libsanitizer/asan/asan_report.cc	(revision 195997)
+++ libsanitizer/asan/asan_report.cc	(working copy)
@@ -118,19 +118,7 @@
   Printf("\n");
 }
 
-static void PrintShadowMemoryForAddress(uptr addr) {
-  if (!AddrIsInMem(addr))
-    return;
-  uptr shadow_addr = MemToShadow(addr);
-  const uptr n_bytes_per_row = 16;
-  uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
-  Printf("Shadow bytes around the buggy address:\n");
-  for (int i = -5; i <= 5; i++) {
-    const char *prefix = (i == 0) ? "=>" : "  ";
-    PrintShadowBytes(prefix,
-                     (u8*)(aligned_shadow + i * n_bytes_per_row),
-                     (u8*)shadow_addr, n_bytes_per_row);
-  }
+static void PrintLegend() {
   Printf("Shadow byte legend (one shadow byte represents %d "
          "application bytes):\n", (int)SHADOW_GRANULARITY);
   PrintShadowByte("  Addressable:           ", 0);
@@ -153,6 +141,23 @@
   PrintShadowByte("  ASan internal:         ", kAsanInternalHeapMagic);
 }
 
+static void PrintShadowMemoryForAddress(uptr addr) {
+  if (!AddrIsInMem(addr))
+    return;
+  uptr shadow_addr = MemToShadow(addr);
+  const uptr n_bytes_per_row = 16;
+  uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
+  Printf("Shadow bytes around the buggy address:\n");
+  for (int i = -5; i <= 5; i++) {
+    const char *prefix = (i == 0) ? "=>" : "  ";
+    PrintShadowBytes(prefix,
+                     (u8*)(aligned_shadow + i * n_bytes_per_row),
+                     (u8*)shadow_addr, n_bytes_per_row);
+  }
+  if (flags()->print_legend)
+    PrintLegend();
+}
+
 static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
                                 const char *zone_name) {
   if (zone_ptr) {
@@ -183,18 +188,23 @@
   Printf("  '%s' is ascii string '%s'\n", g.name, (char*)g.beg);
 }
 
-bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g) {
-  if (addr < g.beg - kGlobalAndStackRedzone) return false;
+bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
+                                     const __asan_global &g) {
+  static const uptr kMinimalDistanceFromAnotherGlobal = 64;
+  if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
   if (addr >= g.beg + g.size_with_redzone) return false;
   Decorator d;
   Printf("%s", d.Location());
-  Printf("%p is located ", (void*)addr);
   if (addr < g.beg) {
-    Printf("%zd bytes to the left", g.beg - addr);
-  } else if (addr >= g.beg + g.size) {
-    Printf("%zd bytes to the right", addr - (g.beg + g.size));
+    Printf("%p is located %zd bytes to the left", (void*)addr, g.beg - addr);
+  } else if (addr + size > g.beg + g.size) {
+    if (addr < g.beg + g.size)
+      addr = g.beg + g.size;
+    Printf("%p is located %zd bytes to the right", (void*)addr,
+           addr - (g.beg + g.size));
   } else {
-    Printf("%zd bytes inside", addr - g.beg);  // Can it happen?
+    // Can it happen?
+    Printf("%p is located %zd bytes inside", (void*)addr, addr - g.beg);
   }
   Printf(" of global variable '%s' (0x%zx) of size %zu\n",
              g.name, g.beg, g.size);
@@ -280,18 +290,22 @@
 
 static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
                                       uptr access_size) {
-  uptr offset;
+  sptr offset;
   Decorator d;
   Printf("%s", d.Location());
-  Printf("%p is located ", (void*)addr);
-  if (chunk.AddrIsInside(addr, access_size, &offset)) {
-    Printf("%zu bytes inside of", offset);
-  } else if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
-    Printf("%zu bytes to the left of", offset);
+  if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
+    Printf("%p is located %zd bytes to the left of", (void*)addr, offset);
   } else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
-    Printf("%zu bytes to the right of", offset);
+    if (offset < 0) {
+      addr -= offset;
+      offset = 0;
+    }
+    Printf("%p is located %zd bytes to the right of", (void*)addr, offset);
+  } else if (chunk.AddrIsInside(addr, access_size, &offset)) {
+    Printf("%p is located %zd bytes inside of", (void*)addr, offset);
   } else {
-    Printf(" somewhere around (this is AddressSanitizer bug!)");
+    Printf("%p is located somewhere around (this is AddressSanitizer bug!)",
+           (void*)addr);
   }
   Printf(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
          (void*)(chunk.Beg()), (void*)(chunk.End()));
@@ -364,7 +378,7 @@
   if (DescribeAddressIfShadow(addr))
     return;
   CHECK(AddrIsInMem(addr));
-  if (DescribeAddressIfGlobal(addr))
+  if (DescribeAddressIfGlobal(addr, access_size))
     return;
   if (DescribeAddressIfStack(addr, access_size))
     return;
@@ -443,7 +457,8 @@
       DescribeThread(curr_thread->summary());
     }
     // Print memory stats.
-    __asan_print_accumulated_stats();
+    if (flags()->print_stats)
+      __asan_print_accumulated_stats();
     if (error_report_callback) {
       error_report_callback(error_message_buffer);
     }
@@ -452,6 +467,20 @@
   }
 };
 
+static void ReportSummary(const char *error_type, StackTrace *stack) {
+  if (!stack->size) return;
+  if (IsSymbolizerAvailable()) {
+    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);
+    ReportErrorSummary(error_type,
+                       StripPathPrefix(ai.file, flags()->strip_path_prefix),
+                       ai.line, ai.function);
+  }
+  // FIXME: do we need to print anything at all if there is no symbolizer?
+}
+
 void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
   ScopedInErrorReport in_report;
   Decorator d;
@@ -464,6 +493,7 @@
   Printf("AddressSanitizer can not provide additional info.\n");
   GET_STACK_TRACE_FATAL(pc, bp);
   PrintStack(&stack);
+  ReportSummary("SEGV", &stack);
 }
 
 void ReportDoubleFree(uptr addr, StackTrace *stack) {
@@ -474,6 +504,7 @@
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
+  ReportSummary("double-free", stack);
 }
 
 void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
@@ -485,6 +516,7 @@
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
+  ReportSummary("bad-free", stack);
 }
 
 void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
@@ -503,6 +535,7 @@
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
+  ReportSummary("alloc-dealloc-mismatch", stack);
   Report("HINT: if you don't care about these warnings you may set "
          "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
 }
@@ -517,6 +550,7 @@
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
+  ReportSummary("bad-malloc_usable_size", stack);
 }
 
 void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
@@ -529,6 +563,7 @@
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeHeapAddress(addr, 1);
+  ReportSummary("bad-__asan_get_allocated_size", stack);
 }
 
 void ReportStringFunctionMemoryRangesOverlap(
@@ -536,14 +571,17 @@
     const char *offset2, uptr length2, StackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
+  char bug_type[100];
+  internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
   Printf("%s", d.Warning());
-  Report("ERROR: AddressSanitizer: %s-param-overlap: "
+  Report("ERROR: AddressSanitizer: %s: "
              "memory ranges [%p,%p) and [%p, %p) overlap\n", \
-             function, offset1, offset1 + length1, offset2, offset2 + length2);
+             bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
   Printf("%s", d.EndWarning());
   PrintStack(stack);
   DescribeAddress((uptr)offset1, length1);
   DescribeAddress((uptr)offset2, length2);
+  ReportSummary(bug_type, stack);
 }
 
 // ----------------------- Mac-specific reports ----------------- {{{1
@@ -653,7 +691,7 @@
   PrintStack(&stack);
 
   DescribeAddress(addr, access_size);
-
+  ReportSummary(bug_descr, &stack);
   PrintShadowMemoryForAddress(addr);
 }
 
Index: libsanitizer/include/sanitizer/asan_interface.h
===================================================================
--- libsanitizer/include/sanitizer/asan_interface.h	(revision 195997)
+++ libsanitizer/include/sanitizer/asan_interface.h	(working copy)
@@ -5,69 +5,18 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file is a part of AddressSanitizer, an address sanity checker.
+// This file is a part of AddressSanitizer.
 //
-// This header can be included by the instrumented program to fetch
-// data (mostly allocator statistics) from ASan runtime library.
+// Public interface header.
 //===----------------------------------------------------------------------===//
 #ifndef SANITIZER_ASAN_INTERFACE_H
 #define SANITIZER_ASAN_INTERFACE_H
 
 #include <sanitizer/common_interface_defs.h>
 
-// ----------- ATTENTION -------------
-// This header should NOT include any other headers from ASan runtime.
-// All functions in this header are extern "C" and start with __asan_.
-
-using __sanitizer::uptr;
-
+#ifdef __cplusplus
 extern "C" {
-  // This function should be called at the very beginning of the process,
-  // before any instrumented code is executed and before any call to malloc.
-  void __asan_init() SANITIZER_INTERFACE_ATTRIBUTE;
-
-  // This structure describes an instrumented global variable.
-  struct __asan_global {
-    uptr beg;                // The address of the global.
-    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.
-    uptr has_dynamic_init;   // Non-zero if the global has dynamic initializer.
-  };
-
-  // These two functions should be called by the instrumented code.
-  // 'globals' is an array of structures describing 'n' globals.
-  void __asan_register_globals(__asan_global *globals, uptr n)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_unregister_globals(__asan_global *globals, uptr n)
-      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)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_after_dynamic_init()
-      SANITIZER_INTERFACE_ATTRIBUTE;
-
-  // These two functions are used by the instrumented code in the
-  // use-after-return mode. __asan_stack_malloc allocates size bytes of
-  // fake stack and __asan_stack_free poisons it. real_stack is a pointer to
-  // the real stack region.
-  uptr __asan_stack_malloc(uptr size, uptr real_stack)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_stack_free(uptr ptr, uptr size, uptr real_stack)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-
-  // These two functions are used by instrumented code in the
-  // use-after-scope mode. They mark memory for local variables as
-  // unaddressable when they leave scope and addressable before the
-  // function exits.
-  void __asan_poison_stack_memory(uptr addr, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-  void __asan_unpoison_stack_memory(uptr addr, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
-
+#endif
   // Marks memory region [addr, addr+size) as unaddressable.
   // This memory must be previously allocated by the user program. Accessing
   // addresses in this region from instrumented code is forbidden until
@@ -76,8 +25,7 @@
   // to ASan alignment restrictions.
   // Method is NOT thread-safe in the sense that no two threads can
   // (un)poison memory in the same memory region simultaneously.
-  void __asan_poison_memory_region(void const volatile *addr, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_poison_memory_region(void const volatile *addr, size_t size);
   // Marks memory region [addr, addr+size) as addressable.
   // This memory must be previously allocated by the user program. Accessing
   // addresses in this region is allowed until this region is poisoned again.
@@ -85,14 +33,9 @@
   // ASan alignment restrictions.
   // Method is NOT thread-safe in the sense that no two threads can
   // (un)poison memory in the same memory region simultaneously.
-  void __asan_unpoison_memory_region(void const volatile *addr, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
 
-  // Performs cleanup before a NoReturn function. Must be called before things
-  // like _exit and execl to avoid false positives on stack.
-  void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE;
-
-// User code should use macro instead of functions.
+  // User code should use macro instead of functions.
 #if __has_feature(address_sanitizer)
 #define ASAN_POISON_MEMORY_REGION(addr, size) \
   __asan_poison_memory_region((addr), (size))
@@ -107,104 +50,86 @@
 
   // Returns true iff addr is poisoned (i.e. 1-byte read/write access to this
   // address will result in error report from AddressSanitizer).
-  bool __asan_address_is_poisoned(void const volatile *addr)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  bool __asan_address_is_poisoned(void const volatile *addr);
 
   // If at least on byte in [beg, beg+size) is poisoned, return the address
   // of the first such byte. Otherwise return 0.
-  uptr __asan_region_is_poisoned(uptr beg, uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void *__asan_region_is_poisoned(void *beg, size_t size);
 
   // Print the description of addr (useful when debugging in gdb).
-  void __asan_describe_address(uptr addr)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_describe_address(void *addr);
 
   // This is an internal function that is called to report an error.
   // However it is still a part of the interface because users may want to
   // set a breakpoint on this function in a debugger.
-  void __asan_report_error(uptr pc, uptr bp, uptr sp,
-                           uptr addr, bool is_write, uptr access_size)
-    SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_report_error(void *pc, void *bp, void *sp,
+                           void *addr, bool is_write, size_t access_size);
 
   // Sets the exit code to use when reporting an error.
   // Returns the old value.
-  int __asan_set_error_exit_code(int exit_code)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  int __asan_set_error_exit_code(int exit_code);
 
   // Sets the callback to be called right before death on error.
   // Passing 0 will unset the callback.
-  void __asan_set_death_callback(void (*callback)(void))
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_set_death_callback(void (*callback)(void));
 
-  void __asan_set_error_report_callback(void (*callback)(const char*))
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_set_error_report_callback(void (*callback)(const char*));
 
   // User may provide function that would be called right when ASan detects
   // an error. This can be used to notice cases when ASan detects an error, but
   // the program crashes before ASan report is printed.
-  /* OPTIONAL */ void __asan_on_error()
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_on_error();
 
   // User may provide its own implementation for symbolization function.
   // It should print the description of instruction at address "pc" to
   // "out_buffer". Description should be at most "out_size" bytes long.
   // User-specified function should return true if symbolization was
   // successful.
-  /* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
-                                       int out_size)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  bool __asan_symbolize(const void *pc, char *out_buffer,
+                                       int out_size);
 
   // Returns the estimated number of bytes that will be reserved by allocator
   // for request of "size" bytes. If ASan allocator can't allocate that much
   // memory, returns the maximal possible allocation size, otherwise returns
   // "size".
-  uptr __asan_get_estimated_allocated_size(uptr size)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_estimated_allocated_size(size_t size);
   // Returns true if p was returned by the ASan allocator and
   // is not yet freed.
-  bool __asan_get_ownership(const void *p)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  bool __asan_get_ownership(const void *p);
   // Returns the number of bytes reserved for the pointer p.
   // Requires (get_ownership(p) == true) or (p == 0).
-  uptr __asan_get_allocated_size(const void *p)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_allocated_size(const void *p);
   // Number of bytes, allocated and not yet freed by the application.
-  uptr __asan_get_current_allocated_bytes()
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_current_allocated_bytes();
   // Number of bytes, mmaped by asan 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).
-  uptr __asan_get_heap_size()
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_heap_size();
   // Number of bytes, mmaped by asan 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 __asan_get_free_bytes() later.
-  uptr __asan_get_free_bytes()
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_free_bytes();
   // Number of bytes in unmapped pages, that are released to OS. Currently,
   // always returns 0.
-  uptr __asan_get_unmapped_bytes()
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  size_t __asan_get_unmapped_bytes();
   // Prints accumulated stats to stderr. Used for debugging.
-  void __asan_print_accumulated_stats()
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_print_accumulated_stats();
 
   // This function may be optionally provided by user and should return
   // a string containing ASan runtime options. See asan_flags.h for details.
-  /* OPTIONAL */ const char* __asan_default_options()
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  const char* __asan_default_options();
 
   // Malloc hooks that may be optionally provided by user.
   // __asan_malloc_hook(ptr, size) is called immediately after
   //   allocation of "size" bytes, which returned "ptr".
   // __asan_free_hook(ptr) is called immediately before
   //   deallocation of "ptr".
-  /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
-  /* OPTIONAL */ void __asan_free_hook(void *ptr)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_malloc_hook(void *ptr, size_t size);
+  void __asan_free_hook(void *ptr);
+#ifdef __cplusplus
 }  // extern "C"
+#endif
 
 #endif  // SANITIZER_ASAN_INTERFACE_H
Index: libsanitizer/include/sanitizer/common_interface_defs.h
===================================================================
--- libsanitizer/include/sanitizer/common_interface_defs.h	(revision 195997)
+++ libsanitizer/include/sanitizer/common_interface_defs.h	(working copy)
@@ -5,86 +5,37 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file is shared between AddressSanitizer and ThreadSanitizer.
-// It contains basic macro and types.
-// NOTE: This file may be included into user code.
+// Common part of the public sanitizer interface.
 //===----------------------------------------------------------------------===//
 
 #ifndef SANITIZER_COMMON_INTERFACE_DEFS_H
 #define SANITIZER_COMMON_INTERFACE_DEFS_H
 
-// ----------- ATTENTION -------------
-// This header should NOT include any other headers to avoid portability issues.
+#include <stddef.h>
+#include <stdint.h>
 
-#if defined(_WIN32)
-// FIXME find out what we need on Windows. __declspec(dllexport) ?
-# define SANITIZER_INTERFACE_ATTRIBUTE
-# define SANITIZER_WEAK_ATTRIBUTE
-#elif defined(SANITIZER_GO)
-# define SANITIZER_INTERFACE_ATTRIBUTE
-# define SANITIZER_WEAK_ATTRIBUTE
-#else
-# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
-# define SANITIZER_WEAK_ATTRIBUTE  __attribute__((weak))
-#endif
-
-#ifdef __linux__
-# define SANITIZER_SUPPORTS_WEAK_HOOKS 1
-#else
-# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
-#endif
-
-// __has_feature
-#if !defined(__has_feature)
-# define __has_feature(x) 0
-#endif
-
-// For portability reasons we do not include stddef.h, stdint.h or any other
-// system header, but we do need some basic types that are not defined
-// in a portable way by the language itself.
-namespace __sanitizer {
-
-#if defined(_WIN64)
-// 64-bit Windows uses LLP64 data model.
-typedef unsigned long long uptr;  // NOLINT
-typedef signed   long long sptr;  // NOLINT
-#else
-typedef unsigned long uptr;  // NOLINT
-typedef signed   long sptr;  // NOLINT
-#endif  // defined(_WIN64)
-#if defined(__x86_64__)
-// Since x32 uses ILP32 data model in 64-bit hardware mode,  we must use
-// 64-bit pointer to unwind stack frame.
-typedef unsigned long long uhwptr;  // NOLINT
-#else
-typedef uptr uhwptr;   // NOLINT
-#endif
-typedef unsigned char u8;
-typedef unsigned short u16;  // NOLINT
-typedef unsigned int u32;
-typedef unsigned long long u64;  // NOLINT
-typedef signed   char s8;
-typedef signed   short s16;  // NOLINT
-typedef signed   int s32;
-typedef signed   long long s64;  // NOLINT
-
-}  // namespace __sanitizer
-
+#ifdef __cplusplus
 extern "C" {
+#endif
   // Tell the tools to write their reports to "path.<pid>" instead of stderr.
-  void __sanitizer_set_report_path(const char *path)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __sanitizer_set_report_path(const char *path);
 
   // Tell the tools to write their reports to given file descriptor instead of
   // stderr.
-  void __sanitizer_set_report_fd(int fd)
-      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __sanitizer_set_report_fd(int fd);
 
   // Notify the tools that the sandbox is going to be turned on. The reserved
   // parameter will be used in the future to hold a structure with functions
   // that the tools may call to bypass the sandbox.
-  void __sanitizer_sandbox_on_notify(void *reserved)
-      SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+  void __sanitizer_sandbox_on_notify(void *reserved);
+
+  // This function is called by the tool when it has just finished reporting
+  // an error. 'error_summary' is a one-line string that summarizes
+  // the error message. This function can be overridden by the client.
+  void __sanitizer_report_error_summary(const char *error_summary);
+
+#ifdef __cplusplus
 }  // extern "C"
+#endif
 
 #endif  // SANITIZER_COMMON_INTERFACE_DEFS_H
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 195997)
+++ gcc/config/i386/i386.c	(working copy)
@@ -5436,7 +5436,9 @@
 static unsigned HOST_WIDE_INT
 ix86_asan_shadow_offset (void)
 {
-  return (unsigned HOST_WIDE_INT) 1 << (TARGET_LP64 ? 44 : 29);
+  return TARGET_LP64 ? (TARGET_MACHO ? (HOST_WIDE_INT_1 << 44)
+				     : HOST_WIDE_INT_C (0x7fff8000))
+		     : (HOST_WIDE_INT_1 << 29);
 }
 \f
 /* Argument support functions.  */
Index: gcc/sanitizer.def
===================================================================
--- gcc/sanitizer.def	(revision 195997)
+++ gcc/sanitizer.def	(working copy)
@@ -27,7 +27,7 @@
    for other FEs by asan.c.  */
 
 /* Address Sanitizer */
-DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init",
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init_v1",
 		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 /* Do not reorder the BUILT_IN_ASAN_REPORT* builtins, e.g. cfgcleanup.c
    relies on this order.  */
Index: gcc/ChangeLog
===================================================================
--- gcc/ChangeLog	(revision 195997)
+++ gcc/ChangeLog	(working copy)
@@ -1,3 +1,9 @@
+2013-02-13  Kostya Serebryany  <kcc@google.com>
+
+	* config/i386/i386.c: Use 0x7fff8000 as asan_shadow_offset on x86_64
+	linux.
+	* sanitizer.def: Rename __asan_init to __asan_init_v1.
+
 2013-02-12  Vladimir Makarov  <vmakarov@redhat.com>
 
 	PR inline-asm/56148
Index: gcc/testsuite/ChangeLog
===================================================================
--- gcc/testsuite/ChangeLog	(revision 195997)
+++ gcc/testsuite/ChangeLog	(working copy)
@@ -1,3 +1,9 @@
+2013-02-13  Kostya Serebryany  <kcc@google.com>
+
+	* c-c++-common/asan/strncpy-overflow-1.c: Update the test
+	to match the fresh asan run-time.
+	* c-c++-common/asan/rlimit-mmap-test-1.c: Ditto.
+
 2013-02-12  Vladimir Makarov  <vmakarov@redhat.com>
 
 	PR inline-asm/56148
Index: gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(revision 195997)
+++ gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(working copy)
@@ -12,7 +12,7 @@
   return short_buffer[8];
 }
 
-/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "WRITE of size \[0-9\]* at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*strncpy-overflow-1.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c	(revision 195997)
+++ gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c	(working copy)
@@ -18,4 +18,4 @@
   return 0;
 }
 
-/* { dg-output "AddressSanitizer is unable to mmap" } */
+/* { dg-output "ERROR: Failed to mmap" } */

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 10:28   ` Konstantin Serebryany
@ 2013-02-13 10:32     ` Jakub Jelinek
  2013-02-13 11:59       ` Jakub Jelinek
  2013-02-13 14:46       ` Jack Howarth
  0 siblings, 2 replies; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-13 10:32 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 02:28:25PM +0400, Konstantin Serebryany wrote:
> Right. In LLVM we test only with ASAN_FLEXIBLE_MAPPING_AND_OFFSET==1,
> so this came unnoticed.
> Fixed in r175049.
...

This is ok, thanks.

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 10:32     ` Jakub Jelinek
@ 2013-02-13 11:59       ` Jakub Jelinek
  2013-02-13 12:33         ` Konstantin Serebryany
  2013-02-13 14:46       ` Jack Howarth
  1 sibling, 1 reply; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-13 11:59 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 11:32:00AM +0100, Jakub Jelinek wrote:
> On Wed, Feb 13, 2013 at 02:28:25PM +0400, Konstantin Serebryany wrote:
> > Right. In LLVM we test only with ASAN_FLEXIBLE_MAPPING_AND_OFFSET==1,
> > so this came unnoticed.
> > Fixed in r175049.
> ...
> 
> This is ok, thanks.

Unfortunately, it seems everything fails with that change :( on Linux.
The problem is that the default prelink library range for x86_64 is
0x3000000000LL to 0x4000000000LL, and that unfortunately overlaps
with the 0x7fff8000LL to 0x10007fff8000LL range that asan wants to use
for the shadow mapping.  And the reason for that prelink default range is
that earlier (see e.g.
http://lwn.net/Articles/106177/
) Linux on x86_64 used much smaller virtual address space than it does now.
Not sure if there are still systems running pre-2.6.9 kernels or whenever the PML4
change made it into Linux kernel on x86-64 and whether people use prelink on
them.  But in any case, even if I change the prelink range now (perhaps
conditionally on the size of address space detected by prelink), it will
still cause issues.

So, either we need to revert that i386.c and asan_mapping.h (SHADOW_OFFSET)
change, or support non-contiguous shadow memory for the Linux x86-64 case.
What could work is if we had:

0x000000000000  -	0x00007fff8000	low memory
0x00007fff8000	-	0x00008fff7000	shadow mem for low memory
0x00008fff7000	-	0x00067fff8000	protected
0x00067fff8000	-	0x00087fff8000	shadow mem for mid memory
0x00087fff8000	-	0x003000000000	protected
0x003000000000  -	0x004000000000	mid memory
0x004000000000	-	0x02008fff7000	protected
0x02008fff7000	-	0x10007fff8000	shadow mem for high memory
0x10007fff8000	-	0x7fffffffffff	high memory

asan_mapping.h then would need to introduce AddrIsInMidMem and
AddrIsInMidShadow inlines (perhaps defined to false for configurations
that don't need 3 part memory), use those in AddrIsInMem
and AddrIsInShadow, tweak AddrIsInShadowGap (as it has now more gaps)
for this configuration and tweak the mapping code.

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 11:59       ` Jakub Jelinek
@ 2013-02-13 12:33         ` Konstantin Serebryany
  2013-02-13 12:48           ` Jakub Jelinek
  0 siblings, 1 reply; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-13 12:33 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 3:59 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Feb 13, 2013 at 11:32:00AM +0100, Jakub Jelinek wrote:
>> On Wed, Feb 13, 2013 at 02:28:25PM +0400, Konstantin Serebryany wrote:
>> > Right. In LLVM we test only with ASAN_FLEXIBLE_MAPPING_AND_OFFSET==1,
>> > so this came unnoticed.
>> > Fixed in r175049.
>> ...
>>
>> This is ok, thanks.
>
> Unfortunately, it seems everything fails with that change :( on Linux.
> The problem is that the default prelink library range for x86_64 is
> 0x3000000000LL to 0x4000000000LL, and that unfortunately overlaps

Forgive my ignorance, what is the  default prelink library range?

> with the 0x7fff8000LL to 0x10007fff8000LL range that asan wants to use
> for the shadow mapping.  And the reason for that prelink default range is
> that earlier (see e.g.
> http://lwn.net/Articles/106177/
> ) Linux on x86_64 used much smaller virtual address space than it does now.
> Not sure if there are still systems running pre-2.6.9 kernels or whenever the PML4
> change made it into Linux kernel on x86-64 and whether people use prelink on
> them.  But in any case, even if I change the prelink range now (perhaps
> conditionally on the size of address space detected by prelink), it will
> still cause issues.
>
> So, either we need to revert that i386.c and asan_mapping.h (SHADOW_OFFSET)
> change, or support non-contiguous shadow memory for the Linux x86-64 case.

I suggest to either revert or (better) to support flexible mapping and
revert the offset only in the gcc compiler module
(leaving asan-rt unchanged).

non-contiguous shadow memory sounds too scary and costly to support,
not worth the benefit.

> What could work is if we had:
>
> 0x000000000000  -       0x00007fff8000  low memory
> 0x00007fff8000  -       0x00008fff7000  shadow mem for low memory
> 0x00008fff7000  -       0x00067fff8000  protected
> 0x00067fff8000  -       0x00087fff8000  shadow mem for mid memory
> 0x00087fff8000  -       0x003000000000  protected
> 0x003000000000  -       0x004000000000  mid memory
> 0x004000000000  -       0x02008fff7000  protected
> 0x02008fff7000  -       0x10007fff8000  shadow mem for high memory
> 0x10007fff8000  -       0x7fffffffffff  high memory
>
> asan_mapping.h then would need to introduce AddrIsInMidMem and
> AddrIsInMidShadow inlines (perhaps defined to false for configurations
> that don't need 3 part memory), use those in AddrIsInMem
> and AddrIsInShadow, tweak AddrIsInShadowGap (as it has now more gaps)
> for this configuration and tweak the mapping code.
>
>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 12:33         ` Konstantin Serebryany
@ 2013-02-13 12:48           ` Jakub Jelinek
  2013-02-13 12:58             ` Konstantin Serebryany
  0 siblings, 1 reply; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-13 12:48 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 04:32:33PM +0400, Konstantin Serebryany wrote:
> > Unfortunately, it seems everything fails with that change :( on Linux.
> > The problem is that the default prelink library range for x86_64 is
> > 0x3000000000LL to 0x4000000000LL, and that unfortunately overlaps
> 
> Forgive my ignorance, what is the  default prelink library range?

Prelink is a program of mine (see e.g.
http://people.redhat.com/jakub/prelink.pdf
) that speeds up dynamic linking of programs.
It is used by default on various Linux distributions.  prelinked shared
libraries (and dynamic linker) have their base addresses chosen by the
prelink program (and, by default in the default range of shared libraries
for the architecture, which is 0x3000000000LL to 0x4000000000LL for x86_64).
The addresses are usually (depending on prelink options) randomized upon
prelinking, so different hosts use different addresses and the same host
even after a while uses different addresses too, but by default for a few
weeks, if say glibc isn't upgraded in between, you get the same addresses
for the libraries all the time.
So, you get something like:
cat /proc/self/maps
00400000-0040b000 r-xp 00000000 08:02 1201920                            /usr/bin/cat
0060a000-0060b000 r--p 0000a000 08:02 1201920                            /usr/bin/cat
0060b000-0060c000 rw-p 0000b000 08:02 1201920                            /usr/bin/cat
01431000-01452000 rw-p 00000000 00:00 0                                  [heap]
3fe9400000-3fe9420000 r-xp 00000000 08:02 1179965                        /usr/lib64/ld-2.15.so
3fe961f000-3fe9620000 r--p 0001f000 08:02 1179965                        /usr/lib64/ld-2.15.so
3fe9620000-3fe9621000 rw-p 00020000 08:02 1179965                        /usr/lib64/ld-2.15.so
3fe9621000-3fe9622000 rw-p 00000000 00:00 0 
3fe9800000-3fe99ac000 r-xp 00000000 08:02 1180697                        /usr/lib64/libc-2.15.so
3fe99ac000-3fe9bac000 ---p 001ac000 08:02 1180697                        /usr/lib64/libc-2.15.so
3fe9bac000-3fe9bb0000 r--p 001ac000 08:02 1180697                        /usr/lib64/libc-2.15.so
3fe9bb0000-3fe9bb2000 rw-p 001b0000 08:02 1180697                        /usr/lib64/libc-2.15.so
3fe9bb2000-3fe9bb7000 rw-p 00000000 00:00 0 
7fae406f5000-7fae46b22000 r--p 00000000 08:02 1215605                    /usr/lib/locale/locale-archive
7fae46b22000-7fae46b25000 rw-p 00000000 00:00 0 
7fae46b42000-7fae46b43000 rw-p 00000000 00:00 0 
7fffe04f7000-7fffe0518000 rw-p 00000000 00:00 0                          [stack]
7fffe05e6000-7fffe05e7000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

Perhaps Ubuntu doesn't enable prelink by default, but all the world isn't Ubuntu.

> I suggest to either revert or (better) to support flexible mapping and
> revert the offset only in the gcc compiler module
> (leaving asan-rt unchanged).

I don't see how could flexible mapping help in this case, it just can't work either.
The only exception are PIE binaries, which by design aren't prelinked and kernel
for them disregards the prelinking of the dynamic linker, so the dynamic linker
for PIEs isn't loaded at the prelink chosen address, but at some randomized address.

If you try -Wl,-Ttext* with flexible mapping and use either zero base, or say 0x7fff8000,
you run into the exactly same issues, wether with gcc or clang.

> non-contiguous shadow memory sounds too scary and costly to support,
> not worth the benefit.

Why do you think it should be too costly?

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 12:48           ` Jakub Jelinek
@ 2013-02-13 12:58             ` Konstantin Serebryany
  2013-02-13 13:07               ` Jakub Jelinek
  0 siblings, 1 reply; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-13 12:58 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 4:48 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Feb 13, 2013 at 04:32:33PM +0400, Konstantin Serebryany wrote:
>> > Unfortunately, it seems everything fails with that change :( on Linux.
>> > The problem is that the default prelink library range for x86_64 is
>> > 0x3000000000LL to 0x4000000000LL, and that unfortunately overlaps
>>
>> Forgive my ignorance, what is the  default prelink library range?
>
> Prelink is a program of mine (see e.g.
> http://people.redhat.com/jakub/prelink.pdf
> ) that speeds up dynamic linking of programs.
> It is used by default on various Linux distributions.

Can it be disabled somehow (for asan)?

>  prelinked shared
> libraries (and dynamic linker) have their base addresses chosen by the
> prelink program (and, by default in the default range of shared libraries
> for the architecture, which is 0x3000000000LL to 0x4000000000LL for x86_64).
> The addresses are usually (depending on prelink options) randomized upon
> prelinking, so different hosts use different addresses and the same host
> even after a while uses different addresses too, but by default for a few
> weeks, if say glibc isn't upgraded in between, you get the same addresses
> for the libraries all the time.
> So, you get something like:
> cat /proc/self/maps
> 00400000-0040b000 r-xp 00000000 08:02 1201920                            /usr/bin/cat
> 0060a000-0060b000 r--p 0000a000 08:02 1201920                            /usr/bin/cat
> 0060b000-0060c000 rw-p 0000b000 08:02 1201920                            /usr/bin/cat
> 01431000-01452000 rw-p 00000000 00:00 0                                  [heap]
> 3fe9400000-3fe9420000 r-xp 00000000 08:02 1179965                        /usr/lib64/ld-2.15.so
> 3fe961f000-3fe9620000 r--p 0001f000 08:02 1179965                        /usr/lib64/ld-2.15.so
> 3fe9620000-3fe9621000 rw-p 00020000 08:02 1179965                        /usr/lib64/ld-2.15.so
> 3fe9621000-3fe9622000 rw-p 00000000 00:00 0
> 3fe9800000-3fe99ac000 r-xp 00000000 08:02 1180697                        /usr/lib64/libc-2.15.so
> 3fe99ac000-3fe9bac000 ---p 001ac000 08:02 1180697                        /usr/lib64/libc-2.15.so
> 3fe9bac000-3fe9bb0000 r--p 001ac000 08:02 1180697                        /usr/lib64/libc-2.15.so
> 3fe9bb0000-3fe9bb2000 rw-p 001b0000 08:02 1180697                        /usr/lib64/libc-2.15.so
> 3fe9bb2000-3fe9bb7000 rw-p 00000000 00:00 0
> 7fae406f5000-7fae46b22000 r--p 00000000 08:02 1215605                    /usr/lib/locale/locale-archive
> 7fae46b22000-7fae46b25000 rw-p 00000000 00:00 0
> 7fae46b42000-7fae46b43000 rw-p 00000000 00:00 0
> 7fffe04f7000-7fffe0518000 rw-p 00000000 00:00 0                          [stack]
> 7fffe05e6000-7fffe05e7000 r-xp 00000000 00:00 0                          [vdso]
> ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
>
> Perhaps Ubuntu doesn't enable prelink by default, but all the world isn't Ubuntu.
>
>> I suggest to either revert or (better) to support flexible mapping and
>> revert the offset only in the gcc compiler module
>> (leaving asan-rt unchanged).
>
> I don't see how could flexible mapping help in this case, it just can't work either.

If we enabled flexible mapping in the gcc build (making it more
similar to the llvm build)
we will be able to use the old 2^44 offset w/o changing the asan-rt.

> The only exception are PIE binaries, which by design aren't prelinked and kernel
> for them disregards the prelinking of the dynamic linker, so the dynamic linker
> for PIEs isn't loaded at the prelink chosen address, but at some randomized address.
>
> If you try -Wl,-Ttext* with flexible mapping and use either zero base, or say 0x7fff8000,
> you run into the exactly same issues, wether with gcc or clang.
>
>> non-contiguous shadow memory sounds too scary and costly to support,
>> not worth the benefit.
>
> Why do you think it should be too costly?

That's yet another set of spaghetti ifdefs.
I'd rather revert the whole thing back to 2^44 than do that.

--kcc

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 12:58             ` Konstantin Serebryany
@ 2013-02-13 13:07               ` Jakub Jelinek
  2013-02-13 13:28                 ` Richard Biener
  2013-02-13 13:39                 ` Konstantin Serebryany
  0 siblings, 2 replies; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-13 13:07 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 04:57:30PM +0400, Konstantin Serebryany wrote:
> On Wed, Feb 13, 2013 at 4:48 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> > On Wed, Feb 13, 2013 at 04:32:33PM +0400, Konstantin Serebryany wrote:
> >> > Unfortunately, it seems everything fails with that change :( on Linux.
> >> > The problem is that the default prelink library range for x86_64 is
> >> > 0x3000000000LL to 0x4000000000LL, and that unfortunately overlaps
> >>
> >> Forgive my ignorance, what is the  default prelink library range?
> >
> > Prelink is a program of mine (see e.g.
> > http://people.redhat.com/jakub/prelink.pdf
> > ) that speeds up dynamic linking of programs.
> > It is used by default on various Linux distributions.
> 
> Can it be disabled somehow (for asan)?

No.  You can disable it for the whole system (prelink -ua), but that is not
a sane requirement to running sanitized programs.  There is
also LD_USE_LOAD_BIAS=0 env variable, but 1) that has to be set before
running the program, setting it from within libasan ctor is too late, and
more importantly 2) it still doesn't affect the mapping of the dynamic
linker.  So, with LD_USE_LOAD_BIAS=0 cat /proc/self/maps the
dynamic linker will be still mapped somewhere in the 0x3000000000 to
0x4000000000 range, just other shared libraries mapped in by the dynamic
linker, rather than kernel directly, will be placed at the randomized (and
usually high) addresses, typically 0x7fXXXXXXXXXX.

> If we enabled flexible mapping in the gcc build (making it more
> similar to the llvm build)
> we will be able to use the old 2^44 offset w/o changing the asan-rt.

Sure, but it will be then slower, I thought you are looking for ASAN speed
improvements.

> That's yet another set of spaghetti ifdefs.
> I'd rather revert the whole thing back to 2^44 than do that.

Please revert the two hunks now.  I'll try to implement it eventually and
try to convince you ;)

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 13:07               ` Jakub Jelinek
@ 2013-02-13 13:28                 ` Richard Biener
  2013-02-13 13:33                   ` Jakub Jelinek
  2013-02-13 13:39                 ` Konstantin Serebryany
  1 sibling, 1 reply; 36+ messages in thread
From: Richard Biener @ 2013-02-13 13:28 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Konstantin Serebryany, GCC Patches, Dodji Seketeli,
	Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 2:07 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Feb 13, 2013 at 04:57:30PM +0400, Konstantin Serebryany wrote:
>> On Wed, Feb 13, 2013 at 4:48 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> > On Wed, Feb 13, 2013 at 04:32:33PM +0400, Konstantin Serebryany wrote:
>> >> > Unfortunately, it seems everything fails with that change :( on Linux.
>> >> > The problem is that the default prelink library range for x86_64 is
>> >> > 0x3000000000LL to 0x4000000000LL, and that unfortunately overlaps
>> >>
>> >> Forgive my ignorance, what is the  default prelink library range?
>> >
>> > Prelink is a program of mine (see e.g.
>> > http://people.redhat.com/jakub/prelink.pdf
>> > ) that speeds up dynamic linking of programs.
>> > It is used by default on various Linux distributions.
>>
>> Can it be disabled somehow (for asan)?
>
> No.  You can disable it for the whole system (prelink -ua), but that is not
> a sane requirement to running sanitized programs.  There is
> also LD_USE_LOAD_BIAS=0 env variable, but 1) that has to be set before
> running the program, setting it from within libasan ctor is too late, and
> more importantly 2) it still doesn't affect the mapping of the dynamic
> linker.  So, with LD_USE_LOAD_BIAS=0 cat /proc/self/maps the
> dynamic linker will be still mapped somewhere in the 0x3000000000 to
> 0x4000000000 range, just other shared libraries mapped in by the dynamic
> linker, rather than kernel directly, will be placed at the randomized (and
> usually high) addresses, typically 0x7fXXXXXXXXXX.

ASAN could set an ELF flag on the executable to tell the kernel not
to use prelinked objects?  That is, similar to how we handle executable
stacks?

Richard.

>> If we enabled flexible mapping in the gcc build (making it more
>> similar to the llvm build)
>> we will be able to use the old 2^44 offset w/o changing the asan-rt.
>
> Sure, but it will be then slower, I thought you are looking for ASAN speed
> improvements.
>
>> That's yet another set of spaghetti ifdefs.
>> I'd rather revert the whole thing back to 2^44 than do that.
>
> Please revert the two hunks now.  I'll try to implement it eventually and
> try to convince you ;)
>
>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 13:28                 ` Richard Biener
@ 2013-02-13 13:33                   ` Jakub Jelinek
  0 siblings, 0 replies; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-13 13:33 UTC (permalink / raw)
  To: Richard Biener
  Cc: Konstantin Serebryany, GCC Patches, Dodji Seketeli,
	Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 02:27:56PM +0100, Richard Biener wrote:
> ASAN could set an ELF flag on the executable to tell the kernel not
> to use prelinked objects?  That is, similar to how we handle executable
> stacks?

But we don't have such a flag right now, and what should old kernels that
don't support it do with that flag?  Should it be some kind of flag that
causes the programs not to run at all on kernel < 3.9 or whenever the flag
would be handled (can be done with .note.ABI-tag section, plus some flag
somewhere), or something else?  In any case, that would mean changes all
through the toolchain (glibc, linkers, kernel), compared to changing
two files in libsanitizer/asan/ (asan_mapping.h and asan_rtl.cc I believe).

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 13:07               ` Jakub Jelinek
  2013-02-13 13:28                 ` Richard Biener
@ 2013-02-13 13:39                 ` Konstantin Serebryany
  2013-02-13 15:19                   ` Jakub Jelinek
  1 sibling, 1 reply; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-13 13:39 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 5:07 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Feb 13, 2013 at 04:57:30PM +0400, Konstantin Serebryany wrote:
>> On Wed, Feb 13, 2013 at 4:48 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> > On Wed, Feb 13, 2013 at 04:32:33PM +0400, Konstantin Serebryany wrote:
>> >> > Unfortunately, it seems everything fails with that change :( on Linux.
>> >> > The problem is that the default prelink library range for x86_64 is
>> >> > 0x3000000000LL to 0x4000000000LL, and that unfortunately overlaps
>> >>
>> >> Forgive my ignorance, what is the  default prelink library range?
>> >
>> > Prelink is a program of mine (see e.g.
>> > http://people.redhat.com/jakub/prelink.pdf
>> > ) that speeds up dynamic linking of programs.
>> > It is used by default on various Linux distributions.
>>
>> Can it be disabled somehow (for asan)?
>
> No.  You can disable it for the whole system (prelink -ua), but that is not
> a sane requirement to running sanitized programs.

Why not?
:)

>> There is
> also LD_USE_LOAD_BIAS=0 env variable, but 1) that has to be set before
> running the program, setting it from within libasan ctor is too late,

This we can deal with.
We already setenv+reexec on Mac to solve similar issue with Mac's
dynamic run-time.

> and
> more importantly 2) it still doesn't affect the mapping of the dynamic
> linker.  So, with LD_USE_LOAD_BIAS=0 cat /proc/self/maps the
> dynamic linker will be still mapped somewhere in the 0x3000000000 to
> 0x4000000000 range, just other shared libraries mapped in by the dynamic
> linker, rather than kernel directly, will be placed at the randomized (and
> usually high) addresses, typically 0x7fXXXXXXXXXX.
>
>> If we enabled flexible mapping in the gcc build (making it more
>> similar to the llvm build)
>> we will be able to use the old 2^44 offset w/o changing the asan-rt.
>
> Sure, but it will be then slower, I thought you are looking for ASAN speed
> improvements.

Yes, and we already achieved it on ubuntu :)

>
>> That's yet another set of spaghetti ifdefs.
>> I'd rather revert the whole thing back to 2^44 than do that.
>
> Please revert the two hunks now.

That's a bummer. We've already deployed Clang with the new setting and
will likely not want to revert it there.
If we revert the two hunks in gcc (in gcc/config/i386/i386.c and in
asan_mapping.h) we will have larger inconsistency between gcc and
clang variants.
But if we switch to flexible mapping in gcc (will require gcc to emit
the two globals) we will only need to revert gcc/config/i386/i386.c
and the run-times in clang and gcc will remain the same.

> I'll try to implement it eventually and
> try to convince you ;)

That's surely not hard to implement, but very hard to support.

--kcc

>
>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 10:32     ` Jakub Jelinek
  2013-02-13 11:59       ` Jakub Jelinek
@ 2013-02-13 14:46       ` Jack Howarth
  1 sibling, 0 replies; 36+ messages in thread
From: Jack Howarth @ 2013-02-13 14:46 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Konstantin Serebryany, GCC Patches, Dodji Seketeli,
	Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 11:32:00AM +0100, Jakub Jelinek wrote:
> On Wed, Feb 13, 2013 at 02:28:25PM +0400, Konstantin Serebryany wrote:
> > Right. In LLVM we test only with ASAN_FLEXIBLE_MAPPING_AND_OFFSET==1,
> > so this came unnoticed.
> > Fixed in r175049.
> ...
> 
> This is ok, thanks.
> 
> 	Jakub

FYI, asan.exp shows no regression at -m32/-m64 on x86_64-apple-darwin12 using
gcc svn at r196013. Thanks for the new allocator support on darwin.
        Jack

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 13:39                 ` Konstantin Serebryany
@ 2013-02-13 15:19                   ` Jakub Jelinek
  2013-02-13 16:48                     ` Jack Howarth
  2013-02-14  8:48                     ` Jakub Jelinek
  0 siblings, 2 replies; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-13 15:19 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 05:39:15PM +0400, Konstantin Serebryany wrote:
> > No.  You can disable it for the whole system (prelink -ua), but that is not
> > a sane requirement to running sanitized programs.
> 
> Why not?
> :)

Because that is a fully system operation, requires root access, etc.
The fact that some user wants to test one of his programs with Asan
shouldn't need to affect other users.

> This we can deal with.
> We already setenv+reexec on Mac to solve similar issue with Mac's
> dynamic run-time.

The reexec is problematic, what if the program already in constructors run
before __asan_init (perhaps ctors of other libraries etc.) does something
that really shouldn't be done twice?

> > Sure, but it will be then slower, I thought you are looking for ASAN speed
> > improvements.
> 
> Yes, and we already achieved it on ubuntu :)

AFAIK prelink is available even on ubuntu, perhaps not the default.

> > I'll try to implement it eventually and
> > try to convince you ;)
> 
> That's surely not hard to implement, but very hard to support.

Why?

Here is the patch, works just fine for me here during asan.exp testing.
You can very easily either install and enable prelink on one of your
x86_64-linux testing boxes, or just install it and add test that
will say prelink -r 0x3600000000 some test shared library and then
just use it in sanitized program (that will also verify that you can mmap
libraries in that range), or even just write a test that will in a
non-instrumented ctor with lower priority than asan's priority
mmap a few pages at 0x3000000000 and close to 0x3fffff0000
and store some data into those buffers later on in sanitized code.

--- asan_mapping.h.jj	2013-02-13 11:53:43.000000000 +0100
+++ asan_mapping.h	2013-02-13 16:00:22.821413836 +0100
@@ -61,13 +61,31 @@ extern SANITIZER_INTERFACE_ATTRIBUTE upt
 #define kHighShadowBeg  MEM_TO_SHADOW(kHighMemBeg)
 #define kHighShadowEnd  MEM_TO_SHADOW(kHighMemEnd)
 
+#if ASAN_LINUX && defined(__x86_64__)
+# define kMidMemBeg	(kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0)
+# define kMidMemEnd	(kLowMemEnd < 0x3000000000ULL ? 0x3fffffffffULL : 0)
+# define kMidShadowBeg	MEM_TO_SHADOW(kMidMemBeg)
+# define kMidShadowEnd	MEM_TO_SHADOW(kMidMemEnd)
+#else
+# define kMidMemBeg	0
+# define kMidMemEnd	0
+# define kMidShadowBeg	0
+# define kMidShadowEnd	0
+#endif
+
 // 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)
 
 namespace __asan {
 
@@ -86,8 +104,12 @@ static inline bool AddrIsInHighMem(uptr
   return a >= kHighMemBeg && a <= kHighMemEnd;
 }
 
+static inline bool AddrIsInMidMem(uptr a) {
+  return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd;
+}
+
 static inline bool AddrIsInMem(uptr a) {
-  return AddrIsInLowMem(a) || AddrIsInHighMem(a);
+  return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a);
 }
 
 static inline uptr MemToShadow(uptr p) {
@@ -99,11 +121,22 @@ static inline bool AddrIsInHighShadow(up
   return a >= kHighShadowBeg && a <=  kHighMemEnd;
 }
 
+static inline bool AddrIsInMidShadow(uptr a) {
+  return kMidMemBeg && a >= kMidShadowBeg && a <= kMidMemEnd;
+}
+
 static inline bool AddrIsInShadow(uptr a) {
-  return AddrIsInLowShadow(a) || AddrIsInHighShadow(a);
+  return AddrIsInLowShadow(a) || AddrIsInMidShadow(a) || AddrIsInHighShadow(a);
 }
 
 static inline bool AddrIsInShadowGap(uptr a) {
+  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)
--- asan_rtl.cc.jj	2013-02-13 11:53:44.000000000 +0100
+++ asan_rtl.cc	2013-02-13 16:00:10.815483846 +0100
@@ -35,8 +35,14 @@ 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, kHighShadowEnd - kLowShadowBeg);
+    else {
+      UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg);
+      UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd);
+    }
+  }
   if (death_callback)
     death_callback();
   if (flags()->abort_on_error)
@@ -357,17 +363,33 @@ void __asan_init() {
            (void*)kHighMemBeg, (void*)kHighMemEnd);
     Printf("|| `[%p, %p]` || HighShadow ||\n",
            (void*)kHighShadowBeg, (void*)kHighShadowEnd);
+    if (kMidMemBeg) {
+      Printf("|| `[%p, %p]` || ShadowGap  ||\n",
+             (void*)kShadowGap3Beg, (void*)kShadowGap3End);
+      Printf("|| `[%p, %p]` || MidMem     ||\n",
+             (void*)kMidMemBeg, (void*)kMidMemEnd);
+      Printf("|| `[%p, %p]` || ShadowGap  ||\n",
+             (void*)kShadowGap2Beg, (void*)kShadowGap2End);
+      Printf("|| `[%p, %p]` || MidShadow  ||\n",
+             (void*)kMidShadowBeg, (void*)kMidShadowEnd);
+    }
     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",
+    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);
 
@@ -375,6 +397,9 @@ void __asan_init() {
     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);
   }
 
   if (flags()->disable_core) {
@@ -384,7 +409,26 @@ void __asan_init() {
   uptr shadow_start = kLowShadowBeg;
   if (kLowShadowBeg > 0) shadow_start -= GetMmapGranularity();
   uptr shadow_end = kHighShadowEnd;
-  if (MemoryRangeIsAvailable(shadow_start, shadow_end)) {
+  if (kMidMemBeg
+      && MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1)
+      && MemoryRangeIsAvailable(kMidMemEnd + 1, shadow_end)) {
+    if (kLowShadowBeg != kLowShadowEnd) {
+      // mmap the low shadow plus at least one page.
+      ReserveShadowMemoryRange(kLowShadowBeg - GetMmapGranularity(),
+                               kLowShadowEnd);
+    }
+    // mmap the mid shadow.
+    ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd);
+    // mmap the high shadow.
+    ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
+    // protect the gaps
+    void *prot = Mprotect(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
+    CHECK(prot == (void*)kShadowGapBeg);
+    prot = Mprotect(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
+    CHECK(prot == (void*)kShadowGap2Beg);
+    prot = Mprotect(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
+    CHECK(prot == (void*)kShadowGap3Beg);
+  } else if (!kMidMemBeg && MemoryRangeIsAvailable(shadow_start, shadow_end)) {
     if (kLowShadowBeg != kLowShadowEnd) {
       // mmap the low shadow plus at least one page.
       ReserveShadowMemoryRange(kLowShadowBeg - GetMmapGranularity(),


	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 15:19                   ` Jakub Jelinek
@ 2013-02-13 16:48                     ` Jack Howarth
  2013-02-13 20:12                       ` Jakub Jelinek
  2013-02-14  8:48                     ` Jakub Jelinek
  1 sibling, 1 reply; 36+ messages in thread
From: Jack Howarth @ 2013-02-13 16:48 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Konstantin Serebryany, GCC Patches, Dodji Seketeli,
	Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 04:19:14PM +0100, Jakub Jelinek wrote:
> 
> The reexec is problematic, what if the program already in constructors run
> before __asan_init (perhaps ctors of other libraries etc.) does something
> that really shouldn't be done twice?
> 

Jakub,
   Wouldn't sorting all of the constructors and destructors by priority, while
retaining the original order, in collect2 solve this issue (as was proposed for
implementing intra-modular init priority support on darwin)?
            Jack

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13  9:20 libsanitizer merge from upstream r175042 Konstantin Serebryany
  2013-02-13  9:51 ` Jakub Jelinek
@ 2013-02-13 18:29 ` H.J. Lu
  2013-02-14  8:08   ` Konstantin Serebryany
  1 sibling, 1 reply; 36+ messages in thread
From: H.J. Lu @ 2013-02-13 18:29 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: GCC Patches, Jakub Jelinek, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Wed, Feb 13, 2013 at 1:19 AM, Konstantin Serebryany
<konstantin.s.serebryany@gmail.com> wrote:
> Hi,
>
> The attached patch is the libsanitizer merge from upstream r175042.
>
> Lots of changes. Among other things:
>  - x86_64 linux: change the shadow offset to 0x7fff8000 (~5% speedup)
>  - the new asan allocator is enabled on Mac (was enabled on Linux before).
>  - tsan finds races between atomic and plain accesses
>  - better scanf interceptor, enabled by default
>  - don't include linux/futex.h (fixes PR56128)
>  - simple tests seem to work (again?) on PowerPC64 with 44-bit address
> space (46 AS not tested)
>
> Patch for libsanitizer is automatically generated by libsanitizer/merge.sh
> Tested with
> rm -rf */{*/,}libsanitizer \
>   && make -j 50 \
>   && make -C gcc check-g{cc,++}
> RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} asan.exp'
>
> Our internal LLVM bots (Linux, Mac and Android) are green.
>
> Ok to commit?
>
> --kcc

This breaks build on Linux/x32 where off_t is 64bit:

In file included from
/export/gnu/import/git/gcc/libsanitizer/interception/interception.h:20:0,
                 from
/export/gnu/import/git/gcc/libsanitizer/interception/interception_type_test.cc:15:
/export/gnu/import/git/gcc/libsanitizer/sanitizer_common/sanitizer_internal_defs.h:221:72:
error: size of array ‘assertion_failed__34’ is negative
     typedef char IMPL_PASTE(assertion_failed_##_, line)[2*(int)(pred)-1]
                                                                        ^
/export/gnu/import/git/gcc/libsanitizer/sanitizer_common/sanitizer_internal_defs.h:215:30:
note: in expansion of macro ‘IMPL_COMPILER_ASSERT’
 #define COMPILER_CHECK(pred) IMPL_COMPILER_ASSERT(pred, __LINE__)
                              ^
/export/gnu/import/git/gcc/libsanitizer/interception/interception_type_test.cc:34:1:
note: in expansion of macro ‘COMPILER_CHECK’
 COMPILER_CHECK(sizeof(OFF_T) == sizeof(off_t));
 ^
make[7]: *** [interception_type_test.lo] Error 1

This patch fixes it.  OK to install?

Thanks.

-- 
H.J.
---
diff --git a/libsanitizer/interception/interception.h
b/libsanitizer/interception/interception.h
index b4c4137..c4c5026 100644
--- a/libsanitizer/interception/interception.h
+++ b/libsanitizer/interception/interception.h
@@ -28,8 +28,8 @@ typedef __sanitizer::s64  INTMAX_T;
 // WARNING: OFF_T may be different from OS type off_t, depending on
the value of
 // _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 is special.
-#ifdef __APPLE__
+// Mac and Linux/x86-64 are special.
+#if defined(__APPLE__) || (defined(__linux__) && defined(__x86_64__))
 typedef __sanitizer::u64 OFF_T;
 #else
 typedef __sanitizer::uptr OFF_T;

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 16:48                     ` Jack Howarth
@ 2013-02-13 20:12                       ` Jakub Jelinek
  0 siblings, 0 replies; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-13 20:12 UTC (permalink / raw)
  To: Jack Howarth
  Cc: Konstantin Serebryany, GCC Patches, Dodji Seketeli,
	Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 11:48:32AM -0500, Jack Howarth wrote:
> On Wed, Feb 13, 2013 at 04:19:14PM +0100, Jakub Jelinek wrote:
> > 
> > The reexec is problematic, what if the program already in constructors run
> > before __asan_init (perhaps ctors of other libraries etc.) does something
> > that really shouldn't be done twice?
> > 
> 
>    Wouldn't sorting all of the constructors and destructors by priority, while
> retaining the original order, in collect2 solve this issue (as was proposed for
> implementing intra-modular init priority support on darwin)?

I wasn't talking about darwin at all, and on Linux inter-CU init priority
works just fine.  I'm just saying that reexec isn't always safe, because
what the program does before __asan_init can be something undesirable to be
done multiple times.

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 18:29 ` H.J. Lu
@ 2013-02-14  8:08   ` Konstantin Serebryany
  0 siblings, 0 replies; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-14  8:08 UTC (permalink / raw)
  To: H.J. Lu
  Cc: GCC Patches, Jakub Jelinek, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Wed, Feb 13, 2013 at 10:29 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Feb 13, 2013 at 1:19 AM, Konstantin Serebryany
> <konstantin.s.serebryany@gmail.com> wrote:
>> Hi,
>>
>> The attached patch is the libsanitizer merge from upstream r175042.
>>
>> Lots of changes. Among other things:
>>  - x86_64 linux: change the shadow offset to 0x7fff8000 (~5% speedup)
>>  - the new asan allocator is enabled on Mac (was enabled on Linux before).
>>  - tsan finds races between atomic and plain accesses
>>  - better scanf interceptor, enabled by default
>>  - don't include linux/futex.h (fixes PR56128)
>>  - simple tests seem to work (again?) on PowerPC64 with 44-bit address
>> space (46 AS not tested)
>>
>> Patch for libsanitizer is automatically generated by libsanitizer/merge.sh
>> Tested with
>> rm -rf */{*/,}libsanitizer \
>>   && make -j 50 \
>>   && make -C gcc check-g{cc,++}
>> RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} asan.exp'
>>
>> Our internal LLVM bots (Linux, Mac and Android) are green.
>>
>> Ok to commit?
>>
>> --kcc
>
> This breaks build on Linux/x32 where off_t is 64bit:

Sorry. I've committed your patch upstream as
http://llvm.org/viewvc/llvm-project?rev=175140&view=rev
Feel free to submit the same directly to gcc.

Thanks!

--kcc

>
> In file included from
> /export/gnu/import/git/gcc/libsanitizer/interception/interception.h:20:0,
>                  from
> /export/gnu/import/git/gcc/libsanitizer/interception/interception_type_test.cc:15:
> /export/gnu/import/git/gcc/libsanitizer/sanitizer_common/sanitizer_internal_defs.h:221:72:
> error: size of array ‘assertion_failed__34’ is negative
>      typedef char IMPL_PASTE(assertion_failed_##_, line)[2*(int)(pred)-1]
>                                                                         ^
> /export/gnu/import/git/gcc/libsanitizer/sanitizer_common/sanitizer_internal_defs.h:215:30:
> note: in expansion of macro ‘IMPL_COMPILER_ASSERT’
>  #define COMPILER_CHECK(pred) IMPL_COMPILER_ASSERT(pred, __LINE__)
>                               ^
> /export/gnu/import/git/gcc/libsanitizer/interception/interception_type_test.cc:34:1:
> note: in expansion of macro ‘COMPILER_CHECK’
>  COMPILER_CHECK(sizeof(OFF_T) == sizeof(off_t));
>  ^
> make[7]: *** [interception_type_test.lo] Error 1
>
> This patch fixes it.  OK to install?
>
> Thanks.
>
> --
> H.J.
> ---
> diff --git a/libsanitizer/interception/interception.h
> b/libsanitizer/interception/interception.h
> index b4c4137..c4c5026 100644
> --- a/libsanitizer/interception/interception.h
> +++ b/libsanitizer/interception/interception.h
> @@ -28,8 +28,8 @@ typedef __sanitizer::s64  INTMAX_T;
>  // WARNING: OFF_T may be different from OS type off_t, depending on
> the value of
>  // _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 is special.
> -#ifdef __APPLE__
> +// Mac and Linux/x86-64 are special.
> +#if defined(__APPLE__) || (defined(__linux__) && defined(__x86_64__))
>  typedef __sanitizer::u64 OFF_T;
>  #else
>  typedef __sanitizer::uptr OFF_T;

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-13 15:19                   ` Jakub Jelinek
  2013-02-13 16:48                     ` Jack Howarth
@ 2013-02-14  8:48                     ` Jakub Jelinek
  2013-02-14 11:56                       ` Konstantin Serebryany
  1 sibling, 1 reply; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-14  8:48 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Wed, Feb 13, 2013 at 04:19:14PM +0100, Jakub Jelinek wrote:
> Here is the patch, works just fine for me here during asan.exp testing.
> You can very easily either install and enable prelink on one of your
> x86_64-linux testing boxes, or just install it and add test that
> will say prelink -r 0x3600000000 some test shared library and then
> just use it in sanitized program (that will also verify that you can mmap
> libraries in that range), or even just write a test that will in a
> non-instrumented ctor with lower priority than asan's priority
> mmap a few pages at 0x3000000000 and close to 0x3fffff0000
> and store some data into those buffers later on in sanitized code.

I forgot you don't even need prelink -r 0x3600000000 for the testing, you
can just link it as
$(CXX) -shared -Wl,-Ttext-segment=0x3600000000 -fPIC -o testlib.so -fsanitize=address testlib.C
So, put some asan tests into the executable, some tests into the shared
library and link the executable against the shared library placed in the
area where prelink allocates addresses to shared libraries.
Perhaps build 3 such libraries, one at 0x3000000000, one somewhere middle
of that range and one close to the end of the range.

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-14  8:48                     ` Jakub Jelinek
@ 2013-02-14 11:56                       ` Konstantin Serebryany
  2013-02-14 12:19                         ` Jakub Jelinek
  0 siblings, 1 reply; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-14 11:56 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

The patch seems to work on a simple test. Let me digest it.
I am trying to understand if there are problems with it other than the
added complexity (which is what I don't like the most).

-Wl,-Ttext-segment=0x3600000000 does not work with binutils-gold.
gold understands -Wl,-Ttext=0x3600000000, but bfd ld doesn't.
Do you know any flag supported by both?

--kcc


On Thu, Feb 14, 2013 at 12:48 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Feb 13, 2013 at 04:19:14PM +0100, Jakub Jelinek wrote:
>> Here is the patch, works just fine for me here during asan.exp testing.
>> You can very easily either install and enable prelink on one of your
>> x86_64-linux testing boxes, or just install it and add test that
>> will say prelink -r 0x3600000000 some test shared library and then
>> just use it in sanitized program (that will also verify that you can mmap
>> libraries in that range), or even just write a test that will in a
>> non-instrumented ctor with lower priority than asan's priority
>> mmap a few pages at 0x3000000000 and close to 0x3fffff0000
>> and store some data into those buffers later on in sanitized code.
>
> I forgot you don't even need prelink -r 0x3600000000 for the testing, you
> can just link it as
> $(CXX) -shared -Wl,-Ttext-segment=0x3600000000 -fPIC -o testlib.so -fsanitize=address testlib.C
> So, put some asan tests into the executable, some tests into the shared
> library and link the executable against the shared library placed in the
> area where prelink allocates addresses to shared libraries.
> Perhaps build 3 such libraries, one at 0x3000000000, one somewhere middle
> of that range and one close to the end of the range.
>
>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-14 11:56                       ` Konstantin Serebryany
@ 2013-02-14 12:19                         ` Jakub Jelinek
  2013-02-14 12:56                           ` Konstantin Serebryany
  2013-02-15  7:45                           ` Konstantin Serebryany
  0 siblings, 2 replies; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-14 12:19 UTC (permalink / raw)
  To: Konstantin Serebryany, Ian Lance Taylor
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Thu, Feb 14, 2013 at 03:55:47PM +0400, Konstantin Serebryany wrote:
> The patch seems to work on a simple test. Let me digest it.
> I am trying to understand if there are problems with it other than the
> added complexity (which is what I don't like the most).

Yes, it is some added complexity, but not too much, and something that can
be tested regularly that it works.

> -Wl,-Ttext-segment=0x3600000000 does not work with binutils-gold.
> gold understands -Wl,-Ttext=0x3600000000, but bfd ld doesn't.
> Do you know any flag supported by both?

-Wl,-Ttext is unfortunately something different, at least for
the bfd linker.  -Ttext-segment aligns the base of the whole shared library,
if you look at start of the linker script for -shared:
  /* Read-only sections, merged into text segment: */
  . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
  .note.gnu.build-id : { *(.note.gnu.build-id) }
  .hash           : { *(.hash) }
  .gnu.hash       : { *(.gnu.hash) }
  .dynsym         : { *(.dynsym) }
  .dynstr         : { *(.dynstr) }
  .gnu.version    : { *(.gnu.version) }
  .gnu.version_d  : { *(.gnu.version_d) }
  .gnu.version_r  : { *(.gnu.version_r) }
...
  .rela.plt       :
    {
      *(.rela.plt)
      *(.rela.iplt)
    }
  .init           :
  {
    KEEP (*(.init))
  }
  .plt            : { *(.plt) *(.iplt) }
  .text           :
  {
    *(.text.unlikely .text.*_unlikely)
    *(.text.exit .text.exit.*)
-Ttext-segment chooses the base at which ELF headers will reside.
-Ttext aligns the .text section's start to that, so most likely the shared
library won't even link, because .init section will be many GBs appart from
.text section.

CCing Ian, if gold has any way to do something similar.
As I said, the alternative is to link the library normally, and run
prelink -r 0x3600000000 libtest.so on the shared library afterwards if prelink is
installed, and make sure you install it on your linux/x86-64 test boxes.

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-14 12:19                         ` Jakub Jelinek
@ 2013-02-14 12:56                           ` Konstantin Serebryany
  2013-02-15  7:45                           ` Konstantin Serebryany
  1 sibling, 0 replies; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-14 12:56 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Thu, Feb 14, 2013 at 4:19 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Thu, Feb 14, 2013 at 03:55:47PM +0400, Konstantin Serebryany wrote:
>> The patch seems to work on a simple test. Let me digest it.
>> I am trying to understand if there are problems with it other than the
>> added complexity (which is what I don't like the most).
>
> Yes, it is some added complexity, but not too much, and something that can
> be tested regularly that it works.
>
>> -Wl,-Ttext-segment=0x3600000000 does not work with binutils-gold.
>> gold understands -Wl,-Ttext=0x3600000000, but bfd ld doesn't.
>> Do you know any flag supported by both?
>
> -Wl,-Ttext is unfortunately something different, at least for
> the bfd linker.  -Ttext-segment aligns the base of the whole shared library,
> if you look at start of the linker script for -shared:
>   /* Read-only sections, merged into text segment: */
>   . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
>   .note.gnu.build-id : { *(.note.gnu.build-id) }
>   .hash           : { *(.hash) }
>   .gnu.hash       : { *(.gnu.hash) }
>   .dynsym         : { *(.dynsym) }
>   .dynstr         : { *(.dynstr) }
>   .gnu.version    : { *(.gnu.version) }
>   .gnu.version_d  : { *(.gnu.version_d) }
>   .gnu.version_r  : { *(.gnu.version_r) }
> ...
>   .rela.plt       :
>     {
>       *(.rela.plt)
>       *(.rela.iplt)
>     }
>   .init           :
>   {
>     KEEP (*(.init))
>   }
>   .plt            : { *(.plt) *(.iplt) }
>   .text           :
>   {
>     *(.text.unlikely .text.*_unlikely)
>     *(.text.exit .text.exit.*)
> -Ttext-segment chooses the base at which ELF headers will reside.
> -Ttext aligns the .text section's start to that, so most likely the shared
> library won't even link, because .init section will be many GBs appart from
> .text section.
>
> CCing Ian, if gold has any way to do something similar.
> As I said, the alternative is to link the library normally, and run
> prelink -r 0x3600000000 libtest.so on the shared library afterwards if prelink is
> installed, and make sure you install it on your linux/x86-64 test boxes.

Another way is to simply force using the bfd linker (on ubuntu, when
gold is the default linker, there is still bfd linker under
/usr/bin/ld.bfd).
Still, better to have something that works for both linkers.

--kcc

>
>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-14 12:19                         ` Jakub Jelinek
  2013-02-14 12:56                           ` Konstantin Serebryany
@ 2013-02-15  7:45                           ` Konstantin Serebryany
  2013-02-15  8:26                             ` Jakub Jelinek
  2013-02-15 15:39                             ` Ian Lance Taylor
  1 sibling, 2 replies; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-15  7:45 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Thu, Feb 14, 2013 at 4:19 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Thu, Feb 14, 2013 at 03:55:47PM +0400, Konstantin Serebryany wrote:
>> The patch seems to work on a simple test. Let me digest it.
>> I am trying to understand if there are problems with it other than the
>> added complexity (which is what I don't like the most).
>
> Yes, it is some added complexity, but not too much, and something that can
> be tested regularly that it works.

The complexity I am afraid of is not only in the code, but also at the
time of execution.
We and our users sometimes have to stare at the /proc/self/maps.
A mapping with 1 (ZeroBase) or 3 (default) asan sections is ok, but
6 extra asan sections becomes nearly incomprehensible, at least for me.

So, how about having kMidMemBeg as a variable, set as __asan_init.
Only if something is mapped around 0x003X00000000 we set it to non-zero.

http://llvm-reviews.chandlerc.com/D411 (still needs some cleanup)

Unfortunately, the test does not work if gold is the system linker.
Any suggestion on how to make the test work with either linker?

Thanks,

--kcc

>
>> -Wl,-Ttext-segment=0x3600000000 does not work with binutils-gold.
>> gold understands -Wl,-Ttext=0x3600000000, but bfd ld doesn't.
>> Do you know any flag supported by both?
>
> -Wl,-Ttext is unfortunately something different, at least for
> the bfd linker.  -Ttext-segment aligns the base of the whole shared library,
> if you look at start of the linker script for -shared:
>   /* Read-only sections, merged into text segment: */
>   . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
>   .note.gnu.build-id : { *(.note.gnu.build-id) }
>   .hash           : { *(.hash) }
>   .gnu.hash       : { *(.gnu.hash) }
>   .dynsym         : { *(.dynsym) }
>   .dynstr         : { *(.dynstr) }
>   .gnu.version    : { *(.gnu.version) }
>   .gnu.version_d  : { *(.gnu.version_d) }
>   .gnu.version_r  : { *(.gnu.version_r) }
> ...
>   .rela.plt       :
>     {
>       *(.rela.plt)
>       *(.rela.iplt)
>     }
>   .init           :
>   {
>     KEEP (*(.init))
>   }
>   .plt            : { *(.plt) *(.iplt) }
>   .text           :
>   {
>     *(.text.unlikely .text.*_unlikely)
>     *(.text.exit .text.exit.*)
> -Ttext-segment chooses the base at which ELF headers will reside.
> -Ttext aligns the .text section's start to that, so most likely the shared
> library won't even link, because .init section will be many GBs appart from
> .text section.
>
> CCing Ian, if gold has any way to do something similar.
> As I said, the alternative is to link the library normally, and run
> prelink -r 0x3600000000 libtest.so on the shared library afterwards if prelink is
> installed, and make sure you install it on your linux/x86-64 test boxes.
>
>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-15  7:45                           ` Konstantin Serebryany
@ 2013-02-15  8:26                             ` Jakub Jelinek
  2013-02-15  8:48                               ` Konstantin Serebryany
  2013-02-15 15:39                             ` Ian Lance Taylor
  1 sibling, 1 reply; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-15  8:26 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Fri, Feb 15, 2013 at 11:45:15AM +0400, Konstantin Serebryany wrote:
> On Thu, Feb 14, 2013 at 4:19 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> > On Thu, Feb 14, 2013 at 03:55:47PM +0400, Konstantin Serebryany wrote:
> >> The patch seems to work on a simple test. Let me digest it.
> >> I am trying to understand if there are problems with it other than the
> >> added complexity (which is what I don't like the most).
> >
> > Yes, it is some added complexity, but not too much, and something that can
> > be tested regularly that it works.
> 
> The complexity I am afraid of is not only in the code, but also at the
> time of execution.
> We and our users sometimes have to stare at the /proc/self/maps.
> A mapping with 1 (ZeroBase) or 3 (default) asan sections is ok, but
> 6 extra asan sections becomes nearly incomprehensible, at least for me.
> 
> So, how about having kMidMemBeg as a variable, set as __asan_init.
> Only if something is mapped around 0x003X00000000 we set it to non-zero.

That is fine for me.  Note that ASAN_FIXED_MAPPING 1 might not work well,
e.g. for shadow offset of 1ULL << 44, there the prelink library range falls
into the low memory and thus kMidMemBeg should be 0.

> http://llvm-reviews.chandlerc.com/D411 (still needs some cleanup)

One cleanup might be avoid calling MemoryRangeIsAvailable unnecessarily
too many times.  Guess if you move:
  uptr shadow_start = kLowShadowBeg;
  if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
  uptr shadow_end = kHighShadowEnd;
  bool shadow_avail = MemoryRangeIsAvailable(shadow_start, shadow_end);
before the
#if ASAN_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
  if (!MemoryRangeIsAvailable(kLowShadowBeg, kHighShadowEnd)) {
    kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
    kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x3fffffffffULL : 0;
  }
#endif
code, you can just use shadow_avail there and later.  Every
MemoryRangeIsAvailable reads /proc/self/maps again, right?

Also, on ppc64 the prelink library area is:
0x8001000000LL to 0x8100000000LL if we want to e.g. handle flexible mapping
there (perhaps better use 0x8000000000L as kMidMemBeg then), guess for 32-bit
architectures it is irrelevant, there is not much
point in using shadow offsets other than the default high one (which is high
enough) or 0 (then you need PIE, and thus prelink info is ignored both by
the kernel and dynamic linker).

> Unfortunately, the test does not work if gold is the system linker.
> Any suggestion on how to make the test work with either linker?

That is the question to Ian, if gold can do that at all.

As I said before, you can try something like:

#include <sys/mman.h>

struct A
{
  A ();
  void *ptr;
};

void *ptr;

__attribute__((no_address_safety_analysis))
A::A ()
{
  ptr = mmap ((void *) 0x3600000000UL, 65536, PROT_READ|PROT_WRITE,
	      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}

A __attribute__((init_priority (1))) a;

int
main ()
{
  if (a.ptr != MAP_FAILED)
    {
      char *ptr = (char *) a.ptr;
      __asan_poison_memory_region (ptr, 4096);
      __asan_poison_memory_region (ptr + 61440, 4096);
      ptr[4096] = 23;
    }
}

and similar (and/or test that accessing the poisoned memory fails etc.).
For gcc you want to compile with -w, so that it doesn't warn about the
reserved init_priority, not sure what clang would do.

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-15  8:26                             ` Jakub Jelinek
@ 2013-02-15  8:48                               ` Konstantin Serebryany
  2013-02-15  9:06                                 ` Jakub Jelinek
  2013-02-22 16:32                                 ` Jakub Jelinek
  0 siblings, 2 replies; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-15  8:48 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

Ian, there is a question for you below.

On Fri, Feb 15, 2013 at 12:26 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Fri, Feb 15, 2013 at 11:45:15AM +0400, Konstantin Serebryany wrote:
>> On Thu, Feb 14, 2013 at 4:19 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> > On Thu, Feb 14, 2013 at 03:55:47PM +0400, Konstantin Serebryany wrote:
>> >> The patch seems to work on a simple test. Let me digest it.
>> >> I am trying to understand if there are problems with it other than the
>> >> added complexity (which is what I don't like the most).
>> >
>> > Yes, it is some added complexity, but not too much, and something that can
>> > be tested regularly that it works.
>>
>> The complexity I am afraid of is not only in the code, but also at the
>> time of execution.
>> We and our users sometimes have to stare at the /proc/self/maps.
>> A mapping with 1 (ZeroBase) or 3 (default) asan sections is ok, but
>> 6 extra asan sections becomes nearly incomprehensible, at least for me.
>>
>> So, how about having kMidMemBeg as a variable, set as __asan_init.
>> Only if something is mapped around 0x003X00000000 we set it to non-zero.
>
> That is fine for me.  Note that ASAN_FIXED_MAPPING 1 might not work well,
> e.g. for shadow offset of 1ULL << 44, there the prelink library range falls
> into the low memory and thus kMidMemBeg should be 0.

Sure. ASAN_FIXED_MAPPING should be used for performance measurements
only -- this is not a release option.
(Added a more precise comment).

>
>> http://llvm-reviews.chandlerc.com/D411 (still needs some cleanup)
>
> One cleanup might be avoid calling MemoryRangeIsAvailable unnecessarily
> too many times.  Guess if you move:
>   uptr shadow_start = kLowShadowBeg;
>   if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
>   uptr shadow_end = kHighShadowEnd;
>   bool shadow_avail = MemoryRangeIsAvailable(shadow_start, shadow_end);
> before the
> #if ASAN_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
>   if (!MemoryRangeIsAvailable(kLowShadowBeg, kHighShadowEnd)) {
>     kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
>     kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x3fffffffffULL : 0;
>   }
> #endif
> code, you can just use shadow_avail there and later.  Every
> MemoryRangeIsAvailable reads /proc/self/maps again, right?

agree, done.

>
> Also, on ppc64 the prelink library area is:
> 0x8001000000LL to 0x8100000000LL if we want to e.g. handle flexible mapping
> there (perhaps better use 0x8000000000L as kMidMemBeg then), guess for 32-bit
> architectures it is irrelevant, there is not much
> point in using shadow offsets other than the default high one (which is high
> enough) or 0 (then you need PIE, and thus prelink info is ignored both by
> the kernel and dynamic linker).

Let's worry about ppc prelink separately.
We are not changing the shadow offset on ppc (because 7fff8000 does
not seem to help it anyway)
and no one complained so far.

>
>> Unfortunately, the test does not work if gold is the system linker.
>> Any suggestion on how to make the test work with either linker?
>
> That is the question to Ian, if gold can do that at all.

Yep.

>
> As I said before, you can try something like:
>
> #include <sys/mman.h>
>
> struct A
> {
>   A ();
>   void *ptr;
> };
>
> void *ptr;
>
> __attribute__((no_address_safety_analysis))
> A::A ()
> {
>   ptr = mmap ((void *) 0x3600000000UL, 65536, PROT_READ|PROT_WRITE,
>               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> }
>
> A __attribute__((init_priority (1))) a;
>
> int
> main ()
> {
>   if (a.ptr != MAP_FAILED)
>     {
>       char *ptr = (char *) a.ptr;
>       __asan_poison_memory_region (ptr, 4096);
>       __asan_poison_memory_region (ptr + 61440, 4096);
>       ptr[4096] = 23;
>     }
> }
>
> and similar (and/or test that accessing the poisoned memory fails etc.).
> For gcc you want to compile with -w, so that it doesn't warn about the
> reserved init_priority, not sure what clang would do.

This is ungood.
First, clang doesn't like it at all:
prelink1.cc:18:18: error: init_priority attribute requires integer
constant between 101 and 65535 inclusive
A __attribute__((init_priority (1))) a;

Second, in some settings we are using ASAN_USE_PREINIT_ARRAY=1
and this may become the default on linux at some point.
so, __asan_init will get called before A::A()

Waiting for Ian's reply about gold.

--kcc

>
>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-15  8:48                               ` Konstantin Serebryany
@ 2013-02-15  9:06                                 ` Jakub Jelinek
  2013-02-15  9:30                                   ` Konstantin Serebryany
  2013-02-22 16:32                                 ` Jakub Jelinek
  1 sibling, 1 reply; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-15  9:06 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Fri, Feb 15, 2013 at 12:47:30PM +0400, Konstantin Serebryany wrote:
> This is ungood.
> First, clang doesn't like it at all:
> prelink1.cc:18:18: error: init_priority attribute requires integer
> constant between 101 and 65535 inclusive
> A __attribute__((init_priority (1))) a;

For gcc it is just a warning, not error, so you can actually use it if you
know what you are doing.

Anyway, if gold doesn't have any way, you can always do the equivalent
of shell
which prelink 2>/dev/null && prelink -r 0x3600000000 libfoo.so
somewhere in the CMakeLists.txt.  That command doesn't affect system
libraries, can be run as normal user, and just transforms a library
from the default link state to -Wl,-Ttext-segment=0x3600000000
state (including debug info etc.).  You'd need to apt-get install prelink
or whatever command is for that on Ubuntu on the test boxes.

OT, unrelated thing, in include/asan_interface.h there is one
#if __has_feature(address_sanitizer)
which for GCC should better be:
#if (defined __has_feature && __has_feature(address_sanitizer)) \
    || defined(__SANITIZE_ADDRESS__)
(and similarly in asan_internal.h).

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-15  9:06                                 ` Jakub Jelinek
@ 2013-02-15  9:30                                   ` Konstantin Serebryany
  2013-02-15  9:37                                     ` Jakub Jelinek
  0 siblings, 1 reply; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-15  9:30 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Fri, Feb 15, 2013 at 1:05 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Fri, Feb 15, 2013 at 12:47:30PM +0400, Konstantin Serebryany wrote:
>> This is ungood.
>> First, clang doesn't like it at all:
>> prelink1.cc:18:18: error: init_priority attribute requires integer
>> constant between 101 and 65535 inclusive
>> A __attribute__((init_priority (1))) a;
>
> For gcc it is just a warning, not error, so you can actually use it if you
> know what you are doing.
>
> Anyway, if gold doesn't have any way, you can always do the equivalent
> of shell
> which prelink 2>/dev/null && prelink -r 0x3600000000 libfoo.so
> somewhere in the CMakeLists.txt.  That command doesn't affect system
> libraries, can be run as normal user, and just transforms a library
> from the default link state to -Wl,-Ttext-segment=0x3600000000
> state (including debug info etc.).  You'd need to apt-get install prelink
> or whatever command is for that on Ubuntu on the test boxes.

that's another option, not perfect though (someone not having prelink
on his/her box may break the tests w/o noticing).

>
> OT, unrelated thing, in include/asan_interface.h there is one
> #if __has_feature(address_sanitizer)
> which for GCC should better be:
> #if (defined __has_feature && __has_feature(address_sanitizer)) \
>     || defined(__SANITIZE_ADDRESS__)
> (and similarly in asan_internal.h).

z.c:1:44: error: missing binary operator before token "("
 #if (defined __has_feature && __has_feature(address_sanitizer)) \

This should be more like the code below

#if !defined(__has_feature)
#define __has_feature(x) 0
#endif
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)

[hopefully not starting a holly war] Any chance to teach gcc/cpp about
__has_feature?

--kcc

>
>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-15  9:30                                   ` Konstantin Serebryany
@ 2013-02-15  9:37                                     ` Jakub Jelinek
  2013-02-15  9:47                                       ` Konstantin Serebryany
  0 siblings, 1 reply; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-15  9:37 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Fri, Feb 15, 2013 at 01:30:18PM +0400, Konstantin Serebryany wrote:
> > OT, unrelated thing, in include/asan_interface.h there is one
> > #if __has_feature(address_sanitizer)
> > which for GCC should better be:
> > #if (defined __has_feature && __has_feature(address_sanitizer)) \
> >     || defined(__SANITIZE_ADDRESS__)
> > (and similarly in asan_internal.h).
> 
> z.c:1:44: error: missing binary operator before token "("
>  #if (defined __has_feature && __has_feature(address_sanitizer)) \
> 
> This should be more like the code below
> 
> #if !defined(__has_feature)
> #define __has_feature(x) 0
> #endif
> #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)

I don't care much.  Would
#if (defined(__has_feature) && __has_feature(address_sanitizer)) \
    || defined(__SANITIZE_ADDRESS__)
work?  In any case, that looks like clang bug, if you have something that
behaves like a function-like macro, #if defined macro or #ifdef macro
or #if defined macro || 1 and similar should work just fine, only if
the macro is followed by ( it should behave differently.

> [hopefully not starting a holly war] Any chance to teach gcc/cpp about
> __has_feature?

Not for GCC 4.8, that is a new feature, so certainly too late for that.

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-15  9:37                                     ` Jakub Jelinek
@ 2013-02-15  9:47                                       ` Konstantin Serebryany
  2013-02-15 12:02                                         ` Konstantin Serebryany
  0 siblings, 1 reply; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-15  9:47 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Fri, Feb 15, 2013 at 1:37 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Fri, Feb 15, 2013 at 01:30:18PM +0400, Konstantin Serebryany wrote:
>> > OT, unrelated thing, in include/asan_interface.h there is one
>> > #if __has_feature(address_sanitizer)
>> > which for GCC should better be:
>> > #if (defined __has_feature && __has_feature(address_sanitizer)) \
>> >     || defined(__SANITIZE_ADDRESS__)
>> > (and similarly in asan_internal.h).
>>
>> z.c:1:44: error: missing binary operator before token "("
>>  #if (defined __has_feature && __has_feature(address_sanitizer)) \
>>
>> This should be more like the code below
>>
>> #if !defined(__has_feature)
>> #define __has_feature(x) 0
>> #endif
>> #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
>
> I don't care much.  Would
> #if (defined(__has_feature) && __has_feature(address_sanitizer)) \
>     || defined(__SANITIZE_ADDRESS__)
> work?  In any case, that looks like clang bug, if you have something that
> behaves like a function-like macro, #if defined macro or #ifdef macro
> or #if defined macro || 1 and similar should work just fine, only if
> the macro is followed by ( it should behave differently.

That's gcc:

% cat z.c
#if (defined __has_feature && __has_feature(address_sanitizer)) \
        || defined(__SANITIZE_ADDRESS__)
#error OK
#else
#error NOOOOO
#endif
% gcc -c -fsanitize=address  z.c
z.c:1:44: error: missing binary operator before token "("
 #if (defined __has_feature && __has_feature(address_sanitizer)) \
                                            ^
z.c:5:2: error: #error NOOOOO
 #error NOOOOO
  ^
% clang -c -fsanitize=address  z.c
z.c:3:2: error: OK
#error OK
 ^
1 error generated.
%


>
>> [hopefully not starting a holly war] Any chance to teach gcc/cpp about
>> __has_feature?
>
> Not for GCC 4.8, that is a new feature, so certainly too late for that.

How about 4.9?

>
>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-15  9:47                                       ` Konstantin Serebryany
@ 2013-02-15 12:02                                         ` Konstantin Serebryany
  0 siblings, 0 replies; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-15 12:02 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

I've submitted http://llvm.org/viewvc/llvm-project?view=revision&revision=175263
If it survives a few days of testing I'll do another merge to gcc.

--kcc

On Fri, Feb 15, 2013 at 1:47 PM, Konstantin Serebryany
<konstantin.s.serebryany@gmail.com> wrote:
> On Fri, Feb 15, 2013 at 1:37 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> On Fri, Feb 15, 2013 at 01:30:18PM +0400, Konstantin Serebryany wrote:
>>> > OT, unrelated thing, in include/asan_interface.h there is one
>>> > #if __has_feature(address_sanitizer)
>>> > which for GCC should better be:
>>> > #if (defined __has_feature && __has_feature(address_sanitizer)) \
>>> >     || defined(__SANITIZE_ADDRESS__)
>>> > (and similarly in asan_internal.h).
>>>
>>> z.c:1:44: error: missing binary operator before token "("
>>>  #if (defined __has_feature && __has_feature(address_sanitizer)) \
>>>
>>> This should be more like the code below
>>>
>>> #if !defined(__has_feature)
>>> #define __has_feature(x) 0
>>> #endif
>>> #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
>>
>> I don't care much.  Would
>> #if (defined(__has_feature) && __has_feature(address_sanitizer)) \
>>     || defined(__SANITIZE_ADDRESS__)
>> work?  In any case, that looks like clang bug, if you have something that
>> behaves like a function-like macro, #if defined macro or #ifdef macro
>> or #if defined macro || 1 and similar should work just fine, only if
>> the macro is followed by ( it should behave differently.
>
> That's gcc:
>
> % cat z.c
> #if (defined __has_feature && __has_feature(address_sanitizer)) \
>         || defined(__SANITIZE_ADDRESS__)
> #error OK
> #else
> #error NOOOOO
> #endif
> % gcc -c -fsanitize=address  z.c
> z.c:1:44: error: missing binary operator before token "("
>  #if (defined __has_feature && __has_feature(address_sanitizer)) \
>                                             ^
> z.c:5:2: error: #error NOOOOO
>  #error NOOOOO
>   ^
> % clang -c -fsanitize=address  z.c
> z.c:3:2: error: OK
> #error OK
>  ^
> 1 error generated.
> %
>
>
>>
>>> [hopefully not starting a holly war] Any chance to teach gcc/cpp about
>>> __has_feature?
>>
>> Not for GCC 4.8, that is a new feature, so certainly too late for that.
>
> How about 4.9?
>
>>
>>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-15  7:45                           ` Konstantin Serebryany
  2013-02-15  8:26                             ` Jakub Jelinek
@ 2013-02-15 15:39                             ` Ian Lance Taylor
  2013-02-18  8:21                               ` Jakub Jelinek
  1 sibling, 1 reply; 36+ messages in thread
From: Ian Lance Taylor @ 2013-02-15 15:39 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Jakub Jelinek, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Thu, Feb 14, 2013 at 11:45 PM, Konstantin Serebryany
<konstantin.s.serebryany@gmail.com> wrote:
>
> Unfortunately, the test does not work if gold is the system linker.
> Any suggestion on how to make the test work with either linker?

I don't know of a way to set the address of the text segment for both
GNU ld and gold.  As you have observed, GNU ld's -Ttext-segment option
is the same as gold's -Ttext option.  GNU ld's -Ttext option is
useless on ELF systems.

I will add -Ttext-segment to gold as an alias for -Ttext, but that
won't help you today.

Sorry.

Ian

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-15 15:39                             ` Ian Lance Taylor
@ 2013-02-18  8:21                               ` Jakub Jelinek
  2013-02-18  8:40                                 ` Konstantin Serebryany
  0 siblings, 1 reply; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-18  8:21 UTC (permalink / raw)
  To: Konstantin Serebryany, Ian Lance Taylor
  Cc: GCC Patches, Dodji Seketeli, Dmitry Vyukov, Evgeniy Stepanov

On Fri, Feb 15, 2013 at 07:39:28AM -0800, Ian Lance Taylor wrote:
> On Thu, Feb 14, 2013 at 11:45 PM, Konstantin Serebryany
> <konstantin.s.serebryany@gmail.com> wrote:
> >
> > Unfortunately, the test does not work if gold is the system linker.
> > Any suggestion on how to make the test work with either linker?
> 
> I don't know of a way to set the address of the text segment for both
> GNU ld and gold.  As you have observed, GNU ld's -Ttext-segment option
> is the same as gold's -Ttext option.  GNU ld's -Ttext option is
> useless on ELF systems.
> 
> I will add -Ttext-segment to gold as an alias for -Ttext, but that
> won't help you today.

Can't you use then something like:
// RUN: %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 || %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000 || exit 0

?

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-18  8:21                               ` Jakub Jelinek
@ 2013-02-18  8:40                                 ` Konstantin Serebryany
  0 siblings, 0 replies; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-18  8:40 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Mon, Feb 18, 2013 at 12:20 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Fri, Feb 15, 2013 at 07:39:28AM -0800, Ian Lance Taylor wrote:
>> On Thu, Feb 14, 2013 at 11:45 PM, Konstantin Serebryany
>> <konstantin.s.serebryany@gmail.com> wrote:
>> >
>> > Unfortunately, the test does not work if gold is the system linker.
>> > Any suggestion on how to make the test work with either linker?
>>
>> I don't know of a way to set the address of the text segment for both
>> GNU ld and gold.  As you have observed, GNU ld's -Ttext-segment option
>> is the same as gold's -Ttext option.  GNU ld's -Ttext option is
>> useless on ELF systems.
>>
>> I will add -Ttext-segment to gold as an alias for -Ttext, but that
>> won't help you today.
>
> Can't you use then something like:
> // RUN: %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 || %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000 || exit 0

Yep, that's what I was going to do once Ian confirmed that -Ttext in
gold is equivalent to Ttext-segment bfd ld.
http://llvm.org/viewvc/llvm-project?rev=175431&view=rev

Thanks!

--kcc


>
> ?
>
>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-15  8:48                               ` Konstantin Serebryany
  2013-02-15  9:06                                 ` Jakub Jelinek
@ 2013-02-22 16:32                                 ` Jakub Jelinek
  2013-02-28 12:30                                   ` Konstantin Serebryany
  1 sibling, 1 reply; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-22 16:32 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Fri, Feb 15, 2013 at 12:47:30PM +0400, Konstantin Serebryany wrote:
> Sure. ASAN_FIXED_MAPPING should be used for performance measurements
> only -- this is not a release option.
> (Added a more precise comment).

BTW, today I think I've discovered what looks like a prelink bug,
but perhaps we need to bump kMidMemEnd a little bit.
With prelink -R, the libraries are randomized in the selected range of addresses,
by picking a random number in between the boundaries of the address range and first
assigning addresses to libraries above that random offset and when there is no longer any room
above it, starting from the beginning of the range.  Unfortunately the code seems to have
some issues if the random address is chosen close to the end of the range, then in some
cases some libraries could start before the range, but end after the range.

On one of my boxes there is (only 4 libraries out of 822 have this problem,
only discovered it because gdb is linked against one of them and I've tried to
LD_PRELOAD=libasan.so.0 to gdb so that the debugged program would inherit that):

prelink -pv 2>&1 | grep 0x0000003.*-.*0x0000004
/usr/lib64/libgmlib.so.1.0.7 [0x1ea5b3cf] 0x0000003fffe00000-0x0000004000008460:
/usr/lib64/libiec61883.so.0.1.1 [0x56363ffc] 0x0000003fffe00000-0x000000400000c3e0:
/usr/lib64/libncurses.so.5.9 [0x120e1b8a] 0x0000003fffe00000-0x0000004000023860:
/usr/lib64/libsoup-2.4.so.1.5.0 [0x99ff4d51] 0x0000003fffe00000-0x000000400006a258:

while on others none.

So, can kMidMemEnd be slightly incremented above this?  Either 0x4fffffffffULL,
or 0x40ffffffffULL (or replace that 0f with 1f, 2f, etc.).
Small model shared libraries can be only up to 2GB in size, so even
0x40ffffffffULL should be big enough for most cases, but 0x4fffffffffULL
could be even safer.  I've justed tested and 0x4fffffffffULL results in
|| `[0x10007fff8000, 0x7fffffffffff]` || HighMem    ||
|| `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
|| `[0x005000000000, 0x02008fff6fff]` || ShadowGap3 ||
|| `[0x003000000000, 0x004fffffffff]` || MidMem     ||
|| `[0x000a7fff8000, 0x002fffffffff]` || ShadowGap2 ||
|| `[0x00067fff8000, 0x000a7fff7fff]` || MidShadow  ||
|| `[0x00008fff7000, 0x00067fff7fff]` || ShadowGap  ||
|| `[0x00007fff8000, 0x00008fff6fff]` || LowShadow  ||
|| `[0x000000000000, 0x00007fff7fff]` || LowMem     ||
MemToShadow(shadow): 0x00008fff7000 0x000091ff6dff 0x004091ff6e00 0x02008fff6fff 0x00014fff7000 0x0001cfff6fff
and seems to work just fine.

	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-22 16:32                                 ` Jakub Jelinek
@ 2013-02-28 12:30                                   ` Konstantin Serebryany
  2013-02-28 19:56                                     ` Jakub Jelinek
  0 siblings, 1 reply; 36+ messages in thread
From: Konstantin Serebryany @ 2013-02-28 12:30 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Fri, Feb 22, 2013 at 8:32 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Fri, Feb 15, 2013 at 12:47:30PM +0400, Konstantin Serebryany wrote:
>> Sure. ASAN_FIXED_MAPPING should be used for performance measurements
>> only -- this is not a release option.
>> (Added a more precise comment).
>
> BTW, today I think I've discovered what looks like a prelink bug,
> but perhaps we need to bump kMidMemEnd a little bit.
> With prelink -R, the libraries are randomized in the selected range of addresses,
> by picking a random number in between the boundaries of the address range and first
> assigning addresses to libraries above that random offset and when there is no longer any room
> above it, starting from the beginning of the range.  Unfortunately the code seems to have
> some issues if the random address is chosen close to the end of the range, then in some
> cases some libraries could start before the range, but end after the range.
>
> On one of my boxes there is (only 4 libraries out of 822 have this problem,
> only discovered it because gdb is linked against one of them and I've tried to
> LD_PRELOAD=libasan.so.0 to gdb so that the debugged program would inherit that):
>
> prelink -pv 2>&1 | grep 0x0000003.*-.*0x0000004
> /usr/lib64/libgmlib.so.1.0.7 [0x1ea5b3cf] 0x0000003fffe00000-0x0000004000008460:
> /usr/lib64/libiec61883.so.0.1.1 [0x56363ffc] 0x0000003fffe00000-0x000000400000c3e0:
> /usr/lib64/libncurses.so.5.9 [0x120e1b8a] 0x0000003fffe00000-0x0000004000023860:
> /usr/lib64/libsoup-2.4.so.1.5.0 [0x99ff4d51] 0x0000003fffe00000-0x000000400006a258:
>
> while on others none.
>
> So, can kMidMemEnd be slightly incremented above this?  Either 0x4fffffffffULL,
> or 0x40ffffffffULL (or replace that 0f with 1f, 2f, etc.).
> Small model shared libraries can be only up to 2GB in size, so even
> 0x40ffffffffULL should be big enough for most cases, but 0x4fffffffffULL
> could be even safer.  I've justed tested and 0x4fffffffffULL results in
> || `[0x10007fff8000, 0x7fffffffffff]` || HighMem    ||
> || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
> || `[0x005000000000, 0x02008fff6fff]` || ShadowGap3 ||
> || `[0x003000000000, 0x004fffffffff]` || MidMem     ||
> || `[0x000a7fff8000, 0x002fffffffff]` || ShadowGap2 ||
> || `[0x00067fff8000, 0x000a7fff7fff]` || MidShadow  ||
> || `[0x00008fff7000, 0x00067fff7fff]` || ShadowGap  ||
> || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow  ||
> || `[0x000000000000, 0x00007fff7fff]` || LowMem     ||
> MemToShadow(shadow): 0x00008fff7000 0x000091ff6dff 0x004091ff6e00 0x02008fff6fff 0x00014fff7000 0x0001cfff6fff
> and seems to work just fine.

I am sorry, I missed this message.
Indeed, the change looks safe,
http://llvm.org/viewvc/llvm-project?rev=176250&view=rev

Thanks!

--kcc

>
>         Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: libsanitizer merge from upstream r175042
  2013-02-28 12:30                                   ` Konstantin Serebryany
@ 2013-02-28 19:56                                     ` Jakub Jelinek
  0 siblings, 0 replies; 36+ messages in thread
From: Jakub Jelinek @ 2013-02-28 19:56 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Ian Lance Taylor, GCC Patches, Dodji Seketeli, Dmitry Vyukov,
	Evgeniy Stepanov

On Thu, Feb 28, 2013 at 04:30:13PM +0400, Konstantin Serebryany wrote:
> I am sorry, I missed this message.
> Indeed, the change looks safe,
> http://llvm.org/viewvc/llvm-project?rev=176250&view=rev

Thanks, here is what I've committed to gcc:

2013-02-28  Jakub Jelinek  <jakub@redhat.com>

	* asan/asan_mapping.h (kMidMemEnd): Increase to 0x4fffffffffULL.
	* asan/asan_rtl.cc (__asan_init): Increase kMidMemEnd to
	0x4fffffffffULL.

--- libsanitizer/asan/asan_mapping.h	(revision 176249)
+++ libsanitizer/asan/asan_mapping.h	(revision 176250)
@@ -32,13 +32,13 @@
 // || `[0x000000040000, 0x01ffffffffff]` || ShadowGap  ||
 //
 // Special case when something is already mapped between
-// 0x003000000000 and 0x004000000000 (e.g. when prelink is installed):
+// 0x003000000000 and 0x005000000000 (e.g. when prelink is installed):
 // || `[0x10007fff8000, 0x7fffffffffff]` || HighMem    ||
 // || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
-// || `[0x004000000000, 0x02008fff6fff]` || ShadowGap3 ||
-// || `[0x003000000000, 0x003fffffffff]` || MidMem     ||
-// || `[0x00087fff8000, 0x002fffffffff]` || ShadowGap2 ||
-// || `[0x00067fff8000, 0x00087fff7fff]` || MidShadow  ||
+// || `[0x005000000000, 0x02008fff6fff]` || ShadowGap3 ||
+// || `[0x003000000000, 0x004fffffffff]` || MidMem     ||
+// || `[0x000a7fff8000, 0x002fffffffff]` || ShadowGap2 ||
+// || `[0x00067fff8000, 0x000a7fff7fff]` || MidShadow  ||
 // || `[0x00008fff7000, 0x00067fff7fff]` || ShadowGap  ||
 // || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow  ||
 // || `[0x000000000000, 0x00007fff7fff]` || LowMem     ||
@@ -131,7 +131,7 @@ extern uptr AsanMappingProfile[];
 // difference between fixed and non-fixed mapping is below the noise level.
 static uptr kHighMemEnd = 0x7fffffffffffULL;
 static uptr kMidMemBeg =    0x3000000000ULL;
-static uptr kMidMemEnd =    0x3fffffffffULL;
+static uptr kMidMemEnd =    0x4fffffffffULL;
 #else
 SANITIZER_INTERFACE_ATTRIBUTE
 extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;  // Initialized in __asan_init.
--- libsanitizer/asan/asan_rtl.cc	(revision 176249)
+++ libsanitizer/asan/asan_rtl.cc	(revision 176250)
@@ -459,7 +459,7 @@ void __asan_init() {
 #if ASAN_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
   if (!full_shadow_is_available) {
     kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
-    kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x3fffffffffULL : 0;
+    kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
   }
 #endif
 


	Jakub

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2013-02-28 19:56 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-13  9:20 libsanitizer merge from upstream r175042 Konstantin Serebryany
2013-02-13  9:51 ` Jakub Jelinek
2013-02-13 10:28   ` Konstantin Serebryany
2013-02-13 10:32     ` Jakub Jelinek
2013-02-13 11:59       ` Jakub Jelinek
2013-02-13 12:33         ` Konstantin Serebryany
2013-02-13 12:48           ` Jakub Jelinek
2013-02-13 12:58             ` Konstantin Serebryany
2013-02-13 13:07               ` Jakub Jelinek
2013-02-13 13:28                 ` Richard Biener
2013-02-13 13:33                   ` Jakub Jelinek
2013-02-13 13:39                 ` Konstantin Serebryany
2013-02-13 15:19                   ` Jakub Jelinek
2013-02-13 16:48                     ` Jack Howarth
2013-02-13 20:12                       ` Jakub Jelinek
2013-02-14  8:48                     ` Jakub Jelinek
2013-02-14 11:56                       ` Konstantin Serebryany
2013-02-14 12:19                         ` Jakub Jelinek
2013-02-14 12:56                           ` Konstantin Serebryany
2013-02-15  7:45                           ` Konstantin Serebryany
2013-02-15  8:26                             ` Jakub Jelinek
2013-02-15  8:48                               ` Konstantin Serebryany
2013-02-15  9:06                                 ` Jakub Jelinek
2013-02-15  9:30                                   ` Konstantin Serebryany
2013-02-15  9:37                                     ` Jakub Jelinek
2013-02-15  9:47                                       ` Konstantin Serebryany
2013-02-15 12:02                                         ` Konstantin Serebryany
2013-02-22 16:32                                 ` Jakub Jelinek
2013-02-28 12:30                                   ` Konstantin Serebryany
2013-02-28 19:56                                     ` Jakub Jelinek
2013-02-15 15:39                             ` Ian Lance Taylor
2013-02-18  8:21                               ` Jakub Jelinek
2013-02-18  8:40                                 ` Konstantin Serebryany
2013-02-13 14:46       ` Jack Howarth
2013-02-13 18:29 ` H.J. Lu
2013-02-14  8:08   ` Konstantin Serebryany

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).