Update aosp/master compiler-rt for rebase to r235153

Change-Id: I7c900e78d263fe0f574369e8383ccac7e36f5c3b
diff --git a/lib/sanitizer_common/Android.mk b/lib/sanitizer_common/Android.mk
index 1af2324..9436a43 100644
--- a/lib/sanitizer_common/Android.mk
+++ b/lib/sanitizer_common/Android.mk
@@ -72,6 +72,9 @@
 san_rtl_c_includes := \
     external/compiler-rt/lib \
 
+################################################################################
+# Host modules
+
 ifneq ($(HOST_OS),darwin)
 
 include $(CLEAR_VARS)
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index 5b32b6a..d213953 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -83,6 +83,7 @@
   sanitizer_platform.h
   sanitizer_platform_interceptors.h
   sanitizer_platform_limits_posix.h
+  sanitizer_posix.h
   sanitizer_procmaps.h
   sanitizer_quarantine.h
   sanitizer_report_decorator.h
@@ -111,6 +112,10 @@
     SANITIZER_NEEDS_SEGV=1)
 endif()
 
+include(CheckIncludeFile)
+append_have_file_definition(rpc/xdr.h HAVE_RPC_XDR_H SANITIZER_COMMON_DEFINITIONS)
+append_have_file_definition(tirpc/rpc/xdr.h HAVE_TIRPC_RPC_XDR_H SANITIZER_COMMON_DEFINITIONS)
+
 set(SANITIZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})
 append_no_rtti_flag(SANITIZER_CFLAGS)
 
diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h
index b5105f8..deaffef 100644
--- a/lib/sanitizer_common/sanitizer_allocator.h
+++ b/lib/sanitizer_common/sanitizer_allocator.h
@@ -323,7 +323,7 @@
 
   void Init() {
     CHECK_EQ(kSpaceBeg,
-             reinterpret_cast<uptr>(Mprotect(kSpaceBeg, kSpaceSize)));
+             reinterpret_cast<uptr>(MmapNoAccess(kSpaceBeg, kSpaceSize)));
     MapWithCallback(kSpaceEnd, AdditionalSize());
   }
 
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 956fc99..8185c81 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -54,18 +54,17 @@
     if (fd_pid == pid)
       return;
     else
-      internal_close(fd);
+      CloseFile(fd);
   }
 
   internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
-  uptr openrv = OpenFile(full_path, WrOnly);
-  if (internal_iserror(openrv)) {
+  fd = OpenFile(full_path, WrOnly);
+  if (fd == kInvalidFd) {
     const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
-    internal_write(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
-    internal_write(kStderrFd, full_path, internal_strlen(full_path));
+    WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
+    WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
     Die();
   }
-  fd = openrv;
   fd_pid = pid;
 }
 
@@ -82,7 +81,7 @@
 
   SpinMutexLock l(mu);
   if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
-    internal_close(fd);
+    CloseFile(fd);
   fd = kInvalidFd;
   if (internal_strcmp(path, "stdout") == 0) {
     fd = kStdoutFd;
@@ -136,7 +135,7 @@
 }
 
 uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
-                      uptr max_len, int *errno_p) {
+                      uptr max_len, error_t *errno_p) {
   uptr PageSize = GetPageSizeCached();
   uptr kMinFileLen = PageSize;
   uptr read_len = 0;
@@ -144,9 +143,8 @@
   *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) {
-    uptr openrv = OpenFile(file_name, RdOnly);
-    if (internal_iserror(openrv, errno_p)) return 0;
-    fd_t fd = openrv;
+    fd_t fd = OpenFile(file_name, RdOnly, errno_p);
+    if (fd == kInvalidFd) return 0;
     UnmapOrDie(*buff, *buff_size);
     *buff = (char*)MmapOrDie(size, __func__);
     *buff_size = size;
@@ -154,8 +152,8 @@
     read_len = 0;
     bool reached_eof = false;
     while (read_len + PageSize <= size) {
-      uptr just_read = internal_read(fd, *buff + read_len, PageSize);
-      if (internal_iserror(just_read, errno_p)) {
+      uptr just_read;
+      if (!ReadFromFile(fd, *buff + read_len, PageSize, &just_read, errno_p)) {
         UnmapOrDie(*buff, *buff_size);
         return 0;
       }
@@ -165,7 +163,7 @@
       }
       read_len += just_read;
     }
-    internal_close(fd);
+    CloseFile(fd);
     if (reached_eof)  // We've read the whole file.
       break;
   }
@@ -219,8 +217,15 @@
 const char *StripModuleName(const char *module) {
   if (module == 0)
     return 0;
-  if (const char *slash_pos = internal_strrchr(module, '/'))
+  if (SANITIZER_WINDOWS) {
+    // On Windows, both slash and backslash are possible.
+    // Pick the one that goes last.
+    if (const char *bslash_pos = internal_strrchr(module, '\\'))
+      return StripModuleName(bslash_pos + 1);
+  }
+  if (const char *slash_pos = internal_strrchr(module, '/')) {
     return slash_pos + 1;
+  }
   return module;
 }
 
@@ -243,14 +248,15 @@
 }
 #endif
 
-LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
+void LoadedModule::set(const char *module_name, uptr base_address) {
+  clear();
   full_name_ = internal_strdup(module_name);
   base_address_ = base_address;
-  ranges_.clear();
 }
 
 void LoadedModule::clear() {
   InternalFree(full_name_);
+  full_name_ = nullptr;
   while (!ranges_.empty()) {
     AddressRange *r = ranges_.front();
     ranges_.pop_front();
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index 0dfa815..2e920c8 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -39,6 +39,9 @@
 
 const uptr kMaxPathLength = 4096;
 
+// 16K loaded modules should be enough for everyone.
+static const uptr kMaxNumberOfModules = 1 << 14;
+
 const uptr kMaxThreadStackSize = 1 << 30;  // 1Gb
 
 extern const char *SanitizerToolName;  // Can be changed by the tool.
@@ -69,9 +72,13 @@
 void *MmapFixedNoReserve(uptr fixed_addr, uptr size);
 void *MmapNoReserveOrDie(uptr size, const char *mem_type);
 void *MmapFixedOrDie(uptr fixed_addr, uptr size);
-void *Mprotect(uptr fixed_addr, uptr size);
+void *MmapNoAccess(uptr fixed_addr, uptr size);
 // Map aligned chunk of address space; size and alignment are powers of two.
 void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type);
+// Disallow access to a memory range.  Use MmapNoAccess to allocate an
+// unaccessible memory.
+bool MprotectNoAccess(uptr addr, uptr size);
+
 // Used to check if we can map shadow memory to a fixed location.
 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
 void FlushUnneededShadowMemory(uptr addr, uptr size);
@@ -160,7 +167,7 @@
 
 struct ReportFile {
   void Write(const char *buffer, uptr length);
-  bool PrintsToTty();
+  bool SupportsColors();
   void SetReportPath(const char *path);
 
   // Don't use fields directly. They are only declared public to allow
@@ -193,18 +200,33 @@
   RdWr
 };
 
-uptr OpenFile(const char *filename, FileAccessMode mode);
+// Returns kInvalidFd on error.
+fd_t OpenFile(const char *filename, FileAccessMode mode,
+              error_t *errno_p = nullptr);
+void CloseFile(fd_t);
+
+// Return true on success, false on error.
+bool ReadFromFile(fd_t fd, void *buff, uptr buff_size,
+                  uptr *bytes_read = nullptr, error_t *error_p = nullptr);
+bool WriteToFile(fd_t fd, const void *buff, uptr buff_size,
+                 uptr *bytes_written = nullptr, error_t *error_p = nullptr);
+
+bool RenameFile(const char *oldpath, const char *newpath,
+                error_t *error_p = nullptr);
+
+bool SupportsColoredOutput(fd_t fd);
+
 // 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',
 // Returns the number of read bytes or 0 if file can not be opened.
 uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
-                      uptr max_len, int *errno_p = nullptr);
+                      uptr max_len, error_t *errno_p = nullptr);
 // Maps given file to virtual memory, and returns pointer to it
-// (or NULL if the mapping failes). Stores the size of mmaped region
+// (or NULL if mapping fails). Stores the size of mmaped region
 // in '*buff_size'.
 void *MapFileToMemory(const char *file_name, uptr *buff_size);
-void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset);
+void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, uptr offset);
 
 bool IsAccessibleMemoryRange(uptr beg, uptr size);
 
@@ -548,8 +570,8 @@
 // executable or a shared object).
 class LoadedModule {
  public:
-  LoadedModule() : full_name_(nullptr), base_address_(0) {}
-  LoadedModule(const char *module_name, uptr base_address);
+  LoadedModule() : full_name_(nullptr), base_address_(0) { ranges_.clear(); }
+  void set(const char *module_name, uptr base_address);
   void clear();
   void addAddressRange(uptr beg, uptr end, bool executable);
   bool containsAddress(uptr address) const;
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index f724115..69c1cf8 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -102,6 +102,13 @@
 #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0)
 #endif
 
+#define COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n)       \
+    COMMON_INTERCEPTOR_READ_RANGE((ctx), (s),                       \
+      common_flags()->strict_string_checks ? (len) + 1 : (n) )
+
+#define COMMON_INTERCEPTOR_READ_STRING(ctx, s, n)                   \
+    COMMON_INTERCEPTOR_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
+
 #ifndef COMMON_INTERCEPTOR_ON_DLOPEN
 #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) {}
 #endif
@@ -159,7 +166,8 @@
 INTERCEPTOR(char*, textdomain, const char *domainname) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname);
-  char* domain = REAL(textdomain)(domainname);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0);
+  char *domain = REAL(textdomain)(domainname);
   if (domain) {
     COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, REAL(strlen)(domain) + 1);
   }
@@ -185,8 +193,8 @@
     c2 = (unsigned char)s2[i];
     if (c1 != c2 || c1 == '\0') break;
   }
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
   return CharCmpX(c1, c2);
 }
 
@@ -231,8 +239,8 @@
     c2 = (unsigned char)s2[i];
     if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
   }
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
   return CharCaseCmp(c1, c2);
 }
 
@@ -727,12 +735,12 @@
   // its metadata. See
   // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
   char *res = REAL(strptime)(s, format, tm);
-  if (res) {
-    COMMON_INTERCEPTOR_READ_RANGE(ctx, s, res - s);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, s, res ? res - s : 0);
+  if (res && tm) {
     // Do not call unpoison_tm here, because strptime does not, in fact,
     // initialize the entire struct tm. For example, tm_zone pointer is left
     // uninitialized.
-    if (tm) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
   }
   return res;
 }
@@ -1513,6 +1521,7 @@
             __sanitizer_glob_t *pglob) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
   __sanitizer_glob_t glob_copy = {
       0,                  0,                   0,
       0,                  wrapped_gl_closedir, wrapped_gl_readdir,
@@ -1543,6 +1552,7 @@
             __sanitizer_glob_t *pglob) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
   __sanitizer_glob_t glob_copy = {
       0,                  0,                   0,
       0,                  wrapped_gl_closedir, wrapped_gl_readdir,
@@ -1689,6 +1699,7 @@
 INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, inet_pton, af, src, dst);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, src, 0);
   // FIXME: figure out read size based on the address family.
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
@@ -2359,6 +2370,37 @@
 #define INIT_GET_CURRENT_DIR_NAME
 #endif
 
+UNUSED static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
+  CHECK(endptr);
+  if (nptr == *endptr) {
+    // No digits were found at strtol call, we need to find out the last
+    // symbol accessed by strtoll on our own.
+    // We get this symbol by skipping leading blanks and optional +/- sign.
+    while (IsSpace(*nptr)) nptr++;
+    if (*nptr == '+' || *nptr == '-') nptr++;
+    *endptr = const_cast<char *>(nptr);
+  }
+  CHECK(*endptr >= nptr);
+}
+
+UNUSED static inline void StrtolFixAndCheck(void *ctx, const char *nptr,
+                             char **endptr, char *real_endptr, int base) {
+  if (endptr != 0) {
+    *endptr = real_endptr;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+  }
+  // If base has unsupported value, strtol can exit with EINVAL
+  // without reading any characters. So do additional checks only
+  // if base is valid.
+  bool is_valid_base = (base == 0) || (2 <= base && base <= 36);
+  if (is_valid_base) {
+    FixRealStrtolEndptr(nptr, &real_endptr);
+  }
+  COMMON_INTERCEPTOR_READ_STRING(ctx, nptr, is_valid_base ?
+                                 (real_endptr - nptr) + 1 : 0);
+}
+
+
 #if SANITIZER_INTERCEPT_STRTOIMAX
 INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
   void *ctx;
@@ -2366,8 +2408,9 @@
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
-  INTMAX_T res = REAL(strtoimax)(nptr, endptr, base);
-  if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+  char *real_endptr;
+  INTMAX_T res = REAL(strtoimax)(nptr, &real_endptr, base);
+  StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
   return res;
 }
 
@@ -2377,8 +2420,9 @@
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
-  INTMAX_T res = REAL(strtoumax)(nptr, endptr, base);
-  if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr));
+  char *real_endptr;
+  INTMAX_T res = REAL(strtoumax)(nptr, &real_endptr, base);
+  StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
   return res;
 }
 
@@ -3642,6 +3686,7 @@
 INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name);
+  COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0);
   COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name);
   return REAL(pthread_setname_np)(thread, name);
 }
@@ -4699,6 +4744,7 @@
 INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag);
+  if (filename) COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
   COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag);
   void *res = REAL(dlopen)(filename, flag);
   COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res);
diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc
index 9622e60..1b65bce 100644
--- a/lib/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -17,12 +17,16 @@
 #include "sanitizer_stacktrace.h"
 #include "sanitizer_symbolizer.h"
 
+#if SANITIZER_POSIX
+#include "sanitizer_posix.h"
+#endif
+
 namespace __sanitizer {
 
-bool ReportFile::PrintsToTty() {
+bool ReportFile::SupportsColors() {
   SpinMutexLock l(mu);
   ReopenIfNecessary();
-  return internal_isatty(fd) != 0;
+  return SupportsColoredOutput(fd);
 }
 
 bool ColorizeReports() {
@@ -33,7 +37,7 @@
 
   const char *flag = common_flags()->color;
   return internal_strcmp(flag, "always") == 0 ||
-         (internal_strcmp(flag, "auto") == 0 && report_file.PrintsToTty());
+         (internal_strcmp(flag, "auto") == 0 && report_file.SupportsColors());
 }
 
 static void (*sandboxing_callback)();
@@ -113,12 +117,13 @@
 }
 
 void MaybeStartBackgroudThread() {
-  if (!SANITIZER_LINUX) return;  // Need to implement/test on other platforms.
+#if SANITIZER_LINUX  // Need to implement/test on other platforms.
   // Start the background thread if one of the rss limits is given.
   if (!common_flags()->hard_rss_limit_mb &&
       !common_flags()->soft_rss_limit_mb) return;
   if (!&real_pthread_create) return;  // Can't spawn the thread anyway.
   internal_start_thread(BackgroundThread, nullptr);
+#endif
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index 94863c6..2c7c7e0 100644
--- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -63,7 +63,7 @@
 // dump current memory layout to another file.
 
 static bool cov_sandboxed = false;
-static int cov_fd = kInvalidFd;
+static fd_t cov_fd = kInvalidFd;
 static unsigned int cov_max_block_size = 0;
 static bool coverage_enabled = false;
 static const char *coverage_dir;
@@ -109,7 +109,8 @@
 
   // Maximal size pc array may ever grow.
   // We MmapNoReserve this space to ensure that the array is contiguous.
-  static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 26, 1 << 27);
+  static const uptr kPcArrayMaxSize =
+      FIRST_32_SECOND_64(1 << (SANITIZER_ANDROID ? 24 : 26), 1 << 27);
   // The amount file mapping for the pc array is grown by.
   static const uptr kPcArrayMmapSize = 64 * 1024;
 
@@ -123,7 +124,7 @@
   // Current file mapped size of the pc array.
   uptr pc_array_mapped_size;
   // Descriptor of the file mapped pc array.
-  int pc_fd;
+  fd_t pc_fd;
 
   // Vector of coverage guard arrays, protected by mu.
   InternalMmapVectorNoCtor<s32*> guard_array_vec;
@@ -176,8 +177,8 @@
   internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw",
                     coverage_dir, internal_getpid());
   pc_fd = OpenFile(path.data(), RdWr);
-  if (internal_iserror(pc_fd)) {
-    Report(" Coverage: failed to open %s for reading/writing\n", path.data());
+  if (pc_fd == kInvalidFd) {
+    Report("Coverage: failed to open %s for reading/writing\n", path.data());
     Die();
   }
 
@@ -210,8 +211,9 @@
   tr_event_array = reinterpret_cast<u32 *>(MmapNoReserveOrDie(
       sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + GetMmapGranularity(),
       "CovInit::tr_event_array"));
-  Mprotect(reinterpret_cast<uptr>(&tr_event_array[kTrEventArrayMaxSize]),
-           GetMmapGranularity());
+  MprotectNoAccess(
+      reinterpret_cast<uptr>(&tr_event_array[kTrEventArrayMaxSize]),
+      GetMmapGranularity());
   tr_event_array_size = kTrEventArrayMaxSize;
   tr_event_pointer = tr_event_array;
 
@@ -229,22 +231,22 @@
 
 void CoverageData::Disable() {
   if (pc_array) {
-    internal_munmap(pc_array, sizeof(uptr) * kPcArrayMaxSize);
+    UnmapOrDie(pc_array, sizeof(uptr) * kPcArrayMaxSize);
     pc_array = nullptr;
   }
   if (cc_array) {
-    internal_munmap(cc_array, sizeof(uptr *) * kCcArrayMaxSize);
+    UnmapOrDie(cc_array, sizeof(uptr *) * kCcArrayMaxSize);
     cc_array = nullptr;
   }
   if (tr_event_array) {
-    internal_munmap(tr_event_array,
-                    sizeof(tr_event_array[0]) * kTrEventArrayMaxSize +
-                        GetMmapGranularity());
+    UnmapOrDie(tr_event_array,
+               sizeof(tr_event_array[0]) * kTrEventArrayMaxSize +
+                   GetMmapGranularity());
     tr_event_array = nullptr;
     tr_event_pointer = nullptr;
   }
   if (pc_fd != kInvalidFd) {
-    internal_close(pc_fd);
+    CloseFile(pc_fd);
     pc_fd = kInvalidFd;
   }
 }
@@ -338,9 +340,8 @@
   const char *module_name = sym->GetModuleNameForPc(caller_pc);
   if (!module_name) return;
   if (module_name_vec.empty() ||
-      internal_strcmp(module_name_vec.back().copied_module_name, module_name))
-    module_name_vec.push_back(
-        {internal_strdup(module_name), range_beg, range_end});
+      module_name_vec.back().copied_module_name != module_name)
+    module_name_vec.push_back({module_name, range_beg, range_end});
   else
     module_name_vec.back().end = range_end;
 }
@@ -516,15 +517,15 @@
 
 static void CovWritePacked(int pid, const char *module, const void *blob,
                            unsigned int blob_size) {
-  if (cov_fd < 0) return;
+  if (cov_fd == kInvalidFd) return;
   unsigned module_name_length = internal_strlen(module);
   CovHeader header = {pid, module_name_length, blob_size};
 
   if (cov_max_block_size == 0) {
     // Writing to a file. Just go ahead.
-    internal_write(cov_fd, &header, sizeof(header));
-    internal_write(cov_fd, module, module_name_length);
-    internal_write(cov_fd, blob, blob_size);
+    WriteToFile(cov_fd, &header, sizeof(header));
+    WriteToFile(cov_fd, module, module_name_length);
+    WriteToFile(cov_fd, blob, blob_size);
   } else {
     // Writing to a socket. We want to split the data into appropriately sized
     // blocks.
@@ -547,8 +548,7 @@
       internal_memcpy(block_data_begin, blob_pos, payload_size);
       blob_pos += payload_size;
       ((CovHeader *)block.data())->data_length = payload_size;
-      internal_write(cov_fd, block.data(),
-                     header_size_with_module + payload_size);
+      WriteToFile(cov_fd, block.data(), header_size_with_module + payload_size);
     }
   }
 }
@@ -557,7 +557,7 @@
 // If packed = true and name == 0: <pid>.<sancov>.<packed>.
 // If packed = true and name != 0: <name>.<sancov>.<packed> (name is
 // user-supplied).
-static int CovOpenFile(InternalScopedString *path, bool packed,
+static fd_t CovOpenFile(InternalScopedString *path, bool packed,
                        const char *name, const char *extension = "sancov") {
   path->clear();
   if (!packed) {
@@ -571,11 +571,9 @@
     else
       path->append("%s/%s.%s.packed", coverage_dir, name, extension);
   }
-  uptr fd = OpenFile(path->data(), WrOnly);
-  if (internal_iserror(fd)) {
-    Report(" SanitizerCoverage: failed to open %s for writing\n", path->data());
-    return -1;
-  }
+  fd_t fd = OpenFile(path->data(), WrOnly);
+  if (fd == kInvalidFd)
+    Report("SanitizerCoverage: failed to open %s for writing\n", path->data());
   return fd;
 }
 
@@ -595,34 +593,35 @@
     out.append("%s 0x%zx\n", module_name, module_address);
   }
   InternalScopedString path(kMaxPathLength);
-  int fd = CovOpenFile(&path, false, "trace-points");
-  if (fd < 0) return;
-  internal_write(fd, out.data(), out.length());
-  internal_close(fd);
+  fd_t fd = CovOpenFile(&path, false, "trace-points");
+  if (fd == kInvalidFd) return;
+  WriteToFile(fd, out.data(), out.length());
+  CloseFile(fd);
 
   fd = CovOpenFile(&path, false, "trace-compunits");
-  if (fd < 0) return;
+  if (fd == kInvalidFd) return;
   out.clear();
   for (uptr i = 0; i < comp_unit_name_vec.size(); i++)
     out.append("%s\n", comp_unit_name_vec[i].copied_module_name);
-  internal_write(fd, out.data(), out.length());
-  internal_close(fd);
+  WriteToFile(fd, out.data(), out.length());
+  CloseFile(fd);
 
   fd = CovOpenFile(&path, false, "trace-events");
-  if (fd < 0) return;
+  if (fd == kInvalidFd) return;
   uptr bytes_to_write = max_idx * sizeof(tr_event_array[0]);
   u8 *event_bytes = reinterpret_cast<u8*>(tr_event_array);
   // The trace file could be huge, and may not be written with a single syscall.
   while (bytes_to_write) {
-    uptr actually_written = internal_write(fd, event_bytes, bytes_to_write);
-    if (actually_written <= bytes_to_write) {
+    uptr actually_written;
+    if (WriteToFile(fd, event_bytes, bytes_to_write, &actually_written) &&
+        actually_written <= bytes_to_write) {
       bytes_to_write -= actually_written;
       event_bytes += actually_written;
     } else {
       break;
     }
   }
-  internal_close(fd);
+  CloseFile(fd);
   VReport(1, " CovDump: Trace: %zd PCs written\n", size());
   VReport(1, " CovDump: Trace: %zd Events written\n", max_idx);
 }
@@ -660,10 +659,10 @@
     }
   }
   InternalScopedString path(kMaxPathLength);
-  int fd = CovOpenFile(&path, false, "caller-callee");
-  if (fd < 0) return;
-  internal_write(fd, out.data(), out.length());
-  internal_close(fd);
+  fd_t fd = CovOpenFile(&path, false, "caller-callee");
+  if (fd == kInvalidFd) return;
+  WriteToFile(fd, out.data(), out.length());
+  CloseFile(fd);
   VReport(1, " CovDump: %zd caller-callee pairs written\n", total);
 }
 
@@ -694,11 +693,11 @@
     CHECK_LE(r.beg, r.end);
     CHECK_LE(r.end, size());
     const char *base_name = StripModuleName(r.copied_module_name);
-    int fd =
+    fd_t fd =
         CovOpenFile(&path, /* packed */ false, base_name, "counters-sancov");
-    if (fd < 0) return;
-    internal_write(fd, bitset.data() + r.beg, r.end - r.beg);
-    internal_close(fd);
+    if (fd == kInvalidFd) return;
+    WriteToFile(fd, bitset.data() + r.beg, r.end - r.beg);
+    CloseFile(fd);
     VReport(1, " CovDump: %zd counters written for '%s'\n", r.end - r.beg,
             base_name);
   }
@@ -722,10 +721,10 @@
         n_set_bits++;
     }
     const char *base_name = StripModuleName(r.copied_module_name);
-    int fd = CovOpenFile(&path, /* packed */ false, base_name, "bitset-sancov");
-    if (fd < 0) return;
-    internal_write(fd, out.data() + r.beg, r.end - r.beg);
-    internal_close(fd);
+    fd_t fd = CovOpenFile(&path, /* packed */false, base_name, "bitset-sancov");
+    if (fd == kInvalidFd) return;
+    WriteToFile(fd, out.data() + r.beg, r.end - r.beg);
+    CloseFile(fd);
     VReport(1,
             " CovDump: bitset of %zd bits written for '%s', %zd bits are set\n",
             r.end - r.beg, base_name, n_set_bits);
@@ -751,9 +750,8 @@
       uptr pc = UnbundlePc(pc_array[i]);
       uptr counter = UnbundleCounter(pc_array[i]);
       if (!pc) continue; // Not visited.
-      const char *unused;
       uptr offset = 0;
-      sym->GetModuleNameAndOffsetForPC(pc, &unused, &offset);
+      sym->GetModuleNameAndOffsetForPC(pc, nullptr, &offset);
       offsets.push_back(BundlePcAndCounter(offset, counter));
     }
 
@@ -771,22 +769,22 @@
 
     const char *module_name = StripModuleName(r.copied_module_name);
     if (cov_sandboxed) {
-      if (cov_fd >= 0) {
+      if (cov_fd != kInvalidFd) {
         CovWritePacked(internal_getpid(), module_name, offsets.data(),
                        offsets.size() * sizeof(offsets[0]));
         VReport(1, " CovDump: %zd PCs written to packed file\n", num_offsets);
       }
     } else {
       // One file per module per process.
-      int fd = CovOpenFile(&path, false /* packed */, module_name);
-      if (fd < 0) continue;
-      internal_write(fd, offsets.data(), offsets.size() * sizeof(offsets[0]));
-      internal_close(fd);
+      fd_t fd = CovOpenFile(&path, false /* packed */, module_name);
+      if (fd == kInvalidFd) continue;
+      WriteToFile(fd, offsets.data(), offsets.size() * sizeof(offsets[0]));
+      CloseFile(fd);
       VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), num_offsets);
     }
   }
-  if (cov_fd >= 0)
-    internal_close(cov_fd);
+  if (cov_fd != kInvalidFd)
+    CloseFile(cov_fd);
 }
 
 void CoverageData::DumpAll() {
@@ -805,18 +803,19 @@
   if (!coverage_enabled) return;
   cov_sandboxed = args->coverage_sandboxed;
   if (!cov_sandboxed) return;
-  cov_fd = args->coverage_fd;
   cov_max_block_size = args->coverage_max_block_size;
-  if (cov_fd < 0) {
+  if (args->coverage_fd >= 0) {
+    cov_fd = (fd_t)args->coverage_fd;
+  } else {
     InternalScopedString path(kMaxPathLength);
     // Pre-open the file now. The sandbox won't allow us to do it later.
     cov_fd = CovOpenFile(&path, true /* packed */, 0);
   }
 }
 
-int MaybeOpenCovFile(const char *name) {
+fd_t MaybeOpenCovFile(const char *name) {
   CHECK(name);
-  if (!coverage_enabled) return -1;
+  if (!coverage_enabled) return kInvalidFd;
   InternalScopedString path(kMaxPathLength);
   return CovOpenFile(&path, true /* packed */, name);
 }
@@ -836,9 +835,7 @@
   coverage_dir = dir;
   coverage_data.Init();
   if (enabled) coverage_data.Enable();
-#if !SANITIZER_WINDOWS
   if (!common_flags()->coverage_direct) Atexit(__sanitizer_cov_dump);
-#endif
 }
 
 void ReInitializeCoverage(bool enabled, const char *dir) {
@@ -893,7 +890,7 @@
 }
 SANITIZER_INTERFACE_ATTRIBUTE
 sptr __sanitizer_maybe_open_cov_file(const char *name) {
-  return MaybeOpenCovFile(name);
+  return (sptr)MaybeOpenCovFile(name);
 }
 SANITIZER_INTERFACE_ATTRIBUTE
 uptr __sanitizer_get_total_unique_coverage() {
diff --git a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
index d3bde4b..a3d75ab 100644
--- a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
@@ -35,7 +35,6 @@
 
 namespace __sanitizer {
 
-static const uptr kMaxNumberOfModules = 1 << 14;
 static const uptr kMaxTextSize = 64 * 1024;
 
 struct CachedMapping {
@@ -96,32 +95,30 @@
     }
   }
 
-  int err;
+  error_t err;
   InternalScopedString tmp_path(64 + internal_strlen(coverage_dir));
   uptr res = internal_snprintf((char *)tmp_path.data(), tmp_path.size(),
                                "%s/%zd.sancov.map.tmp", coverage_dir,
                                internal_getpid());
   CHECK_LE(res, tmp_path.size());
-  uptr map_fd = OpenFile(tmp_path.data(), WrOnly);
-  if (internal_iserror(map_fd, &err)) {
-    Report(" Coverage: failed to open %s for writing: %d\n", tmp_path.data(),
+  fd_t map_fd = OpenFile(tmp_path.data(), WrOnly, &err);
+  if (map_fd == kInvalidFd) {
+    Report("Coverage: failed to open %s for writing: %d\n", tmp_path.data(),
            err);
     Die();
   }
 
-  res = internal_write(map_fd, text.data(), text.length());
-  if (internal_iserror(res, &err)) {
+  if (!WriteToFile(map_fd, text.data(), text.length(), nullptr, &err)) {
     Printf("sancov.map write failed: %d\n", err);
     Die();
   }
-  internal_close(map_fd);
+  CloseFile(map_fd);
 
   InternalScopedString path(64 + internal_strlen(coverage_dir));
   res = internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.map",
                           coverage_dir, internal_getpid());
   CHECK_LE(res, path.size());
-  res = internal_rename(tmp_path.data(), path.data());
-  if (internal_iserror(res, &err)) {
+  if (!RenameFile(tmp_path.data(), path.data(), &err)) {
     Printf("sancov.map rename failed: %d\n", err);
     Die();
   }
diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector1.cc b/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
index b931edc..5890b54 100644
--- a/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
+++ b/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
@@ -40,19 +40,20 @@
 
   explicit DD(const DDFlags *flags);
 
-  DDPhysicalThread* CreatePhysicalThread();
-  void DestroyPhysicalThread(DDPhysicalThread *pt);
+  DDPhysicalThread *CreatePhysicalThread() override;
+  void DestroyPhysicalThread(DDPhysicalThread *pt) override;
 
-  DDLogicalThread* CreateLogicalThread(u64 ctx);
-  void DestroyLogicalThread(DDLogicalThread *lt);
+  DDLogicalThread *CreateLogicalThread(u64 ctx) override;
+  void DestroyLogicalThread(DDLogicalThread *lt) override;
 
-  void MutexInit(DDCallback *cb, DDMutex *m);
-  void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock);
-  void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock);
-  void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock);
-  void MutexDestroy(DDCallback *cb, DDMutex *m);
+  void MutexInit(DDCallback *cb, DDMutex *m) override;
+  void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) override;
+  void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+                      bool trylock) override;
+  void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) override;
+  void MutexDestroy(DDCallback *cb, DDMutex *m) override;
 
-  DDReport *GetReport(DDCallback *cb);
+  DDReport *GetReport(DDCallback *cb) override;
 
   void MutexEnsureID(DDLogicalThread *lt, DDMutex *m);
   void ReportDeadlock(DDCallback *cb, DDMutex *m);
diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc
index e835b46..01098a3 100644
--- a/lib/sanitizer_common/sanitizer_flags.cc
+++ b/lib/sanitizer_common/sanitizer_flags.cc
@@ -54,7 +54,7 @@
   bool Parse(const char *value) final {
     char *data;
     uptr data_mapped_size;
-    int err;
+    error_t err;
     uptr len =
       ReadFileToBuffer(value, &data, &data_mapped_size,
                        Max(kMaxIncludeSize, GetPageSizeCached()), &err);
diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc
index 884602f..80c30ac 100644
--- a/lib/sanitizer_common/sanitizer_flags.inc
+++ b/lib/sanitizer_common/sanitizer_flags.inc
@@ -151,3 +151,5 @@
             "Use DEFAULT to get default format.")
 COMMON_FLAG(bool, no_huge_pages_for_shadow, true,
             "If true, the shadow is not allowed to use huge pages. ")
+COMMON_FLAG(bool, strict_string_checks, false,
+            "If set check that string arguments are properly null-terminated")
diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h
index e7737bd..b76c602 100644
--- a/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -80,7 +80,15 @@
 typedef signed   short s16;  // NOLINT
 typedef signed   int s32;
 typedef signed   long long s64;  // NOLINT
+#if SANITIZER_WINDOWS
+// On Windows, files are HANDLE, which is a synonim of void*.
+// Use void* to avoid including <windows.h> everywhere.
+typedef void* fd_t;
+typedef unsigned error_t;
+#else
 typedef int fd_t;
+typedef int error_t;
+#endif
 
 // 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
diff --git a/lib/sanitizer_common/sanitizer_libc.h b/lib/sanitizer_common/sanitizer_libc.h
index c086b8a..ae4e938 100644
--- a/lib/sanitizer_common/sanitizer_libc.h
+++ b/lib/sanitizer_common/sanitizer_libc.h
@@ -11,6 +11,7 @@
 // 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.
+// FIXME: Some of functions declared in this file are in fact POSIX, not libc.
 //===----------------------------------------------------------------------===//
 #ifndef SANITIZER_LIBC_H
 #define SANITIZER_LIBC_H
@@ -56,74 +57,26 @@
 // Optimized for the case when the result is true.
 bool mem_is_zero(const char *mem, uptr size);
 
-
-// Memory
-uptr internal_mmap(void *addr, uptr length, int prot, int flags,
-                   int fd, u64 offset);
-uptr internal_munmap(void *addr, uptr length);
-
 // I/O
-const fd_t kInvalidFd = -1;
+const fd_t kInvalidFd = (fd_t)-1;
 const fd_t kStdinFd = 0;
-const fd_t kStdoutFd = 1;
-const fd_t kStderrFd = 2;
-uptr internal_close(fd_t fd);
-int internal_isatty(fd_t fd);
+const fd_t kStdoutFd = (fd_t)1;
+const fd_t kStderrFd = (fd_t)2;
 
-// Use __sanitizer::OpenFile() instead.
-uptr internal_open(const char *filename, int flags);
-uptr internal_open(const char *filename, int flags, u32 mode);
-
-uptr internal_read(fd_t fd, void *buf, uptr count);
-uptr internal_write(fd_t fd, const void *buf, uptr count);
 uptr internal_ftruncate(fd_t fd, uptr size);
 
 // OS
-uptr internal_filesize(fd_t fd);  // -1 on error.
-uptr internal_stat(const char *path, void *buf);
-uptr internal_lstat(const char *path, void *buf);
-uptr internal_fstat(fd_t fd, void *buf);
-uptr internal_dup2(int oldfd, int newfd);
-uptr internal_readlink(const char *path, char *buf, uptr bufsize);
-uptr internal_unlink(const char *path);
-uptr internal_rename(const char *oldpath, const char *newpath);
 void NORETURN internal__exit(int exitcode);
-uptr internal_lseek(fd_t fd, OFF_T offset, int whence);
 
-uptr internal_ptrace(int request, int pid, void *addr, void *data);
-uptr internal_waitpid(int pid, int *status, int options);
 uptr internal_getpid();
 uptr internal_getppid();
 
-int internal_fork();
-
 // Threading
 uptr internal_sched_yield();
 
-// These functions call appropriate pthread_ functions directly, bypassing
-// the interceptor. They are weak and may not be present in some tools.
-SANITIZER_WEAK_ATTRIBUTE
-int real_pthread_create(void *th, void *attr, void *(*callback)(void *),
-                        void *param);
-SANITIZER_WEAK_ATTRIBUTE
-int real_pthread_join(void *th, void **ret);
-
-#define DEFINE_REAL_PTHREAD_FUNCTIONS                                          \
-  namespace __sanitizer {                                                      \
-  int real_pthread_create(void *th, void *attr, void *(*callback)(void *),     \
-                          void *param) {                                       \
-    return REAL(pthread_create)(th, attr, callback, param);                    \
-  }                                                                            \
-  int real_pthread_join(void *th, void **ret) {                                \
-    return REAL(pthread_join(th, ret));                                        \
-  }                                                                            \
-  }  // namespace __sanitizer
-
 // Error handling
 bool internal_iserror(uptr retval, int *rverrno = 0);
 
-int internal_sigaction(int signum, const void *act, void *oldact);
-
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_LIBC_H
diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc
index cefb1dc..8c4aeff 100644
--- a/lib/sanitizer_common/sanitizer_libignore.cc
+++ b/lib/sanitizer_common/sanitizer_libignore.cc
@@ -12,6 +12,7 @@
 
 #include "sanitizer_libignore.h"
 #include "sanitizer_flags.h"
+#include "sanitizer_posix.h"
 #include "sanitizer_procmaps.h"
 
 namespace __sanitizer {
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index 8d2ea48..11a6fe6 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -127,6 +127,10 @@
   return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
 }
 
+int internal_mprotect(void *addr, uptr length, int prot) {
+  return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
+}
+
 uptr internal_close(fd_t fd) {
   return internal_syscall(SYSCALL(close), fd);
 }
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index 2ce2025..fd3c134 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -17,6 +17,7 @@
 #if SANITIZER_FREEBSD || SANITIZER_LINUX
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_posix.h"
 #include "sanitizer_platform_limits_posix.h"
 
 struct link_map;  // Opaque type returned by dlopen().
diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index 1c099d8..ab9f0ab 100644
--- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -15,6 +15,7 @@
 #include "sanitizer_platform.h"
 #if SANITIZER_FREEBSD || SANITIZER_LINUX
 
+#include "sanitizer_atomic.h"
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
 #include "sanitizer_freebsd.h"
@@ -22,8 +23,6 @@
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
 #include "sanitizer_stacktrace.h"
-#include "sanitizer_atomic.h"
-#include "sanitizer_symbolizer.h"
 
 #if SANITIZER_ANDROID || SANITIZER_FREEBSD
 #include <dlfcn.h>  // for dlsym()
@@ -437,9 +436,8 @@
     return 0;
   if (data->filter && !data->filter(module_name.data()))
     return 0;
-  void *mem = &data->modules[data->current_n];
-  LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
-                                                   info->dlpi_addr);
+  LoadedModule *cur_module = &data->modules[data->current_n];
+  cur_module->set(module_name.data(), info->dlpi_addr);
   data->current_n++;
   for (int i = 0; i < info->dlpi_phnum; i++) {
     const Elf_Phdr *phdr = &info->dlpi_phdr[i];
@@ -462,19 +460,6 @@
 }
 #endif  // SANITIZER_ANDROID
 
-void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
-  // Some kinds of sandboxes may forbid filesystem access, so we won't be able
-  // to read the file mappings from /proc/self/maps. Luckily, neither the
-  // process will be able to load additional libraries, so it's fine to use the
-  // cached mappings.
-  MemoryMappingLayout::CacheMemoryMappings();
-  // Same for /proc/self/exe in the symbolizer.
-#if !SANITIZER_GO
-  Symbolizer::GetOrInit()->PrepareForSandboxing();
-  CovPrepareForSandboxing(args);
-#endif
-}
-
 // getrusage does not give us the current RSS, only the max RSS.
 // Still, this is better than nothing if /proc/self/statm is not available
 // for some reason, e.g. due to a sandbox.
@@ -488,8 +473,8 @@
 uptr GetRSS() {
   if (!common_flags()->can_use_proc_maps_statm)
     return GetRSSFromGetrusage();
-  uptr fd = OpenFile("/proc/self/statm", RdOnly);
-  if ((sptr)fd < 0)
+  fd_t fd = OpenFile("/proc/self/statm", RdOnly);
+  if (fd == kInvalidFd)
     return GetRSSFromGetrusage();
   char buf[64];
   uptr len = internal_read(fd, buf, sizeof(buf) - 1);
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index 91a5b7d..4c5b409 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -59,6 +59,10 @@
   return munmap(addr, length);
 }
 
+int internal_mprotect(void *addr, uptr length, int prot) {
+  return mprotect(addr, length, prot);
+}
+
 uptr internal_close(fd_t fd) {
   return close(fd);
 }
@@ -220,11 +224,6 @@
   UNIMPLEMENTED();
 }
 
-void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
-  (void)args;
-  // Nothing here for now.
-}
-
 uptr GetPageSize() {
   return sysconf(_SC_PAGESIZE);
 }
diff --git a/lib/sanitizer_common/sanitizer_mac.h b/lib/sanitizer_common/sanitizer_mac.h
index 9eed905..f5d3fe8 100644
--- a/lib/sanitizer_common/sanitizer_mac.h
+++ b/lib/sanitizer_common/sanitizer_mac.h
@@ -15,6 +15,7 @@
 
 #include "sanitizer_platform.h"
 #if SANITIZER_MAC
+#include "sanitizer_posix.h"
 
 namespace __sanitizer {
 
diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h
index fef5a5b..92f7848 100644
--- a/lib/sanitizer_common/sanitizer_platform.h
+++ b/lib/sanitizer_common/sanitizer_platform.h
@@ -130,4 +130,10 @@
 # define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12)
 #endif
 
+// Assume obsolete RPC headers are available by default
+#if !defined(HAVE_RPC_XDR_H) && !defined(HAVE_TIRPC_RPC_XDR_H)
+# define HAVE_RPC_XDR_H (SANITIZER_LINUX && !SANITIZER_ANDROID)
+# define HAVE_TIRPC_RPC_XDR_H 0
+#endif
+
 #endif // SANITIZER_PLATFORM_H
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index 2839e92..e8117f3 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -135,7 +135,11 @@
 #include <netax25/ax25.h>
 #include <netipx/ipx.h>
 #include <netrom/netrom.h>
-#include <rpc/xdr.h>
+#if HAVE_RPC_XDR_H
+# include <rpc/xdr.h>
+#elif HAVE_TIRPC_RPC_XDR_H
+# include <tirpc/rpc/xdr.h>
+#endif
 #include <scsi/scsi.h>
 #include <sys/mtio.h>
 #include <sys/kd.h>
@@ -1159,7 +1163,7 @@
 CHECK_SIZE_AND_OFFSET(group, gr_gid);
 CHECK_SIZE_AND_OFFSET(group, gr_mem);
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if HAVE_RPC_XDR_H || HAVE_TIRPC_RPC_XDR_H
 CHECK_TYPE_SIZE(XDR);
 CHECK_SIZE_AND_OFFSET(XDR, x_op);
 CHECK_SIZE_AND_OFFSET(XDR, x_ops);
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
index 5e01212..0b6d35e 100644
--- a/lib/sanitizer_common/sanitizer_posix.cc
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -9,7 +9,7 @@
 //
 // This file is shared between AddressSanitizer and ThreadSanitizer
 // run-time libraries and implements POSIX-specific functions from
-// sanitizer_libc.h.
+// sanitizer_posix.h.
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_platform.h"
@@ -17,6 +17,7 @@
 
 #include "sanitizer_common.h"
 #include "sanitizer_libc.h"
+#include "sanitizer_posix.h"
 #include "sanitizer_procmaps.h"
 #include "sanitizer_stacktrace.h"
 
@@ -198,27 +199,62 @@
   return (void *)p;
 }
 
-void *Mprotect(uptr fixed_addr, uptr size) {
+void *MmapNoAccess(uptr fixed_addr, uptr size) {
   return (void *)internal_mmap((void*)fixed_addr, size,
                                PROT_NONE,
                                MAP_PRIVATE | MAP_ANON | MAP_FIXED |
                                MAP_NORESERVE, -1, 0);
 }
 
-uptr OpenFile(const char *filename, FileAccessMode mode) {
+bool MprotectNoAccess(uptr addr, uptr size) {
+  return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
+}
+
+fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
   int flags;
   switch (mode) {
     case RdOnly: flags = O_RDONLY; break;
     case WrOnly: flags = O_WRONLY | O_CREAT; break;
     case RdWr: flags = O_RDWR | O_CREAT; break;
   }
-  return internal_open(filename, flags, 0660);
+  fd_t res = internal_open(filename, flags, 0660);
+  if (internal_iserror(res, errno_p))
+    return kInvalidFd;
+  return res;
+}
+
+void CloseFile(fd_t fd) {
+  internal_close(fd);
+}
+
+bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
+                  error_t *error_p) {
+  uptr res = internal_read(fd, buff, buff_size);
+  if (internal_iserror(res, error_p))
+    return false;
+  if (bytes_read)
+    *bytes_read = res;
+  return true;
+}
+
+bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
+                 error_t *error_p) {
+  uptr res = internal_write(fd, buff, buff_size);
+  if (internal_iserror(res, error_p))
+    return false;
+  if (bytes_written)
+    *bytes_written = res;
+  return true;
+}
+
+bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
+  uptr res = internal_rename(oldpath, newpath);
+  return !internal_iserror(res, error_p);
 }
 
 void *MapFileToMemory(const char *file_name, uptr *buff_size) {
-  uptr openrv = OpenFile(file_name, RdOnly);
-  CHECK(!internal_iserror(openrv));
-  fd_t fd = openrv;
+  fd_t fd = OpenFile(file_name, RdOnly);
+  CHECK(fd != kInvalidFd);
   uptr fsize = internal_filesize(fd);
   CHECK_NE(fsize, (uptr)-1);
   CHECK_GT(fsize, 0);
@@ -227,13 +263,13 @@
   return internal_iserror(map) ? 0 : (void *)map;
 }
 
-void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
+void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, uptr offset) {
   uptr flags = MAP_SHARED;
   if (addr) flags |= MAP_FIXED;
   uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
   int mmap_errno = 0;
   if (internal_iserror(p, &mmap_errno)) {
-    Printf("could not map writable file (%zd, %zu, %zu): %zd, errno: %d\n",
+    Printf("could not map writable file (%d, %zu, %zu): %zd, errno: %d\n",
            fd, offset, size, p, mmap_errno);
     return 0;
   }
diff --git a/lib/sanitizer_common/sanitizer_posix.h b/lib/sanitizer_common/sanitizer_posix.h
new file mode 100644
index 0000000..a3377a8
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_posix.h
@@ -0,0 +1,81 @@
+//===-- sanitizer_posix.h -------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries and declares some useful POSIX-specific functions.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_POSIX_H
+#define SANITIZER_POSIX_H
+
+// ----------- ATTENTION -------------
+// This header should NOT include any other headers from sanitizer runtime.
+#include "sanitizer_internal_defs.h"
+
+#if !SANITIZER_POSIX
+// Make it hard to accidentally use any of functions declared in this file:
+#error This file should only be included on POSIX
+#endif
+
+namespace __sanitizer {
+
+// I/O
+// Don't use directly, use __sanitizer::OpenFile() instead.
+uptr internal_open(const char *filename, int flags);
+uptr internal_open(const char *filename, int flags, u32 mode);
+uptr internal_close(fd_t fd);
+
+uptr internal_read(fd_t fd, void *buf, uptr count);
+uptr internal_write(fd_t fd, const void *buf, uptr count);
+
+// Memory
+uptr internal_mmap(void *addr, uptr length, int prot, int flags,
+                   int fd, u64 offset);
+uptr internal_munmap(void *addr, uptr length);
+int internal_mprotect(void *addr, uptr length, int prot);
+
+// OS
+uptr internal_filesize(fd_t fd);  // -1 on error.
+uptr internal_stat(const char *path, void *buf);
+uptr internal_lstat(const char *path, void *buf);
+uptr internal_fstat(fd_t fd, void *buf);
+uptr internal_dup2(int oldfd, int newfd);
+uptr internal_readlink(const char *path, char *buf, uptr bufsize);
+uptr internal_unlink(const char *path);
+uptr internal_rename(const char *oldpath, const char *newpath);
+uptr internal_lseek(fd_t fd, OFF_T offset, int whence);
+
+uptr internal_ptrace(int request, int pid, void *addr, void *data);
+uptr internal_waitpid(int pid, int *status, int options);
+
+int internal_fork();
+
+// These functions call appropriate pthread_ functions directly, bypassing
+// the interceptor. They are weak and may not be present in some tools.
+SANITIZER_WEAK_ATTRIBUTE
+int real_pthread_create(void *th, void *attr, void *(*callback)(void *),
+                        void *param);
+SANITIZER_WEAK_ATTRIBUTE
+int real_pthread_join(void *th, void **ret);
+
+#define DEFINE_REAL_PTHREAD_FUNCTIONS                                          \
+  namespace __sanitizer {                                                      \
+  int real_pthread_create(void *th, void *attr, void *(*callback)(void *),     \
+                          void *param) {                                       \
+    return REAL(pthread_create)(th, attr, callback, param);                    \
+  }                                                                            \
+  int real_pthread_join(void *th, void **ret) {                                \
+    return REAL(pthread_join(th, ret));                                        \
+  }                                                                            \
+  }  // namespace __sanitizer
+
+int internal_sigaction(int signum, const void *act, void *oldact);
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_POSIX_H
diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
index 11828e6..9eb28c6 100644
--- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -18,7 +18,10 @@
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
 #include "sanitizer_platform_limits_posix.h"
+#include "sanitizer_posix.h"
+#include "sanitizer_procmaps.h"
 #include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
 
 #include <errno.h>
 #include <pthread.h>
@@ -119,8 +122,8 @@
 #endif
 }
 
-int internal_isatty(fd_t fd) {
-  return isatty(fd);
+bool SupportsColoredOutput(fd_t fd) {
+  return isatty(fd) != 0;
 }
 
 #ifndef SANITIZER_GO
@@ -200,6 +203,19 @@
   return result;
 }
 
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+  // Some kinds of sandboxes may forbid filesystem access, so we won't be able
+  // to read the file mappings from /proc/self/maps. Luckily, neither the
+  // process will be able to load additional libraries, so it's fine to use the
+  // cached mappings.
+  MemoryMappingLayout::CacheMemoryMappings();
+  // Same for /proc/self/exe in the symbolizer.
+#if !SANITIZER_GO
+  Symbolizer::GetOrInit()->PrepareForSandboxing();
+  CovPrepareForSandboxing(args);
+#endif
+}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc
index 2ec08d7..2c6ce8e 100644
--- a/lib/sanitizer_common/sanitizer_procmaps_common.cc
+++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc
@@ -130,7 +130,6 @@
       continue;
     if (filter && !filter(cur_name))
       continue;
-    void *mem = &modules[n_modules];
     // Don't subtract 'cur_beg' from the first entry:
     // * If a binary is compiled w/o -pie, then the first entry in
     //   process maps is likely the binary itself (all dynamic libs
@@ -143,7 +142,8 @@
     //   shadow memory of the tool), so the module can't be the
     //   first entry.
     uptr base_address = (i ? cur_beg : 0) - cur_offset;
-    LoadedModule *cur_module = new(mem) LoadedModule(cur_name, base_address);
+    LoadedModule *cur_module = &modules[n_modules];
+    cur_module->set(cur_name, base_address);
     cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
     n_modules++;
   }
diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc
index c0a8614..29d6996 100644
--- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc
+++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc
@@ -171,13 +171,13 @@
       continue;
     if (filter && !filter(cur_name))
       continue;
-    LoadedModule *cur_module = 0;
+    LoadedModule *cur_module = nullptr;
     if (n_modules > 0 &&
         0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
       cur_module = &modules[n_modules - 1];
     } else {
-      void *mem = &modules[n_modules];
-      cur_module = new(mem) LoadedModule(cur_name, cur_beg);
+      cur_module = &modules[n_modules];
+      cur_module->set(cur_name, cur_beg);
       n_modules++;
     }
     cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index 64e1c79..47b27e7 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -310,7 +310,7 @@
     // in the future.
     guard_start_ = (uptr)MmapOrDie(stack_size_ + guard_size_,
                                    "ScopedStackWithGuard");
-    CHECK_EQ(guard_start_, (uptr)Mprotect((uptr)guard_start_, guard_size_));
+    CHECK(MprotectNoAccess((uptr)guard_start_, guard_size_));
   }
   ~ScopedStackSpaceWithGuard() {
     UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_);
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cc b/lib/sanitizer_common/sanitizer_symbolizer.cc
index df7661a..8b2496a 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer.cc
@@ -75,8 +75,29 @@
   end_hook_ = end_hook;
 }
 
+const char *Symbolizer::ModuleNameOwner::GetOwnedCopy(const char *str) {
+  mu_->CheckLocked();
+
+  // 'str' will be the same string multiple times in a row, optimize this case.
+  if (last_match_ && !internal_strcmp(last_match_, str))
+    return last_match_;
+
+  // FIXME: this is linear search.
+  // We should optimize this further if this turns out to be a bottleneck later.
+  for (uptr i = 0; i < storage_.size(); ++i) {
+    if (!internal_strcmp(storage_[i], str)) {
+      last_match_ = storage_[i];
+      return last_match_;
+    }
+  }
+  last_match_ = internal_strdup(str);
+  storage_.push_back(last_match_);
+  return last_match_;
+}
+
 Symbolizer::Symbolizer(IntrusiveList<SymbolizerTool> tools)
-    : tools_(tools), start_hook_(0), end_hook_(0) {}
+    : module_names_(&mu_), n_modules_(0), modules_fresh_(false), tools_(tools),
+      start_hook_(0), end_hook_(0) {}
 
 Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym)
     : sym_(sym) {
@@ -89,76 +110,4 @@
     sym_->end_hook_();
 }
 
-SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
-  BlockingMutexLock l(&mu_);
-  const char *module_name;
-  uptr module_offset;
-  SymbolizedStack *res = SymbolizedStack::New(addr);
-  if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name,
-                                                 &module_offset))
-    return res;
-  // Always fill data about module name and offset.
-  res->info.FillModuleInfo(module_name, module_offset);
-  for (auto iter = Iterator(&tools_); iter.hasNext();) {
-    auto *tool = iter.next();
-    SymbolizerScope sym_scope(this);
-    if (tool->SymbolizePC(addr, res)) {
-      return res;
-    }
-  }
-  return res;
-}
-
-bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
-  BlockingMutexLock l(&mu_);
-  const char *module_name;
-  uptr module_offset;
-  if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name,
-                                                 &module_offset))
-    return false;
-  info->Clear();
-  info->module = internal_strdup(module_name);
-  info->module_offset = module_offset;
-  for (auto iter = Iterator(&tools_); iter.hasNext();) {
-    auto *tool = iter.next();
-    SymbolizerScope sym_scope(this);
-    if (tool->SymbolizeData(addr, info)) {
-      return true;
-    }
-  }
-  return true;
-}
-
-bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
-                                 uptr *module_address) {
-  BlockingMutexLock l(&mu_);
-  return PlatformFindModuleNameAndOffsetForAddress(pc, module_name,
-                                                   module_address);
-}
-
-void Symbolizer::Flush() {
-  BlockingMutexLock l(&mu_);
-  for (auto iter = Iterator(&tools_); iter.hasNext();) {
-    auto *tool = iter.next();
-    SymbolizerScope sym_scope(this);
-    tool->Flush();
-  }
-}
-
-const char *Symbolizer::Demangle(const char *name) {
-  BlockingMutexLock l(&mu_);
-  for (auto iter = Iterator(&tools_); iter.hasNext();) {
-    auto *tool = iter.next();
-    SymbolizerScope sym_scope(this);
-    if (const char *demangled = tool->Demangle(name))
-      return demangled;
-  }
-  return PlatformDemangle(name);
-}
-
-void Symbolizer::PrepareForSandboxing() {
-  BlockingMutexLock l(&mu_);
-  PlatformPrepareForSandboxing();
-}
-
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h
index 225da70..9233223 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.h
+++ b/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -75,7 +75,7 @@
 
 class SymbolizerTool;
 
-class Symbolizer {
+class Symbolizer final {
  public:
   /// Initialize and return platform-specific implementation of symbolizer
   /// (if it wasn't already initialized).
@@ -84,15 +84,19 @@
   // all inlined functions, if necessary).
   SymbolizedStack *SymbolizePC(uptr address);
   bool SymbolizeData(uptr address, DataInfo *info);
+
+  // The module names Symbolizer returns are stable and unique for every given
+  // module.  It is safe to store and compare them as pointers.
   bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
                                    uptr *module_address);
   const char *GetModuleNameForPc(uptr pc) {
-    const char *module_name = 0;
+    const char *module_name = nullptr;
     uptr unused;
     if (GetModuleNameAndOffsetForPC(pc, &module_name, &unused))
       return module_name;
     return nullptr;
   }
+
   // Release internal caches (if any).
   void Flush();
   // Attempts to demangle the provided C++ mangled name.
@@ -110,16 +114,40 @@
                 EndSymbolizationHook end_hook);
 
  private:
+  // GetModuleNameAndOffsetForPC has to return a string to the caller.
+  // Since the corresponding module might get unloaded later, we should create
+  // our owned copies of the strings that we can safely return.
+  // ModuleNameOwner does not provide any synchronization, thus calls to
+  // its method should be protected by |mu_|.
+  class ModuleNameOwner {
+   public:
+    explicit ModuleNameOwner(BlockingMutex *synchronized_by)
+        : storage_(kInitialCapacity), last_match_(nullptr),
+          mu_(synchronized_by) {}
+    const char *GetOwnedCopy(const char *str);
+
+   private:
+    static const uptr kInitialCapacity = 1000;
+    InternalMmapVector<const char*> storage_;
+    const char *last_match_;
+
+    BlockingMutex *mu_;
+  } module_names_;
+
   /// Platform-specific function for creating a Symbolizer object.
   static Symbolizer *PlatformInit();
 
-  virtual bool PlatformFindModuleNameAndOffsetForAddress(
-      uptr address, const char **module_name, uptr *module_offset) {
-    UNIMPLEMENTED();
-  }
+  bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,
+                                         uptr *module_offset);
+  LoadedModule *FindModuleForAddress(uptr address);
+  LoadedModule modules_[kMaxNumberOfModules];
+  uptr n_modules_;
+  // If stale, need to reload the modules before looking up addresses.
+  bool modules_fresh_;
+
   // Platform-specific default demangler, must not return nullptr.
-  virtual const char *PlatformDemangle(const char *name) { UNIMPLEMENTED(); }
-  virtual void PlatformPrepareForSandboxing() { UNIMPLEMENTED(); }
+  const char *PlatformDemangle(const char *name);
+  void PlatformPrepareForSandboxing();
 
   static Symbolizer *symbolizer_;
   static StaticSpinMutex init_mu_;
@@ -132,7 +160,6 @@
   typedef IntrusiveList<SymbolizerTool>::Iterator Iterator;
   IntrusiveList<SymbolizerTool> tools_;
 
- protected:
   explicit Symbolizer(IntrusiveList<SymbolizerTool> tools);
 
   static LowLevelAllocator symbolizer_allocator_;
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
index f1e2289..160f55d 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -60,6 +60,121 @@
   return prefix_end;
 }
 
+SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
+  BlockingMutexLock l(&mu_);
+  const char *module_name;
+  uptr module_offset;
+  SymbolizedStack *res = SymbolizedStack::New(addr);
+  if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
+    return res;
+  // Always fill data about module name and offset.
+  res->info.FillModuleInfo(module_name, module_offset);
+  for (auto iter = Iterator(&tools_); iter.hasNext();) {
+    auto *tool = iter.next();
+    SymbolizerScope sym_scope(this);
+    if (tool->SymbolizePC(addr, res)) {
+      return res;
+    }
+  }
+  return res;
+}
+
+bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
+  BlockingMutexLock l(&mu_);
+  const char *module_name;
+  uptr module_offset;
+  if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
+    return false;
+  info->Clear();
+  info->module = internal_strdup(module_name);
+  info->module_offset = module_offset;
+  for (auto iter = Iterator(&tools_); iter.hasNext();) {
+    auto *tool = iter.next();
+    SymbolizerScope sym_scope(this);
+    if (tool->SymbolizeData(addr, info)) {
+      return true;
+    }
+  }
+  return true;
+}
+
+bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+                                             uptr *module_address) {
+  BlockingMutexLock l(&mu_);
+  const char *internal_module_name = nullptr;
+  if (!FindModuleNameAndOffsetForAddress(pc, &internal_module_name,
+                                         module_address))
+    return false;
+
+  if (module_name)
+    *module_name = module_names_.GetOwnedCopy(internal_module_name);
+  return true;
+}
+
+void Symbolizer::Flush() {
+  BlockingMutexLock l(&mu_);
+  for (auto iter = Iterator(&tools_); iter.hasNext();) {
+    auto *tool = iter.next();
+    SymbolizerScope sym_scope(this);
+    tool->Flush();
+  }
+}
+
+const char *Symbolizer::Demangle(const char *name) {
+  BlockingMutexLock l(&mu_);
+  for (auto iter = Iterator(&tools_); iter.hasNext();) {
+    auto *tool = iter.next();
+    SymbolizerScope sym_scope(this);
+    if (const char *demangled = tool->Demangle(name))
+      return demangled;
+  }
+  return PlatformDemangle(name);
+}
+
+void Symbolizer::PrepareForSandboxing() {
+  BlockingMutexLock l(&mu_);
+  PlatformPrepareForSandboxing();
+}
+
+bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,
+                                                   const char **module_name,
+                                                   uptr *module_offset) {
+  LoadedModule *module = FindModuleForAddress(address);
+  if (module == 0)
+    return false;
+  *module_name = module->full_name();
+  *module_offset = address - module->base_address();
+  return true;
+}
+
+LoadedModule *Symbolizer::FindModuleForAddress(uptr address) {
+  bool modules_were_reloaded = false;
+  if (!modules_fresh_) {
+    for (uptr i = 0; i < n_modules_; i++)
+      modules_[i].clear();
+    n_modules_ =
+        GetListOfModules(modules_, kMaxNumberOfModules, /* filter */ nullptr);
+    CHECK_GT(n_modules_, 0);
+    CHECK_LT(n_modules_, kMaxNumberOfModules);
+    modules_fresh_ = true;
+    modules_were_reloaded = true;
+  }
+  for (uptr i = 0; i < n_modules_; i++) {
+    if (modules_[i].containsAddress(address)) {
+      return &modules_[i];
+    }
+  }
+  // Reload the modules and look up again, if we haven't tried it yet.
+  if (!modules_were_reloaded) {
+    // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
+    // It's too aggressive to reload the list of modules each time we fail
+    // to find a module for a given address.
+    modules_fresh_ = false;
+    return FindModuleForAddress(address);
+  }
+  return 0;
+}
+
 Symbolizer *Symbolizer::GetOrInit() {
   SpinMutexLock l(&init_mu_);
   if (symbolizer_)
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index 189b0ab..6e714c7 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -129,13 +129,13 @@
   explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {}
 
  private:
-  bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+  bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
     // Empty line marks the end of llvm-symbolizer output.
     return length >= 2 && buffer[length - 1] == '\n' &&
            buffer[length - 2] == '\n';
   }
 
-  void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+  void ExecuteWithDefaultArgs(const char *path_to_binary) const override {
 #if defined(__x86_64__)
     const char* const kSymbolizerArch = "--default-arch=x86_64";
 #elif defined(__i386__)
@@ -202,7 +202,7 @@
   const char *module_name() const { return module_name_; }
 
  private:
-  bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+  bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
     // Output should consist of two lines.
     int num_lines = 0;
     for (uptr i = 0; i < length; ++i) {
@@ -214,7 +214,7 @@
     return false;
   }
 
-  void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+  void ExecuteWithDefaultArgs(const char *path_to_binary) const override {
     execl(path_to_binary, path_to_binary, "-Cfe", module_name_, (char *)0);
   }
 
@@ -349,69 +349,16 @@
 
 #endif  // SANITIZER_SUPPORTS_WEAK_HOOKS
 
-class POSIXSymbolizer : public Symbolizer {
- public:
-  explicit POSIXSymbolizer(IntrusiveList<SymbolizerTool> tools)
-      : Symbolizer(tools), n_modules_(0), modules_fresh_(false) {}
+const char *Symbolizer::PlatformDemangle(const char *name) {
+  return DemangleCXXABI(name);
+}
 
- private:
-  const char *PlatformDemangle(const char *name) override {
-    return DemangleCXXABI(name);
-  }
-
-  void PlatformPrepareForSandboxing() override {
+void Symbolizer::PlatformPrepareForSandboxing() {
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
-    // Cache /proc/self/exe on Linux.
-    CacheBinaryName();
+  // Cache /proc/self/exe on Linux.
+  CacheBinaryName();
 #endif
-  }
-
-  LoadedModule *FindModuleForAddress(uptr address) {
-    bool modules_were_reloaded = false;
-    if (!modules_fresh_) {
-      for (uptr i = 0; i < n_modules_; i++)
-        modules_[i].clear();
-      n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
-                                    /* filter */ 0);
-      CHECK_GT(n_modules_, 0);
-      CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
-      modules_fresh_ = true;
-      modules_were_reloaded = true;
-    }
-    for (uptr i = 0; i < n_modules_; i++) {
-      if (modules_[i].containsAddress(address)) {
-        return &modules_[i];
-      }
-    }
-    // Reload the modules and look up again, if we haven't tried it yet.
-    if (!modules_were_reloaded) {
-      // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
-      // It's too aggressive to reload the list of modules each time we fail
-      // to find a module for a given address.
-      modules_fresh_ = false;
-      return FindModuleForAddress(address);
-    }
-    return 0;
-  }
-
-  bool PlatformFindModuleNameAndOffsetForAddress(uptr address,
-                                                 const char **module_name,
-                                                 uptr *module_offset) override {
-    LoadedModule *module = FindModuleForAddress(address);
-    if (module == 0)
-      return false;
-    *module_name = module->full_name();
-    *module_offset = address - module->base_address();
-    return true;
-  }
-
-  // 16K loaded modules should be enough for everyone.
-  static const uptr kMaxNumberOfModuleContexts = 1 << 14;
-  LoadedModule modules_[kMaxNumberOfModuleContexts];
-  uptr n_modules_;
-  // If stale, need to reload the modules before looking up addresses.
-  bool modules_fresh_;
-};
+}
 
 static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
   const char *path = common_flags()->external_symbolizer_path;
@@ -494,7 +441,7 @@
   IntrusiveList<SymbolizerTool> list;
   list.clear();
   ChooseSymbolizerTools(&list, &symbolizer_allocator_);
-  return new(symbolizer_allocator_) POSIXSymbolizer(list);
+  return new(symbolizer_allocator_) Symbolizer(list);
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc
index 98d16e0..f1c01a3 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc
@@ -13,6 +13,7 @@
 
 #include "sanitizer_platform.h"
 #if SANITIZER_POSIX
+#include "sanitizer_posix.h"
 #include "sanitizer_symbolizer_internal.h"
 
 #include <errno.h>
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
index 67ed4b3..31f3746 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -129,42 +129,19 @@
     return name;
 }
 
-bool FindModuleNameAndOffsetForAddress(uptr addr, const char **module_name,
-                                       uptr *module_offset) {
-  InitializeDbgHelpIfNeeded();
-
-  IMAGEHLP_MODULE64 mod_info;
-  internal_memset(&mod_info, 0, sizeof(mod_info));
-  mod_info.SizeOfStruct = sizeof(mod_info);
-  if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info)) {
-    *module_name = mod_info.ImageName;
-    *module_offset = addr - (uptr)mod_info.BaseOfImage;
-    return true;
-  }
-  return false;
+const char *Symbolizer::PlatformDemangle(const char *name) {
+  return name;
 }
 
-// TODO(kuba.brecka): To be merged with POSIXSymbolizer.
-class WinSymbolizer : public Symbolizer {
- public:
-  explicit WinSymbolizer(IntrusiveList<SymbolizerTool> tools)
-      : Symbolizer(tools) {}
-
- private:
-  bool PlatformFindModuleNameAndOffsetForAddress(
-      uptr addr, const char **module_name, uptr *module_offset) override {
-    return ::FindModuleNameAndOffsetForAddress(addr, module_name,
-                                               module_offset);
-  }
-  const char *PlatformDemangle(const char *name) override { return name; }
-  void PlatformPrepareForSandboxing() override { }
-};
+void Symbolizer::PlatformPrepareForSandboxing() {
+  // Do nothing.
+}
 
 Symbolizer *Symbolizer::PlatformInit() {
   IntrusiveList<SymbolizerTool> list;
   list.clear();
   list.push_back(new(symbolizer_allocator_) WinSymbolizerTool());
-  return new(symbolizer_allocator_) WinSymbolizer(list);
+  return new(symbolizer_allocator_) Symbolizer(list);
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index 3ec9084..e5e2f64 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -93,6 +93,9 @@
 }
 
 void UnmapOrDie(void *addr, uptr size) {
+  if (!size || !addr)
+    return;
+
   if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
     Report("ERROR: %s failed to "
            "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
@@ -122,7 +125,7 @@
   return MmapOrDie(size, mem_type);
 }
 
-void *Mprotect(uptr fixed_addr, uptr size) {
+void *MmapNoAccess(uptr fixed_addr, uptr size) {
   void *res = VirtualAlloc((LPVOID)fixed_addr, size,
                            MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
   if (res == 0)
@@ -132,6 +135,12 @@
   return res;
 }
 
+bool MprotectNoAccess(uptr addr, uptr size) {
+  DWORD old_protection;
+  return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection);
+}
+
+
 void FlushUnneededShadowMemory(uptr addr, uptr size) {
   // This is almost useless on 32-bits.
   // FIXME: add madvise-analog when we move to 64-bits.
@@ -157,7 +166,7 @@
   UNIMPLEMENTED();
 }
 
-void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
+void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, uptr offset) {
   UNIMPLEMENTED();
 }
 
@@ -206,76 +215,46 @@
 
 namespace {
 struct ModuleInfo {
-  HMODULE handle;
+  const char *filepath;
   uptr base_address;
   uptr end_address;
 };
 
 int CompareModulesBase(const void *pl, const void *pr) {
-  const ModuleInfo &l = *(ModuleInfo *)pl, &r = *(ModuleInfo *)pr;
-  if (l.base_address < r.base_address)
+  const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr;
+  if (l->base_address < r->base_address)
     return -1;
-  return l.base_address > r.base_address;
+  return l->base_address > r->base_address;
 }
 }  // namespace
 
 #ifndef SANITIZER_GO
 void DumpProcessMap() {
   Report("Dumping process modules:\n");
-  HANDLE cur_process = GetCurrentProcess();
+  InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
+  uptr num_modules =
+      GetListOfModules(modules.data(), kMaxNumberOfModules, nullptr);
 
-  // Query the list of modules.  Start by assuming there are no more than 256
-  // modules and retry if that's not sufficient.
-  ModuleInfo *modules;
-  size_t num_modules;
-  {
-    HMODULE *hmodules = 0;
-    uptr modules_buffer_size = sizeof(HMODULE) * 256;
-    DWORD bytes_required;
-    while (!hmodules) {
-      hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
-      CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
-                               &bytes_required));
-      if (bytes_required > modules_buffer_size) {
-        // Either there turned out to be more than 256 hmodules, or new hmodules
-        // could have loaded since the last try.  Retry.
-        UnmapOrDie(hmodules, modules_buffer_size);
-        hmodules = 0;
-        modules_buffer_size = bytes_required;
-      }
-    }
-
-    num_modules = bytes_required / sizeof(HMODULE);
-    modules =
-        (ModuleInfo *)MmapOrDie(num_modules * sizeof(ModuleInfo), __FUNCTION__);
-    for (size_t i = 0; i < num_modules; ++i) {
-      modules[i].handle = hmodules[i];
-      MODULEINFO mi;
-      if (!GetModuleInformation(cur_process, hmodules[i], &mi, sizeof(mi)))
-        continue;
-      modules[i].base_address = (uptr)mi.lpBaseOfDll;
-      modules[i].end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
-    }
-    UnmapOrDie(hmodules, modules_buffer_size);
+  InternalScopedBuffer<ModuleInfo> module_infos(num_modules);
+  for (size_t i = 0; i < num_modules; ++i) {
+    module_infos[i].filepath = modules[i].full_name();
+    module_infos[i].base_address = modules[i].base_address();
+    module_infos[i].end_address = modules[i].ranges().next()->end;
   }
-
-  qsort(modules, num_modules, sizeof(ModuleInfo), CompareModulesBase);
+  qsort(module_infos.data(), num_modules, sizeof(ModuleInfo),
+        CompareModulesBase);
 
   for (size_t i = 0; i < num_modules; ++i) {
-    const ModuleInfo &mi = modules[i];
-    char module_name[MAX_PATH];
-    bool got_module_name = GetModuleFileNameA(
-        mi.handle, module_name, sizeof(module_name));
+    const ModuleInfo &mi = module_infos[i];
     if (mi.end_address != 0) {
       Printf("\t%p-%p %s\n", mi.base_address, mi.end_address,
-             got_module_name ? module_name : "[no name]");
-    } else if (got_module_name) {
-      Printf("\t??\?-??? %s\n", module_name);
+             mi.filepath[0] ? mi.filepath : "[no name]");
+    } else if (mi.filepath[0]) {
+      Printf("\t??\?-??? %s\n", mi.filepath);
     } else {
       Printf("\t???\n");
     }
   }
-  UnmapOrDie(modules, num_modules * sizeof(ModuleInfo));
 }
 #endif
 
@@ -346,117 +325,130 @@
 
 uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
                       string_predicate_t filter) {
-  UNIMPLEMENTED();
-};
+  HANDLE cur_process = GetCurrentProcess();
 
-#ifndef SANITIZER_GO
-int Atexit(void (*function)(void)) {
-  return atexit(function);
-}
-#endif
-
-// ------------------ sanitizer_libc.h
-uptr internal_mmap(void *addr, uptr length, int prot, int flags,
-                   int fd, u64 offset) {
-  UNIMPLEMENTED();
-}
-
-uptr internal_munmap(void *addr, uptr length) {
-  UNIMPLEMENTED();
-}
-
-uptr internal_close(fd_t fd) {
-  UNIMPLEMENTED();
-}
-
-int internal_isatty(fd_t fd) {
-  return _isatty(fd);
-}
-
-uptr internal_open(const char *filename, int flags) {
-  UNIMPLEMENTED();
-}
-
-uptr internal_open(const char *filename, int flags, u32 mode) {
-  UNIMPLEMENTED();
-}
-
-uptr OpenFile(const char *filename, FileAccessMode mode) {
-  UNIMPLEMENTED();
-}
-
-uptr internal_read(fd_t fd, void *buf, uptr count) {
-  UNIMPLEMENTED();
-}
-
-uptr internal_write(fd_t fd, const void *buf, uptr count) {
-  if (fd != kStderrFd)
-    UNIMPLEMENTED();
-
-  static HANDLE output_stream = 0;
-  // Abort immediately if we know printing is not possible.
-  if (output_stream == INVALID_HANDLE_VALUE)
-    return 0;
-
-  // If called for the first time, try to use stderr to output stuff,
-  // falling back to stdout if anything goes wrong.
-  bool fallback_to_stdout = false;
-  if (output_stream == 0) {
-    output_stream = GetStdHandle(STD_ERROR_HANDLE);
-    // We don't distinguish "no such handle" from error.
-    if (output_stream == 0)
-      output_stream = INVALID_HANDLE_VALUE;
-
-    if (output_stream == INVALID_HANDLE_VALUE) {
-      // Retry with stdout?
-      output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
-      if (output_stream == 0)
-        output_stream = INVALID_HANDLE_VALUE;
-      if (output_stream == INVALID_HANDLE_VALUE)
-        return 0;
-    } else {
-      // Successfully got an stderr handle.  However, if WriteFile() fails,
-      // we can still try to fallback to stdout.
-      fallback_to_stdout = true;
+  // Query the list of modules.  Start by assuming there are no more than 256
+  // modules and retry if that's not sufficient.
+  HMODULE *hmodules = 0;
+  uptr modules_buffer_size = sizeof(HMODULE) * 256;
+  DWORD bytes_required;
+  while (!hmodules) {
+    hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
+    CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
+                             &bytes_required));
+    if (bytes_required > modules_buffer_size) {
+      // Either there turned out to be more than 256 hmodules, or new hmodules
+      // could have loaded since the last try.  Retry.
+      UnmapOrDie(hmodules, modules_buffer_size);
+      hmodules = 0;
+      modules_buffer_size = bytes_required;
     }
   }
 
-  DWORD ret;
-  if (WriteFile(output_stream, buf, count, &ret, 0))
-    return ret;
+  // |num_modules| is the number of modules actually present,
+  // |count| is the number of modules we return.
+  size_t nun_modules = bytes_required / sizeof(HMODULE),
+         count = 0;
+  for (size_t i = 0; i < nun_modules && count < max_modules; ++i) {
+    HMODULE handle = hmodules[i];
+    MODULEINFO mi;
+    if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi)))
+      continue;
 
-  // Re-try with stdout if using a valid stderr handle fails.
-  if (fallback_to_stdout) {
-    output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
-    if (output_stream == 0)
-      output_stream = INVALID_HANDLE_VALUE;
-    if (output_stream != INVALID_HANDLE_VALUE)
-      return internal_write(fd, buf, count);
+    char module_name[MAX_PATH];
+    bool got_module_name =
+        GetModuleFileNameA(handle, module_name, sizeof(module_name));
+    if (!got_module_name)
+      module_name[0] = '\0';
+
+    if (filter && !filter(module_name))
+      continue;
+
+    uptr base_address = (uptr)mi.lpBaseOfDll;
+    uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
+    LoadedModule *cur_module = &modules[count];
+    cur_module->set(module_name, base_address);
+    // We add the whole module as one single address range.
+    cur_module->addAddressRange(base_address, end_address, /*executable*/ true);
+    count++;
   }
+  UnmapOrDie(hmodules, modules_buffer_size);
+
+  return count;
+};
+
+#ifndef SANITIZER_GO
+// We can't use atexit() directly at __asan_init time as the CRT is not fully
+// initialized at this point.  Place the functions into a vector and use
+// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers).
+InternalMmapVectorNoCtor<void (*)(void)> atexit_functions;
+
+int Atexit(void (*function)(void)) {
+  atexit_functions.push_back(function);
   return 0;
 }
 
-uptr internal_stat(const char *path, void *buf) {
+static int RunAtexit() {
+  int ret = 0;
+  for (uptr i = 0; i < atexit_functions.size(); ++i) {
+    ret |= atexit(atexit_functions[i]);
+  }
+  return ret;
+}
+
+#pragma section(".CRT$XID", long, read)  // NOLINT
+static __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit;
+#endif
+
+// ------------------ sanitizer_libc.h
+fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) {
+  if (mode != WrOnly)
+    UNIMPLEMENTED();
+  fd_t res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
+                        FILE_ATTRIBUTE_NORMAL, nullptr);
+  CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd);
+  CHECK(res != kStderrFd || kStderrFd == kInvalidFd);
+  return res;
+}
+
+void CloseFile(fd_t fd) {
+  CloseHandle(fd);
+}
+
+bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
+                  error_t *error_p) {
   UNIMPLEMENTED();
 }
 
-uptr internal_lstat(const char *path, void *buf) {
-  UNIMPLEMENTED();
+bool SupportsColoredOutput(fd_t fd) {
+  // FIXME: support colored output.
+  return false;
 }
 
-uptr internal_fstat(fd_t fd, void *buf) {
-  UNIMPLEMENTED();
+bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
+                 error_t *error_p) {
+  CHECK(fd != kInvalidFd);
+
+  if (fd == kStdoutFd) {
+    fd = GetStdHandle(STD_OUTPUT_HANDLE);
+    if (fd == 0) fd = kInvalidFd;
+  } else if (fd == kStderrFd) {
+    fd = GetStdHandle(STD_ERROR_HANDLE);
+    if (fd == 0) fd = kInvalidFd;
+  }
+
+  DWORD internal_bytes_written;
+  if (fd == kInvalidFd ||
+      WriteFile(fd, buff, buff_size, &internal_bytes_written, 0)) {
+    if (error_p) *error_p = GetLastError();
+    return false;
+  } else {
+    if (bytes_written) *bytes_written = internal_bytes_written;
+    return true;
+  }
 }
 
-uptr internal_filesize(fd_t fd) {
-  UNIMPLEMENTED();
-}
-
-uptr internal_dup2(int oldfd, int newfd) {
-  UNIMPLEMENTED();
-}
-
-uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
+bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
   UNIMPLEMENTED();
 }
 
@@ -473,10 +465,6 @@
   UNIMPLEMENTED();
 }
 
-uptr internal_rename(const char *oldpath, const char *newpath) {
-  UNIMPLEMENTED();
-}
-
 uptr GetRSS() {
   return 0;
 }
@@ -600,7 +588,7 @@
 void ReportFile::Write(const char *buffer, uptr length) {
   SpinMutexLock l(mu);
   ReopenIfNecessary();
-  if (length != internal_write(fd, buffer, length)) {
+  if (!WriteToFile(fd, buffer, length)) {
     // stderr may be closed, but we may be able to print to the debugger
     // instead.  This is the case when launching a program from Visual Studio,
     // and the following routine should write to its console.
diff --git a/lib/sanitizer_common/scripts/sancov.py b/lib/sanitizer_common/scripts/sancov.py
index 53180d0..776b8d9 100755
--- a/lib/sanitizer_common/scripts/sancov.py
+++ b/lib/sanitizer_common/scripts/sancov.py
@@ -4,10 +4,11 @@
 # We need to merge these integers into a set and then
 # either print them (as hex) or dump them into another file.
 import array
+import bisect
+import glob
+import os.path
 import struct
 import sys
-import bisect
-import os.path
 
 prog_name = ""
 
@@ -181,13 +182,19 @@
   if len(sys.argv) <= 2:
     Usage();
 
+  file_list = []
+  for f in sys.argv[2:]:
+    file_list += glob.glob(f)
+  if not file_list:
+    Usage()
+
   if sys.argv[1] == "print":
-    PrintFiles(sys.argv[2:])
+    PrintFiles(file_list)
   elif sys.argv[1] == "merge":
-    MergeAndPrint(sys.argv[2:])
+    MergeAndPrint(file_list)
   elif sys.argv[1] == "unpack":
-    Unpack(sys.argv[2:])
+    Unpack(file_list)
   elif sys.argv[1] == "rawunpack":
-    RawUnpack(sys.argv[2:])
+    RawUnpack(file_list)
   else:
     Usage()
diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
index 279f6fe..3252db7 100644
--- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
@@ -17,6 +17,7 @@
 #if SANITIZER_LINUX || SANITIZER_MAC
 # define SANITIZER_TEST_HAS_STAT_H 1
 # include <sys/stat.h>
+# include "sanitizer_common/sanitizer_posix.h"
 #else
 # define SANITIZER_TEST_HAS_STAT_H 0
 #endif
@@ -78,16 +79,14 @@
 
   char tmpfile[128];
   temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp.");
-  uptr openrv = OpenFile(tmpfile, WrOnly);
-  EXPECT_FALSE(internal_iserror(openrv));
-  fd_t fd = openrv;
+  fd_t fd = OpenFile(tmpfile, WrOnly);
+  ASSERT_NE(fd, kInvalidFd);
   EXPECT_EQ(len1, internal_write(fd, str1, len1));
   EXPECT_EQ(len2, internal_write(fd, str2, len2));
-  internal_close(fd);
+  CloseFile(fd);
 
-  openrv = OpenFile(tmpfile, RdOnly);
-  EXPECT_FALSE(internal_iserror(openrv));
-  fd = openrv;
+  fd = OpenFile(tmpfile, RdOnly);
+  ASSERT_NE(fd, kInvalidFd);
   uptr fsize = internal_filesize(fd);
   EXPECT_EQ(len1 + len2, fsize);
 
@@ -115,7 +114,7 @@
   internal_memset(buf, 0, len1);
   EXPECT_EQ(len2, internal_read(fd, buf, len2));
   EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
-  internal_close(fd);
+  CloseFile(fd);
   internal_unlink(tmpfile);
 }
 #endif
@@ -134,12 +133,11 @@
   char tmpfile[128];
   temp_file_name(tmpfile, sizeof(tmpfile),
                  "sanitizer_common.internalmmapwithoffset.tmp.");
-  uptr res = OpenFile(tmpfile, RdWr);
-  ASSERT_FALSE(internal_iserror(res));
-  fd_t fd = res;
+  fd_t fd = OpenFile(tmpfile, RdWr);
+  ASSERT_NE(fd, kInvalidFd);
 
   uptr page_size = GetPageSizeCached();
-  res = internal_ftruncate(fd, page_size * 2);
+  uptr res = internal_ftruncate(fd, page_size * 2);
   ASSERT_FALSE(internal_iserror(res));
 
   res = internal_lseek(fd, page_size, SEEK_SET);
@@ -154,8 +152,8 @@
   ASSERT_EQ('A', p[0]);
   ASSERT_EQ('B', p[1]);
 
-  internal_close(fd);
-  internal_munmap(p, page_size);
+  CloseFile(fd);
+  UnmapOrDie(p, page_size);
   internal_unlink(tmpfile);
 }
 #endif
diff --git a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
index abe4ef4..12bc9e1 100644
--- a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
@@ -37,8 +37,7 @@
   const char *binary_name = last_slash ? last_slash + 1 : argv0;
   MemoryMappingLayout memory_mapping(false);
   const uptr kMaxModules = 100;
-  LoadedModule *modules =
-      (LoadedModule *)malloc(kMaxModules * sizeof(LoadedModule));
+  LoadedModule modules[kMaxModules];
   uptr n_modules = memory_mapping.DumpListOfModules(modules, kMaxModules, 0);
   EXPECT_GT(n_modules, 0U);
   bool found = false;
@@ -51,7 +50,6 @@
     modules[i].clear();
   }
   EXPECT_TRUE(found);
-  free(modules);
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
index a8bd726..654ea1d 100644
--- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
@@ -45,7 +45,7 @@
 void FastUnwindTest::SetUp() {
   size_t ps = GetPageSize();
   mapping = MmapOrDie(2 * ps, "FastUnwindTest");
-  Mprotect((uptr)mapping, ps);
+  MprotectNoAccess((uptr)mapping, ps);
 
   // Unwinder may peek 1 word down from the starting FP.
   fake_stack = (uhwptr *)((uptr)mapping + ps + sizeof(uhwptr));