Merge "Remove known failures from arm ifunc tests"
diff --git a/libc/Android.bp b/libc/Android.bp
index 590fd28..b2ebe09 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1,6 +1,7 @@
 // Define the common source files for all the libc instances
 // =========================================================
 libc_common_src_files = [
+    "async_safe/async_safe_log.cpp",
     "bionic/ether_aton.c",
     "bionic/ether_ntoa.c",
     "bionic/fts.c",
@@ -58,7 +59,10 @@
     asflags: libc_common_flags,
     conlyflags: ["-std=gnu99"],
     cppflags: [],
-    include_dirs: ["external/jemalloc/include"],
+    include_dirs: [
+        "bionic/libc/async_safe/include",
+        "external/jemalloc/include",
+    ],
 
     stl: "none",
     system_shared_libs: [],
@@ -1346,7 +1350,6 @@
         "bionic/__libc_current_sigrtmax.cpp",
         "bionic/__libc_current_sigrtmin.cpp",
         "bionic/libc_init_common.cpp",
-        "bionic/libc_logging.cpp",
         "bionic/libgen.cpp",
         "bionic/link.cpp",
         "bionic/locale.cpp",
@@ -1705,7 +1708,7 @@
             "bionic/libc_init_static.cpp",
         ],
         cflags: ["-DLIBC_STATIC"],
-        whole_static_libs: ["libc_init_static", "libjemalloc"],
+        whole_static_libs: ["libc_init_static"],
     },
     shared: {
         srcs: [
@@ -1717,7 +1720,6 @@
             "bionic/NetdClient.cpp",
             "arch-common/bionic/crtend_so.S",
         ],
-        whole_static_libs: ["libjemalloc"],
     },
 
     required: ["tzdata"],
@@ -1740,7 +1742,7 @@
     // you wanted!
 
     shared_libs: ["libdl"],
-    whole_static_libs: ["libc_common"],
+    whole_static_libs: ["libc_common", "libjemalloc"],
 
     nocrt: true,
 
@@ -1793,19 +1795,6 @@
 }
 
 // ========================================================
-// libc_logging.a
-// ========================================================
-cc_library_static {
-    defaults: ["libc_defaults"],
-
-    srcs: [
-        "bionic/libc_logging.cpp",
-    ],
-
-    name: "libc_logging",
-}
-
-// ========================================================
 // libstdc++.so + libstdc++.a
 // ========================================================
 cc_library {
@@ -1818,9 +1807,7 @@
     ],
     name: "libstdc++",
     system_shared_libs: ["libc"],
-    shared: {
-        static_libs: ["libc_logging"],
-    },
+		static_libs: ["libasync_safe"],
 
     //TODO (dimitry): This is to work around b/24465209. Remove after root cause is fixed
     arch: {
diff --git a/libc/NOTICE b/libc/NOTICE
index 1c317a9..fcc3c85 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -1,5 +1,6 @@
-   Copyright (c) 2014, Linaro Limited
-   All rights reserved.
+   Copyright (c) 2014, ARM Limited
+   All rights Reserved.
+   Copyright (c) 2014, Linaro Ltd.
 
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
@@ -8,9 +9,9 @@
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in the
          documentation and/or other materials provided with the distribution.
-       * Neither the name of the Linaro nor the
-         names of its contributors may be used to endorse or promote products
-         derived from this software without specific prior written permission.
+       * Neither the name of the company nor the names of its contributors
+         may be used to endorse or promote products derived from this
+         software without specific prior written permission.
 
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -26,11 +27,8 @@
 
 -------------------------------------------------------------------
 
-   strchr - find a character in a string
-
-   Copyright (c) 2014, ARM Limited
-   All rights Reserved.
-   Copyright (c) 2014, Linaro Ltd.
+   Copyright (c) 2014, Linaro Limited
+   All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
@@ -39,9 +37,9 @@
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in the
          documentation and/or other materials provided with the distribution.
-       * Neither the name of the company nor the names of its contributors
-         may be used to endorse or promote products derived from this
-         software without specific prior written permission.
+       * Neither the name of the Linaro nor the
+         names of its contributors may be used to endorse or promote products
+         derived from this software without specific prior written permission.
 
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -6137,34 +6135,3 @@
 
 -------------------------------------------------------------------
 
-memchr - find a character in a memory zone
-
-Copyright (c) 2014, ARM Limited
-All rights Reserved.
-Copyright (c) 2014, Linaro Ltd.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
-    * Neither the name of the company nor the names of its contributors
-      may be used to endorse or promote products derived from this
-      software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
--------------------------------------------------------------------
-
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index f98cc61..936f3fd 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -143,7 +143,7 @@
 int ___fchmodat:fchmodat(int, const char*, mode_t)  all
 int fchownat(int, const char*, uid_t, gid_t, int)  all
 int fstatat64|fstatat:fstatat64(int, const char*, struct stat*, int)   arm,mips,x86
-int fstatat64|fstatat:newfstatat(int, const char*, struct stat*, int)  arm64,x86_64
+int fstatat64|fstatat:newfstatat(int, const char*, struct stat*, int)  arm64,mips64,x86_64
 int linkat(int, const char*, int, const char*, int)  all
 int mkdirat(int, const char*, mode_t)  all
 int mknodat(int, const char*, mode_t, dev_t)  all
@@ -187,7 +187,7 @@
 int __statfs:statfs(const char*, struct statfs*)  arm64,mips64,x86_64
 
 int     fstat64|fstat:fstat64(int, struct stat*)    arm,mips,x86
-int     fstat64|fstat:fstat(int, struct stat*)    arm64,x86_64
+int     fstat64|fstat:fstat(int, struct stat*)    arm64,mips64,x86_64
 
 # file system
 int     chdir(const char*)              all
@@ -343,7 +343,7 @@
 int     cacheflush:__ARM_NR_cacheflush(long start, long end, long flags)  arm
 
 # MIPS-specific
-int     _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips
+int     _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips,mips64
 int     __set_tls:set_thread_area(void*) mips,mips64
 
 # x86-specific
diff --git a/libc/arch-arm/bionic/atexit_legacy.c b/libc/arch-arm/bionic/atexit_legacy.c
index c0d704d..7254017 100644
--- a/libc/arch-arm/bionic/atexit_legacy.c
+++ b/libc/arch-arm/bionic/atexit_legacy.c
@@ -29,7 +29,7 @@
 #include <sys/types.h>
 #include <stdio.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 /*
  * This source file should only be included by libc.so, its purpose is
@@ -53,7 +53,7 @@
      */
     static char const warning[] = "WARNING: generic atexit() called from legacy shared library\n";
 
-    __libc_format_log(ANDROID_LOG_WARN, "libc", warning);
+    async_safe_format_log(ANDROID_LOG_WARN, "libc", warning);
     fprintf(stderr, warning);
 
     return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
diff --git a/libc/arch-arm64/generic/bionic/memchr.S b/libc/arch-arm64/generic/bionic/memchr.S
index a00dd8d..7b7e699 100644
--- a/libc/arch-arm64/generic/bionic/memchr.S
+++ b/libc/arch-arm64/generic/bionic/memchr.S
@@ -1,33 +1,32 @@
 /*
- * memchr - find a character in a memory zone
  *
- * Copyright (c) 2014, ARM Limited
- * All rights Reserved.
- * Copyright (c) 2014, Linaro Ltd.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the company nor the names of its contributors
- *       may be used to endorse or promote products derived from this
- *       software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+   Copyright (c) 2014, ARM Limited
+   All rights Reserved.
+   Copyright (c) 2014, Linaro Ltd.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the company nor the names of its contributors
+         may be used to endorse or promote products derived from this
+         software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
 
 /* Assumptions:
  *
diff --git a/libc/arch-arm64/generic/bionic/strchr.S b/libc/arch-arm64/generic/bionic/strchr.S
index b54106d..2db0c76 100644
--- a/libc/arch-arm64/generic/bionic/strchr.S
+++ b/libc/arch-arm64/generic/bionic/strchr.S
@@ -1,6 +1,5 @@
 /*
-   strchr - find a character in a string
-
+ *
    Copyright (c) 2014, ARM Limited
    All rights Reserved.
    Copyright (c) 2014, Linaro Ltd.
diff --git a/libc/arch-mips/bionic/cacheflush.cpp b/libc/arch-mips/bionic/cacheflush.cpp
index 98c0bd4..380ad90 100644
--- a/libc/arch-mips/bionic/cacheflush.cpp
+++ b/libc/arch-mips/bionic/cacheflush.cpp
@@ -29,7 +29,7 @@
 #include <unistd.h>
 #include <sys/cachectl.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 // Linux historically defines a cacheflush(3) routine for MIPS
 // with this signature:
@@ -50,7 +50,8 @@
     // It looks like this is really a MIPS-style cacheflush call.
     static bool warned = false;
     if (!warned) {
-      __libc_format_log(ANDROID_LOG_WARN, "libc", "cacheflush called with (start,len) instead of (start,end)");
+      async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                            "cacheflush called with (start,len) instead of (start,end)");
       warned = true;
     }
     end += start;
diff --git a/libc/arch-x86/bionic/__set_tls.cpp b/libc/arch-x86/bionic/__set_tls.cpp
index b26fd56..241d94a 100644
--- a/libc/arch-x86/bionic/__set_tls.cpp
+++ b/libc/arch-x86/bionic/__set_tls.cpp
@@ -32,9 +32,9 @@
 
 #include <asm/ldt.h>
 
-extern "C" int __set_thread_area(struct user_desc*);
+extern "C" int __set_thread_area(user_desc*);
 
-__LIBC_HIDDEN__ void __init_user_desc(struct user_desc* result, bool allocate, void* base_addr) {
+__LIBC_HIDDEN__ void __init_user_desc(user_desc* result, bool allocate, void* base_addr) {
   if (allocate) {
     // Let the kernel choose.
     result->entry_number = -1;
@@ -58,7 +58,7 @@
 }
 
 extern "C" __LIBC_HIDDEN__ int __set_tls(void* ptr) {
-  struct user_desc tls_descriptor;
+  user_desc tls_descriptor = {};
   __init_user_desc(&tls_descriptor, true, ptr);
 
   int rc = __set_thread_area(&tls_descriptor);
diff --git a/libc/async_safe/Android.bp b/libc/async_safe/Android.bp
new file mode 100644
index 0000000..9e36d97
--- /dev/null
+++ b/libc/async_safe/Android.bp
@@ -0,0 +1,15 @@
+// ========================================================
+// libasync_safe.a
+// ========================================================
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: [
+        "async_safe_log.cpp",
+    ],
+
+    name: "libasync_safe",
+
+    include_dirs: ["bionic/libc"],
+
+    export_include_dirs: ["include"],
+}
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
new file mode 100644
index 0000000..372f385
--- /dev/null
+++ b/libc/async_safe/async_safe_log.cpp
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <android/set_abort_message.h>
+#include <async_safe/log.h>
+
+#include "private/CachedProperty.h"
+#include "private/ScopedPthreadMutexLocker.h"
+
+// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
+enum AndroidEventLogType {
+  EVENT_TYPE_INT = 0,
+  EVENT_TYPE_LONG = 1,
+  EVENT_TYPE_STRING = 2,
+  EVENT_TYPE_LIST = 3,
+  EVENT_TYPE_FLOAT = 4,
+};
+
+struct BufferOutputStream {
+ public:
+  BufferOutputStream(char* buffer, size_t size) : total(0) {
+    buffer_ = buffer;
+    end_ = buffer + size - 1;
+    pos_ = buffer_;
+    pos_[0] = '\0';
+  }
+
+  ~BufferOutputStream() {}
+
+  void Send(const char* data, int len) {
+    if (len < 0) {
+      len = strlen(data);
+    }
+
+    total += len;
+
+    while (len > 0) {
+      int avail = end_ - pos_;
+      if (avail == 0) {
+        return;
+      }
+      if (avail > len) {
+        avail = len;
+      }
+      memcpy(pos_, data, avail);
+      pos_ += avail;
+      pos_[0] = '\0';
+      len -= avail;
+    }
+  }
+
+  size_t total;
+
+ private:
+  char* buffer_;
+  char* pos_;
+  char* end_;
+};
+
+struct FdOutputStream {
+ public:
+  explicit FdOutputStream(int fd) : total(0), fd_(fd) {}
+
+  void Send(const char* data, int len) {
+    if (len < 0) {
+      len = strlen(data);
+    }
+
+    total += len;
+
+    while (len > 0) {
+      int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
+      if (rc == -1) {
+        return;
+      }
+      data += rc;
+      len -= rc;
+    }
+  }
+
+  size_t total;
+
+ private:
+  int fd_;
+};
+
+/*** formatted output implementation
+ ***/
+
+/* Parse a decimal string from 'format + *ppos',
+ * return the value, and writes the new position past
+ * the decimal string in '*ppos' on exit.
+ *
+ * NOTE: Does *not* handle a sign prefix.
+ */
+static unsigned parse_decimal(const char* format, int* ppos) {
+  const char* p = format + *ppos;
+  unsigned result = 0;
+
+  for (;;) {
+    int ch = *p;
+    unsigned d = static_cast<unsigned>(ch - '0');
+
+    if (d >= 10U) {
+      break;
+    }
+
+    result = result * 10 + d;
+    p++;
+  }
+  *ppos = p - format;
+  return result;
+}
+
+// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes.
+// Assumes that buf_size > 0.
+static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) {
+  char* p = buf;
+  char* end = buf + buf_size - 1;
+
+  // Generate digit string in reverse order.
+  while (value) {
+    unsigned d = value % base;
+    value /= base;
+    if (p != end) {
+      char ch;
+      if (d < 10) {
+        ch = '0' + d;
+      } else {
+        ch = (caps ? 'A' : 'a') + (d - 10);
+      }
+      *p++ = ch;
+    }
+  }
+
+  // Special case for 0.
+  if (p == buf) {
+    if (p != end) {
+      *p++ = '0';
+    }
+  }
+  *p = '\0';
+
+  // Reverse digit string in-place.
+  size_t length = p - buf;
+  for (size_t i = 0, j = length - 1; i < j; ++i, --j) {
+    char ch = buf[i];
+    buf[i] = buf[j];
+    buf[j] = ch;
+  }
+}
+
+static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) {
+  // Decode the conversion specifier.
+  int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o');
+  int base = 10;
+  if (conversion == 'x' || conversion == 'X') {
+    base = 16;
+  } else if (conversion == 'o') {
+    base = 8;
+  }
+  bool caps = (conversion == 'X');
+
+  if (is_signed && static_cast<int64_t>(value) < 0) {
+    buf[0] = '-';
+    buf += 1;
+    buf_size -= 1;
+    value = static_cast<uint64_t>(-static_cast<int64_t>(value));
+  }
+  format_unsigned(buf, buf_size, value, base, caps);
+}
+
+template <typename Out>
+static void SendRepeat(Out& o, char ch, int count) {
+  char pad[8];
+  memset(pad, ch, sizeof(pad));
+
+  const int pad_size = static_cast<int>(sizeof(pad));
+  while (count > 0) {
+    int avail = count;
+    if (avail > pad_size) {
+      avail = pad_size;
+    }
+    o.Send(pad, avail);
+    count -= avail;
+  }
+}
+
+/* Perform formatted output to an output target 'o' */
+template <typename Out>
+static void out_vformat(Out& o, const char* format, va_list args) {
+  int nn = 0;
+
+  for (;;) {
+    int mm;
+    int padZero = 0;
+    int padLeft = 0;
+    char sign = '\0';
+    int width = -1;
+    int prec = -1;
+    size_t bytelen = sizeof(int);
+    int slen;
+    char buffer[32]; /* temporary buffer used to format numbers */
+
+    char c;
+
+    /* first, find all characters that are not 0 or '%' */
+    /* then send them to the output directly */
+    mm = nn;
+    do {
+      c = format[mm];
+      if (c == '\0' || c == '%') break;
+      mm++;
+    } while (1);
+
+    if (mm > nn) {
+      o.Send(format + nn, mm - nn);
+      nn = mm;
+    }
+
+    /* is this it ? then exit */
+    if (c == '\0') break;
+
+    /* nope, we are at a '%' modifier */
+    nn++;  // skip it
+
+    /* parse flags */
+    for (;;) {
+      c = format[nn++];
+      if (c == '\0') { /* single trailing '%' ? */
+        c = '%';
+        o.Send(&c, 1);
+        return;
+      } else if (c == '0') {
+        padZero = 1;
+        continue;
+      } else if (c == '-') {
+        padLeft = 1;
+        continue;
+      } else if (c == ' ' || c == '+') {
+        sign = c;
+        continue;
+      }
+      break;
+    }
+
+    /* parse field width */
+    if ((c >= '0' && c <= '9')) {
+      nn--;
+      width = static_cast<int>(parse_decimal(format, &nn));
+      c = format[nn++];
+    }
+
+    /* parse precision */
+    if (c == '.') {
+      prec = static_cast<int>(parse_decimal(format, &nn));
+      c = format[nn++];
+    }
+
+    /* length modifier */
+    switch (c) {
+      case 'h':
+        bytelen = sizeof(short);
+        if (format[nn] == 'h') {
+          bytelen = sizeof(char);
+          nn += 1;
+        }
+        c = format[nn++];
+        break;
+      case 'l':
+        bytelen = sizeof(long);
+        if (format[nn] == 'l') {
+          bytelen = sizeof(long long);
+          nn += 1;
+        }
+        c = format[nn++];
+        break;
+      case 'z':
+        bytelen = sizeof(size_t);
+        c = format[nn++];
+        break;
+      case 't':
+        bytelen = sizeof(ptrdiff_t);
+        c = format[nn++];
+        break;
+      default:;
+    }
+
+    /* conversion specifier */
+    const char* str = buffer;
+    if (c == 's') {
+      /* string */
+      str = va_arg(args, const char*);
+      if (str == NULL) {
+        str = "(null)";
+      }
+    } else if (c == 'c') {
+      /* character */
+      /* NOTE: char is promoted to int when passed through the stack */
+      buffer[0] = static_cast<char>(va_arg(args, int));
+      buffer[1] = '\0';
+    } else if (c == 'p') {
+      uint64_t value = reinterpret_cast<uintptr_t>(va_arg(args, void*));
+      buffer[0] = '0';
+      buffer[1] = 'x';
+      format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
+    } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
+      /* integers - first read value from stack */
+      uint64_t value;
+      int is_signed = (c == 'd' || c == 'i' || c == 'o');
+
+      /* NOTE: int8_t and int16_t are promoted to int when passed
+       *       through the stack
+       */
+      switch (bytelen) {
+        case 1:
+          value = static_cast<uint8_t>(va_arg(args, int));
+          break;
+        case 2:
+          value = static_cast<uint16_t>(va_arg(args, int));
+          break;
+        case 4:
+          value = va_arg(args, uint32_t);
+          break;
+        case 8:
+          value = va_arg(args, uint64_t);
+          break;
+        default:
+          return; /* should not happen */
+      }
+
+      /* sign extension, if needed */
+      if (is_signed) {
+        int shift = 64 - 8 * bytelen;
+        value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift);
+      }
+
+      /* format the number properly into our buffer */
+      format_integer(buffer, sizeof(buffer), value, c);
+    } else if (c == '%') {
+      buffer[0] = '%';
+      buffer[1] = '\0';
+    } else {
+      __assert(__FILE__, __LINE__, "conversion specifier unsupported");
+    }
+
+    /* if we are here, 'str' points to the content that must be
+     * outputted. handle padding and alignment now */
+
+    slen = strlen(str);
+
+    if (sign != '\0' || prec != -1) {
+      __assert(__FILE__, __LINE__, "sign/precision unsupported");
+    }
+
+    if (slen < width && !padLeft) {
+      char padChar = padZero ? '0' : ' ';
+      SendRepeat(o, padChar, width - slen);
+    }
+
+    o.Send(str, slen);
+
+    if (slen < width && padLeft) {
+      char padChar = padZero ? '0' : ' ';
+      SendRepeat(o, padChar, width - slen);
+    }
+  }
+}
+
+int async_safe_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
+  BufferOutputStream os(buffer, buffer_size);
+  va_list args;
+  va_start(args, format);
+  out_vformat(os, format, args);
+  va_end(args);
+  return os.total;
+}
+
+int async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format,
+                                     va_list args) {
+  BufferOutputStream os(buffer, buffer_size);
+  out_vformat(os, format, args);
+  return os.total;
+}
+
+int async_safe_format_fd(int fd, const char* format, ...) {
+  FdOutputStream os(fd);
+  va_list args;
+  va_start(args, format);
+  out_vformat(os, format, args);
+  va_end(args);
+  return os.total;
+}
+
+static int write_stderr(const char* tag, const char* msg) {
+  iovec vec[4];
+  vec[0].iov_base = const_cast<char*>(tag);
+  vec[0].iov_len = strlen(tag);
+  vec[1].iov_base = const_cast<char*>(": ");
+  vec[1].iov_len = 2;
+  vec[2].iov_base = const_cast<char*>(msg);
+  vec[2].iov_len = strlen(msg);
+  vec[3].iov_base = const_cast<char*>("\n");
+  vec[3].iov_len = 1;
+
+  int result = TEMP_FAILURE_RETRY(writev(STDERR_FILENO, vec, 4));
+  return result;
+}
+
+static int open_log_socket() {
+  // ToDo: Ideally we want this to fail if the gid of the current
+  // process is AID_LOGD, but will have to wait until we have
+  // registered this in private/android_filesystem_config.h. We have
+  // found that all logd crashes thus far have had no problem stuffing
+  // the UNIX domain socket and moving on so not critical *today*.
+
+  int log_fd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
+  if (log_fd == -1) {
+    return -1;
+  }
+
+  union {
+    struct sockaddr addr;
+    struct sockaddr_un addrUn;
+  } u;
+  memset(&u, 0, sizeof(u));
+  u.addrUn.sun_family = AF_UNIX;
+  strlcpy(u.addrUn.sun_path, "/dev/socket/logdw", sizeof(u.addrUn.sun_path));
+
+  if (TEMP_FAILURE_RETRY(connect(log_fd, &u.addr, sizeof(u.addrUn))) != 0) {
+    close(log_fd);
+    return -1;
+  }
+
+  return log_fd;
+}
+
+static clockid_t log_clockid() {
+  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+  ScopedPthreadMutexLocker locker(&mutex);
+
+  static CachedProperty ro_logd_timestamp("ro.logd.timestamp");
+  static CachedProperty persist_logd_timestamp("persist.logd.timestamp");
+
+  char ch = persist_logd_timestamp.Get()[0];
+  if (ch == '\0') ch = ro_logd_timestamp.Get()[0];
+
+  return (tolower(ch) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
+}
+
+struct log_time {  // Wire format
+  uint32_t tv_sec;
+  uint32_t tv_nsec;
+};
+
+int async_safe_write_log(int priority, const char* tag, const char* msg) {
+  int main_log_fd = open_log_socket();
+  if (main_log_fd == -1) {
+    // Try stderr instead.
+    return write_stderr(tag, msg);
+  }
+
+  iovec vec[6];
+  char log_id = (priority == ANDROID_LOG_FATAL) ? LOG_ID_CRASH : LOG_ID_MAIN;
+  vec[0].iov_base = &log_id;
+  vec[0].iov_len = sizeof(log_id);
+  uint16_t tid = gettid();
+  vec[1].iov_base = &tid;
+  vec[1].iov_len = sizeof(tid);
+  timespec ts;
+  clock_gettime(log_clockid(), &ts);
+  log_time realtime_ts;
+  realtime_ts.tv_sec = ts.tv_sec;
+  realtime_ts.tv_nsec = ts.tv_nsec;
+  vec[2].iov_base = &realtime_ts;
+  vec[2].iov_len = sizeof(realtime_ts);
+
+  vec[3].iov_base = &priority;
+  vec[3].iov_len = 1;
+  vec[4].iov_base = const_cast<char*>(tag);
+  vec[4].iov_len = strlen(tag) + 1;
+  vec[5].iov_base = const_cast<char*>(msg);
+  vec[5].iov_len = strlen(msg) + 1;
+
+  int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
+  close(main_log_fd);
+  return result;
+}
+
+int async_safe_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
+  char buffer[1024];
+  BufferOutputStream os(buffer, sizeof(buffer));
+  out_vformat(os, format, args);
+  return async_safe_write_log(priority, tag, buffer);
+}
+
+int async_safe_format_log(int priority, const char* tag, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  int result = async_safe_format_log_va_list(priority, tag, format, args);
+  va_end(args);
+  return result;
+}
+
+void async_safe_fatal_va_list(const char* prefix, const char* format, va_list args) {
+  char msg[1024];
+  BufferOutputStream os(msg, sizeof(msg));
+
+  if (prefix) {
+    os.Send(prefix, strlen(prefix));
+    os.Send(": ", 2);
+  }
+
+  out_vformat(os, format, args);
+
+  // Log to stderr for the benefit of "adb shell" users and gtests.
+  struct iovec iov[2] = {
+      {msg, os.total}, {const_cast<char*>("\n"), 1},
+  };
+  TEMP_FAILURE_RETRY(writev(2, iov, 2));
+
+  // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed).
+  async_safe_write_log(ANDROID_LOG_FATAL, "libc", msg);
+
+  android_set_abort_message(msg);
+}
+
+void async_safe_fatal(const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  async_safe_fatal_va_list(nullptr, fmt, args);
+  va_end(args);
+  abort();
+}
diff --git a/libc/private/libc_logging.h b/libc/async_safe/include/async_safe/log.h
similarity index 61%
rename from libc/private/libc_logging.h
rename to libc/async_safe/include/async_safe/log.h
index 73bc9a5..f93f672 100644
--- a/libc/private/libc_logging.h
+++ b/libc/async_safe/include/async_safe/log.h
@@ -26,14 +26,16 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LIBC_LOGGING_H
-#define _LIBC_LOGGING_H
+#ifndef _ASYNC_SAFE_LOG_LOG_H
+#define _ASYNC_SAFE_LOG_LOG_H
 
 #include <sys/cdefs.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdint.h>
 
+// These functions do not allocate memory to send data to the log.
+
 __BEGIN_DECLS
 
 enum {
@@ -63,10 +65,16 @@
 };
 
 // Formats a message to the log (priority 'fatal'), then aborts.
-__noreturn void __libc_fatal(const char* _Nonnull, ...) __printflike(1, 2);
+__noreturn void async_safe_fatal(const char* _Nonnull fmt, ...) __printflike(1, 2);
 
-// Formats a message to the log (priority 'fatal'), prefixed by "FORTIFY: ", then aborts.
-__noreturn void __fortify_fatal(const char* _Nonnull, ...) __printflike(1, 2);
+// This function does return, so callers that want to abort, must do so themselves.
+#if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+void async_safe_fatal_va_list(
+    const char* _Nullable prefix, const char* _Nonnull fmt, va_list);
+#else // defined(__mips__) || defined(__i386__)
+void async_safe_fatal_va_list(
+    const char* _Nullable prefix, const char* _Nonnull fmt, va_list _Nonnull);
+#endif
 
 //
 // Formatting routines for the C library's internal debugging.
@@ -74,29 +82,31 @@
 // These are async signal safe, so they can be called from signal handlers.
 //
 
-int __libc_format_buffer(char* _Nonnull buf, size_t size, const char* _Nonnull fmt, ...) __printflike(3, 4);
+int async_safe_format_buffer(char* _Nonnull buf, size_t size, const char* _Nonnull fmt, ...) __printflike(3, 4);
 
 #if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
-int __libc_format_buffer_va_list(char* _Nonnull buffer, size_t buffer_size,
-                                 const char* _Nonnull format, va_list args);
+int async_safe_format_buffer_va_list(
+    char* _Nonnull buffer, size_t buffer_size, const char* _Nonnull format, va_list args);
 #else // defined(__mips__) || defined(__i386__)
-int __libc_format_buffer_va_list(char* _Nonnull buffer, size_t buffer_size,
-                                 const char* _Nonnull format, va_list _Nonnull args);
+int async_safe_format_buffer_va_list(
+    char* _Nonnull buffer, size_t buffer_size, const char* _Nonnull format, va_list _Nonnull args);
 #endif
 
-int __libc_format_fd(int fd, const char* _Nonnull format , ...) __printflike(2, 3);
-int __libc_format_log(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, ...) __printflike(3, 4);
+int async_safe_format_fd(int fd, const char* _Nonnull format , ...) __printflike(2, 3);
+int async_safe_format_log(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, ...) __printflike(3, 4);
 #if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
-int __libc_format_log_va_list(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list ap);
+int async_safe_format_log_va_list(
+    int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list ap);
 #else // defined(__mips__) || defined(__i386__)
-int __libc_format_log_va_list(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list _Nonnull ap);
+int async_safe_format_log_va_list(
+    int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list _Nonnull ap);
 #endif
-int __libc_write_log(int pri, const char* _Nonnull tag, const char* _Nonnull msg);
+int async_safe_write_log(int pri, const char* _Nonnull tag, const char* _Nonnull msg);
 
 #define CHECK(predicate) \
   do { \
     if (!(predicate)) { \
-      __libc_fatal("%s:%d: %s CHECK '" #predicate "' failed", \
+      async_safe_fatal("%s:%d: %s CHECK '" #predicate "' failed", \
           __FILE__, __LINE__, __FUNCTION__); \
     } \
   } while(0)
diff --git a/libc/bionic/NetdClient.cpp b/libc/bionic/NetdClient.cpp
index b117d72..a1071d2 100644
--- a/libc/bionic/NetdClient.cpp
+++ b/libc/bionic/NetdClient.cpp
@@ -18,7 +18,8 @@
 #error NetdClient.cpp should NOT be included in static libc builds.
 #endif
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
+
 #include "private/NetdClientDispatch.h"
 
 #include <dlfcn.h>
@@ -53,6 +54,6 @@
 
 extern "C" __LIBC_HIDDEN__ void netdClientInit() {
     if (pthread_once(&netdClientInitOnce, netdClientInitImpl)) {
-        __libc_format_log(ANDROID_LOG_ERROR, "netdClient", "Failed to initialize netd_client");
+        async_safe_format_log(ANDROID_LOG_ERROR, "netdClient", "Failed to initialize netd_client");
     }
 }
diff --git a/libc/bionic/__cxa_pure_virtual.cpp b/libc/bionic/__cxa_pure_virtual.cpp
index 30b581f..00a4d90 100644
--- a/libc/bionic/__cxa_pure_virtual.cpp
+++ b/libc/bionic/__cxa_pure_virtual.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <private/libc_logging.h>
+#include <async_safe/log.h>
 
 extern "C" void __cxa_pure_virtual() {
-  __libc_fatal("Pure virtual function called. Are you calling virtual methods from a destructor?");
+  async_safe_fatal("Pure virtual function called. Are you calling virtual methods from a destructor?");
 }
diff --git a/libc/bionic/__stack_chk_fail.cpp b/libc/bionic/__stack_chk_fail.cpp
index cb039cf..5f5a5f6 100644
--- a/libc/bionic/__stack_chk_fail.cpp
+++ b/libc/bionic/__stack_chk_fail.cpp
@@ -28,9 +28,10 @@
 
 #include <stdlib.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_ssp.h"
-#include "private/libc_logging.h"
 
 void __stack_chk_fail() {
-  __libc_fatal("stack corruption detected (-fstack-protector)");
+  async_safe_fatal("stack corruption detected (-fstack-protector)");
 }
diff --git a/libc/bionic/abort.cpp b/libc/bionic/abort.cpp
index cf8fa8e..3ba83d1 100644
--- a/libc/bionic/abort.cpp
+++ b/libc/bionic/abort.cpp
@@ -29,9 +29,15 @@
 
 #include <signal.h>
 #include <stdlib.h>
+#include <sys/syscall.h>
 #include <unistd.h>
 
 void abort() {
+  // Protect ourselves against stale cached PID/TID values by fetching them via syscall.
+  // http://b/37769298
+  pid_t pid = syscall(__NR_getpid);
+  pid_t tid = syscall(__NR_gettid);
+
   // Don't block SIGABRT to give any signal handler a chance; we ignore
   // any errors -- X311J doesn't allow abort to return anyway.
   sigset_t mask;
@@ -39,7 +45,8 @@
   sigdelset(&mask, SIGABRT);
   sigprocmask(SIG_SETMASK, &mask, NULL);
 
-  tgkill(getpid(), gettid(), SIGABRT);
+  // Use tgkill directly instead of raise, to avoid inserting spurious stack frames.
+  tgkill(pid, tid, SIGABRT);
 
   // If SIGABRT ignored, or caught and the handler returns,
   // remove the SIGABRT signal handler and raise SIGABRT again.
@@ -50,7 +57,7 @@
   sigaction(SIGABRT, &sa, &sa);
   sigprocmask(SIG_SETMASK, &mask, NULL);
 
-  tgkill(getpid(), gettid(), SIGABRT);
+  tgkill(pid, tid, SIGABRT);
 
   // If we get this far, just exit.
   _exit(127);
diff --git a/libc/bionic/assert.cpp b/libc/bionic/assert.cpp
index 985fc38..41831cb 100644
--- a/libc/bionic/assert.cpp
+++ b/libc/bionic/assert.cpp
@@ -30,16 +30,16 @@
 
 #include <assert.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 void __assert(const char* file, int line, const char* failed_expression) {
-  __libc_fatal("%s:%d: assertion \"%s\" failed", file, line, failed_expression);
+  async_safe_fatal("%s:%d: assertion \"%s\" failed", file, line, failed_expression);
 }
 
 void __assert2(const char* file, int line, const char* function, const char* failed_expression) {
-  __libc_fatal("%s:%d: %s: assertion \"%s\" failed", file, line, function, failed_expression);
+  async_safe_fatal("%s:%d: %s: assertion \"%s\" failed", file, line, function, failed_expression);
 }
 
 extern "C" __LIBC_HIDDEN__ void longjmperror() {
-  __libc_fatal("longjmp botch");
+  async_safe_fatal("longjmp botch");
 }
diff --git a/libc/bionic/bionic_arc4random.cpp b/libc/bionic/bionic_arc4random.cpp
index ba3b4e1..a4842f6 100644
--- a/libc/bionic/bionic_arc4random.cpp
+++ b/libc/bionic/bionic_arc4random.cpp
@@ -35,8 +35,9 @@
 #include <syscall.h>
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 #include "private/KernelArgumentBlock.h"
-#include "private/libc_logging.h"
 
 bool __libc_arc4random_has_unlimited_entropy() {
   static bool have_urandom = access("/dev/urandom", R_OK) == 0;
@@ -53,8 +54,8 @@
 
   static size_t at_random_bytes_consumed = 0;
   if (at_random_bytes_consumed + n > 16) {
-    __libc_fatal("ran out of AT_RANDOM bytes, have %zu, requested %zu",
-                 16 - at_random_bytes_consumed, n);
+    async_safe_fatal("ran out of AT_RANDOM bytes, have %zu, requested %zu",
+                     16 - at_random_bytes_consumed, n);
   }
 
   memcpy(buf, reinterpret_cast<char*>(args.getauxval(AT_RANDOM)) + at_random_bytes_consumed, n);
diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp
index 5699f6e..970a92b 100644
--- a/libc/bionic/bionic_systrace.cpp
+++ b/libc/bionic/bionic_systrace.cpp
@@ -23,7 +23,6 @@
 #include "private/bionic_lock.h"
 #include "private/bionic_systrace.h"
 #include "private/CachedProperty.h"
-#include "private/libc_logging.h"
 
 #include <cutils/trace.h> // For ATRACE_TAG_BIONIC.
 
diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp
index 5d565c4..078a0b3 100644
--- a/libc/bionic/grp_pwd.cpp
+++ b/libc/bionic/grp_pwd.cpp
@@ -41,7 +41,6 @@
 #include "private/bionic_macros.h"
 #include "private/grp_pwd.h"
 #include "private/ErrnoRestorer.h"
-#include "private/libc_logging.h"
 
 // Generated android_ids array
 #include "generated_android_ids.h"
diff --git a/libc/bionic/icu.cpp b/libc/bionic/icu.cpp
index abc0eec..944a3f8 100644
--- a/libc/bionic/icu.cpp
+++ b/libc/bionic/icu.cpp
@@ -33,7 +33,7 @@
 #include <pthread.h>
 #include <stdlib.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 // Allowed icu4c version numbers are in the range [44, 999].
 // Gingerbread's icu4c 4.4 is the minimum supported ICU version.
@@ -68,7 +68,7 @@
   free(namelist);
 
   if (max_version == -1 || max_version < ICUDATA_VERSION_MIN) {
-    __libc_write_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find an ICU .dat file");
+    async_safe_write_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find an ICU .dat file");
     return false;
   }
 
@@ -76,7 +76,8 @@
 
   g_libicuuc_handle = dlopen("libicuuc.so", RTLD_LOCAL);
   if (g_libicuuc_handle == nullptr) {
-    __libc_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't open libicuuc.so: %s", dlerror());
+    async_safe_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't open libicuuc.so: %s",
+                          dlerror());
     return false;
   }
 
@@ -93,7 +94,8 @@
 
   void* symbol = dlsym(g_libicuuc_handle, versioned_symbol_name);
   if (symbol == nullptr) {
-    __libc_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find %s", versioned_symbol_name);
+    async_safe_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find %s",
+                          versioned_symbol_name);
   }
   return symbol;
 }
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 970a49c..e051762 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -41,12 +41,13 @@
 #include <sys/time.h>
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 #include "private/KernelArgumentBlock.h"
 #include "private/WriteProtected.h"
 #include "private/bionic_auxv.h"
 #include "private/bionic_globals.h"
 #include "private/bionic_tls.h"
-#include "private/libc_logging.h"
 #include "private/thread_private.h"
 #include "pthread_internal.h"
 
@@ -69,7 +70,9 @@
 __LIBC_HIDDEN__ void* __libc_sysinfo = reinterpret_cast<void*>(__libc_int0x80);
 
 __LIBC_HIDDEN__ void __libc_init_sysinfo(KernelArgumentBlock& args) {
-  __libc_sysinfo = reinterpret_cast<void*>(args.getauxval(AT_SYSINFO));
+  // Running under valgrind, AT_SYSINFO won't be set.
+  void* at_sysinfo = reinterpret_cast<void*>(args.getauxval(AT_SYSINFO));
+  if (at_sysinfo != nullptr) __libc_sysinfo = at_sysinfo;
 }
 
 // TODO: lose this function and just access __libc_sysinfo directly.
@@ -96,8 +99,8 @@
 #if !defined(__LP64__)
 static void __check_max_thread_id() {
   if (gettid() > 65535) {
-    __libc_fatal("Limited by the size of pthread_mutex_t, 32 bit bionic libc only accepts "
-                 "pid <= 65535, but current pid is %d", gettid());
+    async_safe_fatal("Limited by the size of pthread_mutex_t, 32 bit bionic libc only accepts "
+                     "pid <= 65535, but current pid is %d", gettid());
   }
 }
 #endif
@@ -303,11 +306,11 @@
 #if !defined(__LP64__)
   int old_value = personality(0xffffffff);
   if (old_value == -1) {
-    __libc_fatal("error getting old personality value: %s", strerror(errno));
+    async_safe_fatal("error getting old personality value: %s", strerror(errno));
   }
 
   if (personality((static_cast<unsigned int>(old_value) & ~PER_MASK) | PER_LINUX32) == -1) {
-    __libc_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
+    async_safe_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
   }
 #endif
 }
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
deleted file mode 100644
index 54664d9..0000000
--- a/libc/bionic/libc_logging.cpp
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-// Relative paths so we can #include this .cpp file for testing.
-#include "../private/CachedProperty.h"
-#include "../private/libc_logging.h"
-#include "../private/ScopedPthreadMutexLocker.h"
-
-#include <android/set_abort_message.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
-enum AndroidEventLogType {
-  EVENT_TYPE_INT      = 0,
-  EVENT_TYPE_LONG     = 1,
-  EVENT_TYPE_STRING   = 2,
-  EVENT_TYPE_LIST     = 3,
-  EVENT_TYPE_FLOAT    = 4,
-};
-
-struct BufferOutputStream {
- public:
-  BufferOutputStream(char* buffer, size_t size) : total(0) {
-    buffer_ = buffer;
-    end_ = buffer + size - 1;
-    pos_ = buffer_;
-    pos_[0] = '\0';
-  }
-
-  ~BufferOutputStream() {
-  }
-
-  void Send(const char* data, int len) {
-    if (len < 0) {
-      len = strlen(data);
-    }
-
-    total += len;
-
-    while (len > 0) {
-      int avail = end_ - pos_;
-      if (avail == 0) {
-        return;
-      }
-      if (avail > len) {
-        avail = len;
-      }
-      memcpy(pos_, data, avail);
-      pos_ += avail;
-      pos_[0] = '\0';
-      len -= avail;
-    }
-  }
-
-  size_t total;
-
- private:
-  char* buffer_;
-  char* pos_;
-  char* end_;
-};
-
-struct FdOutputStream {
- public:
-  explicit FdOutputStream(int fd) : total(0), fd_(fd) {
-  }
-
-  void Send(const char* data, int len) {
-    if (len < 0) {
-      len = strlen(data);
-    }
-
-    total += len;
-
-    while (len > 0) {
-      int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
-      if (rc == -1) {
-        return;
-      }
-      data += rc;
-      len -= rc;
-    }
-  }
-
-  size_t total;
-
- private:
-  int fd_;
-};
-
-/*** formatted output implementation
- ***/
-
-/* Parse a decimal string from 'format + *ppos',
- * return the value, and writes the new position past
- * the decimal string in '*ppos' on exit.
- *
- * NOTE: Does *not* handle a sign prefix.
- */
-static unsigned parse_decimal(const char *format, int *ppos) {
-    const char* p = format + *ppos;
-    unsigned result = 0;
-
-    for (;;) {
-        int ch = *p;
-        unsigned d = static_cast<unsigned>(ch - '0');
-
-        if (d >= 10U) {
-            break;
-        }
-
-        result = result*10 + d;
-        p++;
-    }
-    *ppos = p - format;
-    return result;
-}
-
-// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes.
-// Assumes that buf_size > 0.
-static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) {
-  char* p = buf;
-  char* end = buf + buf_size - 1;
-
-  // Generate digit string in reverse order.
-  while (value) {
-    unsigned d = value % base;
-    value /= base;
-    if (p != end) {
-      char ch;
-      if (d < 10) {
-        ch = '0' + d;
-      } else {
-        ch = (caps ? 'A' : 'a') + (d - 10);
-      }
-      *p++ = ch;
-    }
-  }
-
-  // Special case for 0.
-  if (p == buf) {
-    if (p != end) {
-      *p++ = '0';
-    }
-  }
-  *p = '\0';
-
-  // Reverse digit string in-place.
-  size_t length = p - buf;
-  for (size_t i = 0, j = length - 1; i < j; ++i, --j) {
-    char ch = buf[i];
-    buf[i] = buf[j];
-    buf[j] = ch;
-  }
-}
-
-static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) {
-  // Decode the conversion specifier.
-  int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o');
-  int base = 10;
-  if (conversion == 'x' || conversion == 'X') {
-    base = 16;
-  } else if (conversion == 'o') {
-    base = 8;
-  }
-  bool caps = (conversion == 'X');
-
-  if (is_signed && static_cast<int64_t>(value) < 0) {
-    buf[0] = '-';
-    buf += 1;
-    buf_size -= 1;
-    value = static_cast<uint64_t>(-static_cast<int64_t>(value));
-  }
-  format_unsigned(buf, buf_size, value, base, caps);
-}
-
-template <typename Out>
-static void SendRepeat(Out& o, char ch, int count) {
-  char pad[8];
-  memset(pad, ch, sizeof(pad));
-
-  const int pad_size = static_cast<int>(sizeof(pad));
-  while (count > 0) {
-    int avail = count;
-    if (avail > pad_size) {
-      avail = pad_size;
-    }
-    o.Send(pad, avail);
-    count -= avail;
-  }
-}
-
-/* Perform formatted output to an output target 'o' */
-template <typename Out>
-static void out_vformat(Out& o, const char* format, va_list args) {
-    int nn = 0;
-
-    for (;;) {
-        int mm;
-        int padZero = 0;
-        int padLeft = 0;
-        char sign = '\0';
-        int width = -1;
-        int prec  = -1;
-        size_t bytelen = sizeof(int);
-        int slen;
-        char buffer[32];  /* temporary buffer used to format numbers */
-
-        char  c;
-
-        /* first, find all characters that are not 0 or '%' */
-        /* then send them to the output directly */
-        mm = nn;
-        do {
-            c = format[mm];
-            if (c == '\0' || c == '%')
-                break;
-            mm++;
-        } while (1);
-
-        if (mm > nn) {
-            o.Send(format+nn, mm-nn);
-            nn = mm;
-        }
-
-        /* is this it ? then exit */
-        if (c == '\0')
-            break;
-
-        /* nope, we are at a '%' modifier */
-        nn++;  // skip it
-
-        /* parse flags */
-        for (;;) {
-            c = format[nn++];
-            if (c == '\0') {  /* single trailing '%' ? */
-                c = '%';
-                o.Send(&c, 1);
-                return;
-            }
-            else if (c == '0') {
-                padZero = 1;
-                continue;
-            }
-            else if (c == '-') {
-                padLeft = 1;
-                continue;
-            }
-            else if (c == ' ' || c == '+') {
-                sign = c;
-                continue;
-            }
-            break;
-        }
-
-        /* parse field width */
-        if ((c >= '0' && c <= '9')) {
-            nn --;
-            width = static_cast<int>(parse_decimal(format, &nn));
-            c = format[nn++];
-        }
-
-        /* parse precision */
-        if (c == '.') {
-            prec = static_cast<int>(parse_decimal(format, &nn));
-            c = format[nn++];
-        }
-
-        /* length modifier */
-        switch (c) {
-        case 'h':
-            bytelen = sizeof(short);
-            if (format[nn] == 'h') {
-                bytelen = sizeof(char);
-                nn += 1;
-            }
-            c = format[nn++];
-            break;
-        case 'l':
-            bytelen = sizeof(long);
-            if (format[nn] == 'l') {
-                bytelen = sizeof(long long);
-                nn += 1;
-            }
-            c = format[nn++];
-            break;
-        case 'z':
-            bytelen = sizeof(size_t);
-            c = format[nn++];
-            break;
-        case 't':
-            bytelen = sizeof(ptrdiff_t);
-            c = format[nn++];
-            break;
-        default:
-            ;
-        }
-
-        /* conversion specifier */
-        const char* str = buffer;
-        if (c == 's') {
-            /* string */
-            str = va_arg(args, const char*);
-            if (str == NULL) {
-                str = "(null)";
-            }
-        } else if (c == 'c') {
-            /* character */
-            /* NOTE: char is promoted to int when passed through the stack */
-            buffer[0] = static_cast<char>(va_arg(args, int));
-            buffer[1] = '\0';
-        } else if (c == 'p') {
-            uint64_t  value = reinterpret_cast<uintptr_t>(va_arg(args, void*));
-            buffer[0] = '0';
-            buffer[1] = 'x';
-            format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
-        } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
-            /* integers - first read value from stack */
-            uint64_t value;
-            int is_signed = (c == 'd' || c == 'i' || c == 'o');
-
-            /* NOTE: int8_t and int16_t are promoted to int when passed
-             *       through the stack
-             */
-            switch (bytelen) {
-            case 1: value = static_cast<uint8_t>(va_arg(args, int)); break;
-            case 2: value = static_cast<uint16_t>(va_arg(args, int)); break;
-            case 4: value = va_arg(args, uint32_t); break;
-            case 8: value = va_arg(args, uint64_t); break;
-            default: return;  /* should not happen */
-            }
-
-            /* sign extension, if needed */
-            if (is_signed) {
-                int shift = 64 - 8*bytelen;
-                value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift);
-            }
-
-            /* format the number properly into our buffer */
-            format_integer(buffer, sizeof(buffer), value, c);
-        } else if (c == '%') {
-            buffer[0] = '%';
-            buffer[1] = '\0';
-        } else {
-            __assert(__FILE__, __LINE__, "conversion specifier unsupported");
-        }
-
-        /* if we are here, 'str' points to the content that must be
-         * outputted. handle padding and alignment now */
-
-        slen = strlen(str);
-
-        if (sign != '\0' || prec != -1) {
-            __assert(__FILE__, __LINE__, "sign/precision unsupported");
-        }
-
-        if (slen < width && !padLeft) {
-            char padChar = padZero ? '0' : ' ';
-            SendRepeat(o, padChar, width - slen);
-        }
-
-        o.Send(str, slen);
-
-        if (slen < width && padLeft) {
-            char padChar = padZero ? '0' : ' ';
-            SendRepeat(o, padChar, width - slen);
-        }
-    }
-}
-
-int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
-  BufferOutputStream os(buffer, buffer_size);
-  va_list args;
-  va_start(args, format);
-  out_vformat(os, format, args);
-  va_end(args);
-  return os.total;
-}
-
-int __libc_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format,
-                                 va_list args) {
-  BufferOutputStream os(buffer, buffer_size);
-  out_vformat(os, format, args);
-  return os.total;
-}
-
-int __libc_format_fd(int fd, const char* format, ...) {
-  FdOutputStream os(fd);
-  va_list args;
-  va_start(args, format);
-  out_vformat(os, format, args);
-  va_end(args);
-  return os.total;
-}
-
-static int __libc_write_stderr(const char* tag, const char* msg) {
-  iovec vec[4];
-  vec[0].iov_base = const_cast<char*>(tag);
-  vec[0].iov_len = strlen(tag);
-  vec[1].iov_base = const_cast<char*>(": ");
-  vec[1].iov_len = 2;
-  vec[2].iov_base = const_cast<char*>(msg);
-  vec[2].iov_len = strlen(msg);
-  vec[3].iov_base = const_cast<char*>("\n");
-  vec[3].iov_len = 1;
-
-  int result = TEMP_FAILURE_RETRY(writev(STDERR_FILENO, vec, 4));
-  return result;
-}
-
-static int __libc_open_log_socket() {
-  // ToDo: Ideally we want this to fail if the gid of the current
-  // process is AID_LOGD, but will have to wait until we have
-  // registered this in private/android_filesystem_config.h. We have
-  // found that all logd crashes thus far have had no problem stuffing
-  // the UNIX domain socket and moving on so not critical *today*.
-
-  int log_fd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
-  if (log_fd == -1) {
-    return -1;
-  }
-
-  union {
-    struct sockaddr    addr;
-    struct sockaddr_un addrUn;
-  } u;
-  memset(&u, 0, sizeof(u));
-  u.addrUn.sun_family = AF_UNIX;
-  strlcpy(u.addrUn.sun_path, "/dev/socket/logdw", sizeof(u.addrUn.sun_path));
-
-  if (TEMP_FAILURE_RETRY(connect(log_fd, &u.addr, sizeof(u.addrUn))) != 0) {
-    close(log_fd);
-    return -1;
-  }
-
-  return log_fd;
-}
-
-static clockid_t __android_log_clockid() {
-  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-  ScopedPthreadMutexLocker locker(&mutex);
-
-  static CachedProperty ro_logd_timestamp("ro.logd.timestamp");
-  static CachedProperty persist_logd_timestamp("persist.logd.timestamp");
-
-  char ch = persist_logd_timestamp.Get()[0];
-  if (ch == '\0') ch = ro_logd_timestamp.Get()[0];
-
-  return (tolower(ch) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
-}
-
-struct log_time { // Wire format
-  uint32_t tv_sec;
-  uint32_t tv_nsec;
-};
-
-int __libc_write_log(int priority, const char* tag, const char* msg) {
-  int main_log_fd = __libc_open_log_socket();
-  if (main_log_fd == -1) {
-    // Try stderr instead.
-    return __libc_write_stderr(tag, msg);
-  }
-
-  iovec vec[6];
-  char log_id = (priority == ANDROID_LOG_FATAL) ? LOG_ID_CRASH : LOG_ID_MAIN;
-  vec[0].iov_base = &log_id;
-  vec[0].iov_len = sizeof(log_id);
-  uint16_t tid = gettid();
-  vec[1].iov_base = &tid;
-  vec[1].iov_len = sizeof(tid);
-  timespec ts;
-  clock_gettime(__android_log_clockid(), &ts);
-  log_time realtime_ts;
-  realtime_ts.tv_sec = ts.tv_sec;
-  realtime_ts.tv_nsec = ts.tv_nsec;
-  vec[2].iov_base = &realtime_ts;
-  vec[2].iov_len = sizeof(realtime_ts);
-
-  vec[3].iov_base = &priority;
-  vec[3].iov_len = 1;
-  vec[4].iov_base = const_cast<char*>(tag);
-  vec[4].iov_len = strlen(tag) + 1;
-  vec[5].iov_base = const_cast<char*>(msg);
-  vec[5].iov_len = strlen(msg) + 1;
-
-  int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
-  close(main_log_fd);
-  return result;
-}
-
-int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
-  char buffer[1024];
-  BufferOutputStream os(buffer, sizeof(buffer));
-  out_vformat(os, format, args);
-  return __libc_write_log(priority, tag, buffer);
-}
-
-int __libc_format_log(int priority, const char* tag, const char* format, ...) {
-  va_list args;
-  va_start(args, format);
-  int result = __libc_format_log_va_list(priority, tag, format, args);
-  va_end(args);
-  return result;
-}
-
-static void __libc_fatal_va_list(const char* prefix, const char* format, va_list args) {
-  char msg[1024];
-  BufferOutputStream os(msg, sizeof(msg));
-
-  if (prefix) {
-    os.Send(prefix, strlen(prefix));
-    os.Send(": ", 2);
-  }
-
-  out_vformat(os, format, args);
-
-  // Log to stderr for the benefit of "adb shell" users and gtests.
-  struct iovec iov[2] = {
-    { msg, os.total },
-    { const_cast<char*>("\n"), 1 },
-  };
-  TEMP_FAILURE_RETRY(writev(2, iov, 2));
-
-  // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed).
-  __libc_write_log(ANDROID_LOG_FATAL, "libc", msg);
-
-  android_set_abort_message(msg);
-}
-
-void __libc_fatal(const char* fmt, ...) {
-  va_list args;
-  va_start(args, fmt);
-  __libc_fatal_va_list(nullptr, fmt, args);
-  va_end(args);
-  abort();
-}
-
-void __fortify_fatal(const char* fmt, ...) {
-  va_list args;
-  va_start(args, fmt);
-  __libc_fatal_va_list("FORTIFY", fmt, args);
-  va_end(args);
-  abort();
-}
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 3fceb71..18c998d 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -167,7 +167,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <private/libc_logging.h>
+#include <async_safe/log.h>
 #include <sys/system_properties.h>
 
 extern "C" int __cxa_atexit(void (*func)(void *), void *arg, void *dso);
@@ -188,9 +188,9 @@
 // Log functions
 // =============================================================================
 #define error_log(format, ...)  \
-    __libc_format_log(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ )
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ )
 #define info_log(format, ...)  \
-    __libc_format_log(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ )
+    async_safe_format_log(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ )
 // =============================================================================
 
 // =============================================================================
diff --git a/libc/bionic/ndk_cruft.cpp b/libc/bionic/ndk_cruft.cpp
index 29565a2..016b476 100644
--- a/libc/bionic/ndk_cruft.cpp
+++ b/libc/bionic/ndk_cruft.cpp
@@ -46,7 +46,6 @@
 #include <wchar.h>
 
 #include "private/bionic_macros.h"
-#include "private/libc_logging.h"
 
 extern "C" {
 
diff --git a/libc/bionic/new.cpp b/libc/bionic/new.cpp
index 76c46ee..9499ff5 100644
--- a/libc/bionic/new.cpp
+++ b/libc/bionic/new.cpp
@@ -19,14 +19,14 @@
 #include <errno.h>
 #include <stdlib.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 const std::nothrow_t std::nothrow = {};
 
 void* operator new(std::size_t size) {
     void* p = malloc(size);
     if (p == NULL) {
-        __libc_fatal("new failed to allocate %zu bytes", size);
+        async_safe_fatal("new failed to allocate %zu bytes", size);
     }
     return p;
 }
@@ -34,7 +34,7 @@
 void* operator new[](std::size_t size) {
     void* p = malloc(size);
     if (p == NULL) {
-        __libc_fatal("new[] failed to allocate %zu bytes", size);
+        async_safe_fatal("new[] failed to allocate %zu bytes", size);
     }
     return p;
 }
diff --git a/libc/bionic/open.cpp b/libc/bionic/open.cpp
index 2daa21f..6d179c4 100644
--- a/libc/bionic/open.cpp
+++ b/libc/bionic/open.cpp
@@ -31,7 +31,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-#include "private/libc_logging.h"
+#include "private/bionic_fortify.h"
 
 extern "C" int __openat(int, const char*, int, int);
 
diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp
index cfa58fc..4b6a8f2 100644
--- a/libc/bionic/pthread_attr.cpp
+++ b/libc/bionic/pthread_attr.cpp
@@ -33,9 +33,10 @@
 #include <sys/resource.h>
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_string_utils.h"
 #include "private/ErrnoRestorer.h"
-#include "private/libc_logging.h"
 #include "pthread_internal.h"
 
 int pthread_attr_init(pthread_attr_t* attr) {
@@ -117,12 +118,12 @@
 static uintptr_t __get_main_stack_startstack() {
   FILE* fp = fopen("/proc/self/stat", "re");
   if (fp == nullptr) {
-    __libc_fatal("couldn't open /proc/self/stat: %s", strerror(errno));
+    async_safe_fatal("couldn't open /proc/self/stat: %s", strerror(errno));
   }
 
   char line[BUFSIZ];
   if (fgets(line, sizeof(line), fp) == nullptr) {
-    __libc_fatal("couldn't read /proc/self/stat: %s", strerror(errno));
+    async_safe_fatal("couldn't read /proc/self/stat: %s", strerror(errno));
   }
 
   fclose(fp);
@@ -138,7 +139,7 @@
              "%*u %*u %*u %*u %*u %*u %*u "
              "%*d %*d %*d %*d %*d %*d "
              "%*u %*u %*d %*u %*u %*u %" SCNuPTR, &startstack) != 1) {
-    __libc_fatal("couldn't parse /proc/self/stat");
+    async_safe_fatal("couldn't parse /proc/self/stat");
   }
 
   return startstack;
@@ -163,7 +164,7 @@
   // Hunt for the region that contains that address.
   FILE* fp = fopen("/proc/self/maps", "re");
   if (fp == nullptr) {
-    __libc_fatal("couldn't open /proc/self/maps");
+    async_safe_fatal("couldn't open /proc/self/maps");
   }
   char line[BUFSIZ];
   while (fgets(line, sizeof(line), fp) != NULL) {
@@ -177,7 +178,7 @@
       }
     }
   }
-  __libc_fatal("Stack not found in /proc/self/maps");
+  async_safe_fatal("Stack not found in /proc/self/maps");
 }
 
 int pthread_attr_getstack(const pthread_attr_t* attr, void** stack_base, size_t* stack_size) {
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index 6b3e148..9f4481f 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -35,11 +35,12 @@
 
 #include "pthread_internal.h"
 
+#include <async_safe/log.h>
+
 #include "private/bionic_macros.h"
 #include "private/bionic_prctl.h"
 #include "private/bionic_ssp.h"
 #include "private/bionic_tls.h"
-#include "private/libc_logging.h"
 #include "private/ErrnoRestorer.h"
 
 // x86 uses segment descriptors rather than a direct pointer to TLS.
@@ -60,13 +61,13 @@
   size_t allocation_size = BIONIC_TLS_SIZE + 2 * PAGE_SIZE;
   void* allocation = mmap(nullptr, allocation_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   if (allocation == MAP_FAILED) {
-    __libc_fatal("failed to allocate TLS");
+    async_safe_fatal("failed to allocate TLS");
   }
   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, allocation, allocation_size, "bionic TLS guard page");
 
   thread->bionic_tls = reinterpret_cast<bionic_tls*>(static_cast<char*>(allocation) + PAGE_SIZE);
   if (mprotect(thread->bionic_tls, BIONIC_TLS_SIZE, PROT_READ | PROT_WRITE) != 0) {
-    __libc_fatal("failed to mprotect TLS");
+    async_safe_fatal("failed to mprotect TLS");
   }
   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, thread->bionic_tls, BIONIC_TLS_SIZE, "bionic TLS");
 }
@@ -118,8 +119,8 @@
       // For backwards compatibility reasons, we only report failures on 64-bit devices.
       error = errno;
 #endif
-      __libc_format_log(ANDROID_LOG_WARN, "libc",
-                        "pthread_create sched_setscheduler call failed: %s", strerror(errno));
+      async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                            "pthread_create sched_setscheduler call failed: %s", strerror(errno));
     }
   }
 
@@ -134,7 +135,7 @@
   int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
   void* space = mmap(NULL, mmap_size, prot, flags, -1, 0);
   if (space == MAP_FAILED) {
-    __libc_format_log(ANDROID_LOG_WARN,
+    async_safe_format_log(ANDROID_LOG_WARN,
                       "libc",
                       "pthread_create failed: couldn't allocate %zu-bytes mapped space: %s",
                       mmap_size, strerror(errno));
@@ -144,9 +145,9 @@
   // Stack is at the lower end of mapped space, stack guard region is at the lower end of stack.
   // Set the stack guard region to PROT_NONE, so we can detect thread stack overflow.
   if (mprotect(space, stack_guard_size, PROT_NONE) == -1) {
-    __libc_format_log(ANDROID_LOG_WARN, "libc",
-                      "pthread_create failed: couldn't mprotect PROT_NONE %zu-byte stack guard region: %s",
-                      stack_guard_size, strerror(errno));
+    async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                          "pthread_create failed: couldn't mprotect PROT_NONE %zu-byte stack guard region: %s",
+                          stack_guard_size, strerror(errno));
     munmap(space, mmap_size);
     return NULL;
   }
@@ -281,7 +282,8 @@
     if (thread->mmap_size != 0) {
       munmap(thread->attr.stack_base, thread->mmap_size);
     }
-    __libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s", strerror(errno));
+    async_safe_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s",
+                          strerror(errno));
     return clone_errno;
   }
 
diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp
index 5819bc1..abd403b 100644
--- a/libc/bionic/pthread_internal.cpp
+++ b/libc/bionic/pthread_internal.cpp
@@ -33,10 +33,11 @@
 #include <string.h>
 #include <sys/mman.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_futex.h"
 #include "private/bionic_sdk_version.h"
 #include "private/bionic_tls.h"
-#include "private/libc_logging.h"
 
 static pthread_internal_t* g_thread_list = nullptr;
 static pthread_rwlock_t g_thread_list_lock = PTHREAD_RWLOCK_INITIALIZER;
@@ -116,9 +117,9 @@
       // addresses might sometimes contain threads or things that look enough like
       // threads for us to do some real damage by continuing.
       // TODO: try getting rid of this when Treble lets us keep vendor blobs on an old API level.
-      __libc_format_log(ANDROID_LOG_WARN, "libc", "invalid pthread_t (0) passed to libc");
+      async_safe_format_log(ANDROID_LOG_WARN, "libc", "invalid pthread_t (0) passed to libc");
     } else {
-      __libc_fatal("invalid pthread_t %p passed to libc", thread);
+      async_safe_fatal("invalid pthread_t %p passed to libc", thread);
     }
   }
   return nullptr;
diff --git a/libc/bionic/raise.cpp b/libc/bionic/raise.cpp
index b134b5a..1f204d4 100644
--- a/libc/bionic/raise.cpp
+++ b/libc/bionic/raise.cpp
@@ -27,14 +27,14 @@
  */
 
 #include <errno.h>
-#include <pthread.h>
 #include <signal.h>
+#include <unistd.h>
+#include <sys/syscall.h>
 
 int raise(int sig) {
-  int rc = pthread_kill(pthread_self(), sig);
-  if (rc != 0) {
-    errno = rc;
-    return -1;
-  }
-  return 0;
+  // Protect ourselves against stale cached PID/TID values by fetching them via syscall.
+  // http://b/37769298
+  pid_t pid = syscall(__NR_getpid);
+  pid_t tid = syscall(__NR_gettid);
+  return tgkill(pid, tid, sig);
 }
diff --git a/libc/bionic/setjmp_cookie.cpp b/libc/bionic/setjmp_cookie.cpp
index 4fa68c2..41a439f 100644
--- a/libc/bionic/setjmp_cookie.cpp
+++ b/libc/bionic/setjmp_cookie.cpp
@@ -34,9 +34,10 @@
 #include <sys/auxv.h>
 #include <sys/cdefs.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_arc4random.h"
 #include "private/bionic_globals.h"
-#include "private/libc_logging.h"
 #include "private/KernelArgumentBlock.h"
 
 void __libc_init_setjmp_cookie(libc_globals* globals, KernelArgumentBlock& args) {
@@ -49,7 +50,7 @@
 
 extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_get(long sigflag) {
   if (sigflag & ~1) {
-    __libc_fatal("unexpected sigflag value: %ld", sigflag);
+    async_safe_fatal("unexpected sigflag value: %ld", sigflag);
   }
 
   return __libc_globals->setjmp_cookie | sigflag;
@@ -58,12 +59,12 @@
 // Aborts if cookie doesn't match, returns the signal flag otherwise.
 extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_check(long cookie) {
   if (__libc_globals->setjmp_cookie != (cookie & ~1)) {
-    __libc_fatal("setjmp cookie mismatch");
+    async_safe_fatal("setjmp cookie mismatch");
   }
 
   return cookie & 1;
 }
 
 extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_checksum_mismatch() {
-  __libc_fatal("setjmp checksum mismatch");
+  async_safe_fatal("setjmp checksum mismatch");
 }
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
index a0a0809..dad3fb3 100644
--- a/libc/bionic/strerror_r.cpp
+++ b/libc/bionic/strerror_r.cpp
@@ -12,8 +12,9 @@
 #include <signal.h>
 #include <stdio.h>
 
+#include <async_safe/log.h>
+
 #include "private/ErrnoRestorer.h"
-#include "private/libc_logging.h"
 
 struct Pair {
   int code;
@@ -57,7 +58,7 @@
   if (error_name != NULL) {
     length = strlcpy(buf, error_name, buf_len);
   } else {
-    length = __libc_format_buffer(buf, buf_len, "Unknown error %d", error_number);
+    length = async_safe_format_buffer(buf, buf_len, "Unknown error %d", error_number);
   }
   if (length >= buf_len) {
     errno_restorer.override(ERANGE);
diff --git a/libc/bionic/syslog.cpp b/libc/bionic/syslog.cpp
index 8e3f34f..9424573 100644
--- a/libc/bionic/syslog.cpp
+++ b/libc/bionic/syslog.cpp
@@ -19,7 +19,7 @@
 #include <string.h>
 #include <syslog.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 static const char* syslog_log_tag = NULL;
 static int syslog_priority_mask = 0xff;
@@ -109,7 +109,7 @@
     *dst = '\0';
   }
 
-  // We can't let __libc_format_log do the formatting because it doesn't support
+  // We can't let async_safe_format_log do the formatting because it doesn't support
   // all the printf functionality.
   char log_line[1024];
   vsnprintf(log_line, sizeof(log_line), log_fmt, args);
@@ -118,5 +118,5 @@
     free(const_cast<char*>(log_fmt));
   }
 
-  __libc_format_log(android_log_priority, log_tag, "%s", log_line);
+  async_safe_format_log(android_log_priority, log_tag, "%s", log_line);
 }
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index 9fb03ac..a958699 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -54,12 +54,13 @@
 #include <sys/_system_properties.h>
 #include <sys/system_properties.h>
 
+#include <async_safe/log.h>
+
 #include "private/ErrnoRestorer.h"
 #include "private/bionic_futex.h"
 #include "private/bionic_lock.h"
 #include "private/bionic_macros.h"
 #include "private/bionic_sdk_version.h"
-#include "private/libc_logging.h"
 
 static constexpr int PROP_FILENAME_MAX = 1024;
 
@@ -227,8 +228,8 @@
 
   if (context) {
     if (fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) {
-      __libc_format_log(ANDROID_LOG_ERROR, "libc",
-                        "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
+      async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+                            "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
       /*
        * fsetxattr() will fail during system properties tests due to selinux policy.
        * We do not want to create a custom policy for the tester, so we will continue in
@@ -640,9 +641,9 @@
       // ms so callers who do read-after-write can reliably see
       // what they've written.  Most of the time.
       // TODO: fix the system properties design.
-      __libc_format_log(ANDROID_LOG_WARN, "libc",
-                        "Property service has timed out while trying to set \"%s\" to \"%s\"",
-                        msg->name, msg->value);
+      async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                            "Property service has timed out while trying to set \"%s\" to \"%s\"",
+                            msg->name, msg->value);
       result = 0;
     }
   }
@@ -806,7 +807,8 @@
   }
 
   char filename[PROP_FILENAME_MAX];
-  int len = __libc_format_buffer(filename, sizeof(filename), "%s/%s", property_filename, context_);
+  int len = async_safe_format_buffer(filename, sizeof(filename), "%s/%s", property_filename,
+                                     context_);
   if (len < 0 || len > PROP_FILENAME_MAX) {
     lock_.unlock();
     return false;
@@ -841,7 +843,8 @@
 
 bool context_node::check_access() {
   char filename[PROP_FILENAME_MAX];
-  int len = __libc_format_buffer(filename, sizeof(filename), "%s/%s", property_filename, context_);
+  int len = async_safe_format_buffer(filename, sizeof(filename), "%s/%s", property_filename,
+                                     context_);
   if (len < 0 || len > PROP_FILENAME_MAX) {
     return false;
   }
@@ -864,7 +867,8 @@
 static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
   char filename[PROP_FILENAME_MAX];
   int len =
-      __libc_format_buffer(filename, sizeof(filename), "%s/properties_serial", property_filename);
+      async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial",
+                               property_filename);
   if (len < 0 || len > PROP_FILENAME_MAX) {
     __system_property_area__ = nullptr;
     return false;
@@ -1152,7 +1156,7 @@
 
   prop_area* pa = get_prop_area_for_name(name);
   if (!pa) {
-    __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
     return nullptr;
   }
 
@@ -1184,11 +1188,11 @@
       if (name != nullptr) {
         size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
         if (namelen >= PROP_NAME_MAX) {
-          __libc_format_log(ANDROID_LOG_ERROR, "libc",
-                            "The property name length for \"%s\" is >= %d;"
-                            " please use __system_property_read_callback"
-                            " to read this property. (the name is truncated to \"%s\")",
-                            pi->name, PROP_NAME_MAX - 1, name);
+          async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+                                "The property name length for \"%s\" is >= %d;"
+                                " please use __system_property_read_callback"
+                                " to read this property. (the name is truncated to \"%s\")",
+                                pi->name, PROP_NAME_MAX - 1, name);
         }
       }
       return len;
@@ -1239,17 +1243,17 @@
   char value[PROP_VALUE_MAX];
   if (__system_property_get(kServiceVersionPropertyName, value) == 0) {
     g_propservice_protocol_version = kProtocolVersion1;
-    __libc_format_log(ANDROID_LOG_WARN, "libc",
-                      "Using old property service protocol (\"%s\" is not set)",
-                      kServiceVersionPropertyName);
+    async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                          "Using old property service protocol (\"%s\" is not set)",
+                          kServiceVersionPropertyName);
   } else {
     uint32_t version = static_cast<uint32_t>(atoll(value));
     if (version >= kProtocolVersion2) {
       g_propservice_protocol_version = kProtocolVersion2;
     } else {
-      __libc_format_log(ANDROID_LOG_WARN, "libc",
-                        "Using old property service protocol (\"%s\"=\"%s\")",
-                        kServiceVersionPropertyName, value);
+      async_safe_format_log(ANDROID_LOG_WARN, "libc",
+                            "Using old property service protocol (\"%s\"=\"%s\")",
+                            kServiceVersionPropertyName, value);
       g_propservice_protocol_version = kProtocolVersion1;
     }
   }
@@ -1280,49 +1284,49 @@
     PropertyServiceConnection connection;
     if (!connection.IsValid()) {
       errno = connection.GetLastError();
-      __libc_format_log(ANDROID_LOG_WARN,
-                        "libc",
-                        "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)",
-                        key,
-                        value,
-                        errno,
-                        strerror(errno));
+      async_safe_format_log(ANDROID_LOG_WARN,
+                            "libc",
+                            "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)",
+                            key,
+                            value,
+                            errno,
+                            strerror(errno));
       return -1;
     }
 
     SocketWriter writer(&connection);
     if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
       errno = connection.GetLastError();
-      __libc_format_log(ANDROID_LOG_WARN,
-                        "libc",
-                        "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
-                        key,
-                        value,
-                        errno,
-                        strerror(errno));
+      async_safe_format_log(ANDROID_LOG_WARN,
+                            "libc",
+                            "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
+                            key,
+                            value,
+                            errno,
+                            strerror(errno));
       return -1;
     }
 
     int result = -1;
     if (!connection.RecvInt32(&result)) {
       errno = connection.GetLastError();
-      __libc_format_log(ANDROID_LOG_WARN,
-                        "libc",
-                        "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
-                        key,
-                        value,
-                        errno,
-                        strerror(errno));
+      async_safe_format_log(ANDROID_LOG_WARN,
+                            "libc",
+                            "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
+                            key,
+                            value,
+                            errno,
+                            strerror(errno));
       return -1;
     }
 
     if (result != PROP_SUCCESS) {
-      __libc_format_log(ANDROID_LOG_WARN,
-                        "libc",
-                        "Unable to set property \"%s\" to \"%s\": error code: 0x%x",
-                        key,
-                        value,
-                        result);
+      async_safe_format_log(ANDROID_LOG_WARN,
+                            "libc",
+                            "Unable to set property \"%s\" to \"%s\": error code: 0x%x",
+                            key,
+                            value,
+                            result);
       return -1;
     }
 
@@ -1377,7 +1381,7 @@
   prop_area* pa = get_prop_area_for_name(name);
 
   if (!pa) {
-    __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
     return -1;
   }
 
diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index 82e0ddf..9c65570 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -47,7 +47,7 @@
 #include "resolv_netid.h"
 #include "res_private.h"
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 /* This code implements a small and *simple* DNS resolver cache.
  *
@@ -155,7 +155,7 @@
 
 #define XLOG(...) ({ \
     if (DEBUG) { \
-        __libc_format_log(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__); \
+        async_safe_format_log(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__); \
     } else { \
         ((void)0); \
     } \
diff --git a/libc/dns/resolv/res_send.c b/libc/dns/resolv/res_send.c
index f53da5f..586bb8f 100644
--- a/libc/dns/resolv/res_send.c
+++ b/libc/dns/resolv/res_send.c
@@ -114,7 +114,7 @@
 
 #include <resolv_cache.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 #ifndef DE_CONST
 #define DE_CONST(c,v)   v = ((c) ? \
@@ -564,7 +564,7 @@
 			}
 
 			if (DBG) {
-				__libc_format_log(ANDROID_LOG_DEBUG, "libc",
+				async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
 					"used send_vc %d\n", n);
 			}
 
@@ -576,7 +576,7 @@
 		} else {
 			/* Use datagrams. */
 			if (DBG) {
-				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using send_dg\n");
+				async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "using send_dg\n");
 			}
 
 			n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
@@ -591,7 +591,7 @@
 			}
 
 			if (DBG) {
-				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "used send_dg %d\n",n);
+				async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "used send_dg %d\n",n);
 			}
 
 			if (n < 0)
@@ -599,7 +599,7 @@
 			if (n == 0)
 				goto next_ns;
 			if (DBG) {
-				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "time=%ld\n",
+				async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "time=%ld\n",
 						  time(NULL));
 			}
 			if (v_circuit)
@@ -739,7 +739,7 @@
 		timeout = 1;
 	}
 	if (DBG) {
-		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using timeout of %d sec\n", timeout);
+		async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "using timeout of %d sec\n", timeout);
 	}
 
 	return timeout;
@@ -764,7 +764,7 @@
 	void *tmp;
 
 	if (DBG) {
-		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using send_vc\n");
+		async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "using send_vc\n");
 	}
 
 	nsap = get_nsaddr(statp, (size_t)ns);
@@ -993,7 +993,7 @@
 		timeout = evConsTime((long)sec, 0L);
 		finish = evAddTime(now, timeout);
 		if (DBG) {
-			__libc_format_log(ANDROID_LOG_DEBUG, "libc", "  %d send_vc\n", sock);
+			async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "  %d send_vc\n", sock);
 		}
 
 		res = retrying_select(sock, &rset, &wset, &finish);
@@ -1004,7 +1004,7 @@
 done:
 	fcntl(sock, F_SETFL, origflags);
 	if (DBG) {
-		__libc_format_log(ANDROID_LOG_DEBUG, "libc",
+		async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
 			"  %d connect_with_timeout returning %d\n", sock, res);
 	}
 	return res;
@@ -1020,7 +1020,7 @@
 
 retry:
 	if (DBG) {
-		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "  %d retrying_select\n", sock);
+		async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "  %d retrying_select\n", sock);
 	}
 
 	now = evNowTime();
@@ -1040,7 +1040,7 @@
 	n = pselect(sock + 1, readset, writeset, NULL, &timeout, NULL);
 	if (n == 0) {
 		if (DBG) {
-			__libc_format_log(ANDROID_LOG_DEBUG, " libc",
+			async_safe_format_log(ANDROID_LOG_DEBUG, " libc",
 				"  %d retrying_select timeout\n", sock);
 		}
 		errno = ETIMEDOUT;
@@ -1050,7 +1050,7 @@
 		if (errno == EINTR)
 			goto retry;
 		if (DBG) {
-			__libc_format_log(ANDROID_LOG_DEBUG, "libc",
+			async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
 				"  %d retrying_select got error %d\n",sock, n);
 		}
 		return n;
@@ -1060,7 +1060,7 @@
 		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) {
 			errno = error;
 			if (DBG) {
-				__libc_format_log(ANDROID_LOG_DEBUG, "libc",
+				async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
 					"  %d retrying_select dot error2 %d\n", sock, errno);
 			}
 
@@ -1068,7 +1068,7 @@
 		}
 	}
 	if (DBG) {
-		__libc_format_log(ANDROID_LOG_DEBUG, "libc",
+		async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
 			"  %d retrying_select returning %d\n",sock, n);
 	}
 
diff --git a/libc/dns/resolv/res_state.c b/libc/dns/resolv/res_state.c
index 4ed168c..94124ff 100644
--- a/libc/dns/resolv/res_state.c
+++ b/libc/dns/resolv/res_state.c
@@ -41,9 +41,9 @@
 #define DEBUG 0
 
 #if DEBUG
-#  include "private/libc_logging.h"
+#  include <async_safe/log.h>
 #  include <unistd.h>  /* for gettid() */
-#  define D(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__)
+#  define D(...) async_safe_format_log(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__)
 #else
 #  define D(...)  do{}while(0)
 #endif
diff --git a/libc/dns/resolv/res_stats.c b/libc/dns/resolv/res_stats.c
index 99c79e4..97d54d2 100644
--- a/libc/dns/resolv/res_stats.c
+++ b/libc/dns/resolv/res_stats.c
@@ -18,9 +18,10 @@
 #include <arpa/nameser.h>
 #include <string.h>
 
-#include "resolv_stats.h"
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
+
 #include "isc/eventlib.h"
+#include "resolv_stats.h"
 
 #define DBG 0
 
@@ -38,7 +39,7 @@
 _res_stats_set_sample(struct __res_sample* sample, time_t now, int rcode, int rtt)
 {
     if (DBG) {
-        __libc_format_log(ANDROID_LOG_INFO, "libc", "rcode = %d, sec = %d", rcode, rtt);
+        async_safe_format_log(ANDROID_LOG_INFO, "libc", "rcode = %d, sec = %d", rcode, rtt);
     }
     sample->at = now;
     sample->rcode = rcode;
@@ -128,14 +129,15 @@
     if (successes >= 0 && errors >= 0 && timeouts >= 0) {
         int total = successes + errors + timeouts;
         if (DBG) {
-            __libc_format_log(ANDROID_LOG_DEBUG, "libc", "NS stats: S %d + E %d + T %d + I %d "
+            async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "NS stats: S %d + E %d + T %d + I %d "
                  "= %d, rtt = %d, min_samples = %d\n", successes, errors, timeouts, internal_errors,
                  total, rtt_avg, params->min_samples);
         }
         if (total >= params->min_samples && (errors > 0 || timeouts > 0)) {
             int success_rate = successes * 100 / total;
             if (DBG) {
-                __libc_format_log(ANDROID_LOG_DEBUG, "libc", "success rate %d%%\n", success_rate);
+                async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "success rate %d%%\n",
+                                      success_rate);
             }
             if (success_rate < params->success_threshold) {
                 // evNowTime() is used here instead of time() to stay consistent with the rest of
@@ -146,13 +148,13 @@
                     // date has been reached, however the code for returning the ring buffer to its
                     // previous non-circular state would induce additional complexity.
                     if (DBG) {
-                        __libc_format_log(ANDROID_LOG_INFO, "libc",
+                        async_safe_format_log(ANDROID_LOG_INFO, "libc",
                             "samples stale, retrying server\n");
                     }
                     _res_stats_clear_samples(stats);
                 } else {
                     if (DBG) {
-                        __libc_format_log(ANDROID_LOG_INFO, "libc",
+                        async_safe_format_log(ANDROID_LOG_INFO, "libc",
                             "too many resolution errors, ignoring server\n");
                     }
                     return 0;
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index 708c101..b071b90 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -13,9 +13,10 @@
 
     stl: "libc++_static",
 
-    static_libs: ["libc_logging"],
+    whole_static_libs: ["libasync_safe"],
 
     include_dirs: ["bionic/libc"],
+
     export_include_dirs: ["."],
 
     sanitize: {
@@ -29,7 +30,6 @@
         "-Werror",
         "-Wno-error=format-zero-length",
     ],
-
 }
 
 // ==============================================================
@@ -61,9 +61,9 @@
     },
 
     static_libs: [
+        "libasync_safe",
         "libbase",
         "libc_malloc_debug_backtrace",
-        "libc_logging",
     ],
 
     multilib: {
@@ -89,7 +89,6 @@
         "-fno-stack-protector",
         "-Wno-error=format-zero-length",
     ],
-
 }
 
 // ==============================================================
@@ -118,7 +117,7 @@
     whole_static_libs: ["libc_malloc_debug"],
 
     local_include_dirs: ["tests"],
-    include_dirs: ["bionic/libc"],
+    include_dirs: ["bionic/libc", "bionic/libc/async_safe/include"],
 
     shared_libs: ["libbase"],
 
@@ -127,5 +126,4 @@
         "-Werror",
         "-Wno-error=format-zero-length",
     ],
-
 }
diff --git a/libc/malloc_debug/backtrace.cpp b/libc/malloc_debug/backtrace.cpp
index 75a255c..88f5a1d 100644
--- a/libc/malloc_debug/backtrace.cpp
+++ b/libc/malloc_debug/backtrace.cpp
@@ -158,13 +158,13 @@
       char* demangled_symbol = __cxa_demangle(symbol, nullptr, nullptr, nullptr);
       const char* best_name = (demangled_symbol != nullptr) ? demangled_symbol : symbol;
 
-      __libc_format_buffer(buf, sizeof(buf),
-          "          #%02zd  pc %" PAD_PTR "  %s (%s+%" PRIuPTR ")\n", frame_num,
+      async_safe_format_buffer(
+          buf, sizeof(buf), "          #%02zd  pc %" PAD_PTR "  %s (%s+%" PRIuPTR ")\n", frame_num,
           rel_pc, soname, best_name, frames[frame_num] - offset);
       free(demangled_symbol);
     } else {
-      __libc_format_buffer(buf, sizeof(buf),
-          "          #%02zd  pc %" PAD_PTR "  %s\n", frame_num, rel_pc, soname);
+      async_safe_format_buffer(
+          buf, sizeof(buf), "          #%02zd  pc %" PAD_PTR "  %s\n", frame_num, rel_pc, soname);
     }
     str += buf;
   }
diff --git a/libc/malloc_debug/debug_log.h b/libc/malloc_debug/debug_log.h
index 4df0408..ed4b541 100644
--- a/libc/malloc_debug/debug_log.h
+++ b/libc/malloc_debug/debug_log.h
@@ -29,18 +29,18 @@
 #ifndef MALLOC_DEBUG_LOG_H
 #define MALLOC_DEBUG_LOG_H
 
-#include <private/libc_logging.h>
+#include <async_safe/log.h>
 
 // =============================================================================
 // log functions
 // =============================================================================
 #define debug_log(format, ...)  \
-    __libc_format_log(ANDROID_LOG_DEBUG, "malloc_debug", (format), ##__VA_ARGS__ )
+    async_safe_format_log(ANDROID_LOG_DEBUG, "malloc_debug", (format), ##__VA_ARGS__ )
 #define error_log(format, ...)  \
-    __libc_format_log(ANDROID_LOG_ERROR, "malloc_debug", (format), ##__VA_ARGS__ )
+    async_safe_format_log(ANDROID_LOG_ERROR, "malloc_debug", (format), ##__VA_ARGS__ )
 #define error_log_string(str)  \
-    __libc_write_log(ANDROID_LOG_ERROR, "malloc_debug", (str))
+    async_safe_write_log(ANDROID_LOG_ERROR, "malloc_debug", (str))
 #define info_log(format, ...)  \
-    __libc_format_log(ANDROID_LOG_INFO, "malloc_debug", (format), ##__VA_ARGS__ )
+    async_safe_format_log(ANDROID_LOG_INFO, "malloc_debug", (format), ##__VA_ARGS__ )
 
 #endif  // MALLOC_DEBUG_LOG_H
diff --git a/libc/malloc_debug/tests/log_fake.cpp b/libc/malloc_debug/tests/log_fake.cpp
index 194d42b..fb64e3e 100644
--- a/libc/malloc_debug/tests/log_fake.cpp
+++ b/libc/malloc_debug/tests/log_fake.cpp
@@ -44,7 +44,7 @@
   return g_fake_log_print;
 }
 
-extern "C" int __libc_format_log(int priority, const char* tag, const char* format, ...) {
+extern "C" int async_safe_format_log(int priority, const char* tag, const char* format, ...) {
   g_fake_log_print += std::to_string(priority) + ' ';
   g_fake_log_print += tag;
   g_fake_log_print += ' ';
diff --git a/libc/private/WriteProtected.h b/libc/private/WriteProtected.h
index 1133e2a..20afdec 100644
--- a/libc/private/WriteProtected.h
+++ b/libc/private/WriteProtected.h
@@ -23,9 +23,10 @@
 #include <sys/mman.h>
 #include <sys/user.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_macros.h"
 #include "private/bionic_prctl.h"
-#include "private/libc_logging.h"
 
 template <typename T>
 union WriteProtectedContents {
@@ -57,7 +58,7 @@
     memset(&contents, 0, sizeof(contents));
 
     if (mprotect(&contents, PAGE_SIZE, PROT_READ)) {
-      __libc_fatal("failed to make WriteProtected nonwritable in initialize");
+      async_safe_fatal("failed to make WriteProtected nonwritable in initialize");
     }
   }
 
@@ -72,13 +73,13 @@
   template <typename Mutator>
   void mutate(Mutator mutator) {
     if (mprotect(&contents, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
-      __libc_fatal("failed to make WriteProtected writable in mutate: %s",
-                   strerror(errno));
+      async_safe_fatal("failed to make WriteProtected writable in mutate: %s",
+                       strerror(errno));
     }
     mutator(&contents.value);
     if (mprotect(&contents, PAGE_SIZE, PROT_READ) != 0) {
-      __libc_fatal("failed to make WriteProtected nonwritable in mutate: %s",
-                   strerror(errno));
+      async_safe_fatal("failed to make WriteProtected nonwritable in mutate: %s",
+                       strerror(errno));
     }
   }
 };
diff --git a/libc/private/bionic_fortify.h b/libc/private/bionic_fortify.h
index df810ca..8591117 100644
--- a/libc/private/bionic_fortify.h
+++ b/libc/private/bionic_fortify.h
@@ -26,11 +26,21 @@
  * SUCH DAMAGE.
  */
 
-#include "private/libc_logging.h"
-
 #include <poll.h> // For struct pollfd.
+#include <stdarg.h>
+#include <stdlib.h>
 #include <sys/select.h> // For struct fd_set.
 
+#include <async_safe/log.h>
+
+static inline __noreturn void __fortify_fatal(const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  async_safe_fatal_va_list("FORTIFY", fmt, args);
+  va_end(args);
+  abort();
+}
+
 //
 // Common helpers.
 //
diff --git a/libc/seccomp/mips64_policy.cpp b/libc/seccomp/mips64_policy.cpp
index f073d01..83b6111 100644
--- a/libc/seccomp/mips64_policy.cpp
+++ b/libc/seccomp/mips64_policy.cpp
@@ -5,59 +5,61 @@
 
 #include "seccomp_bpfs.h"
 const sock_filter mips64_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5000, 0, 82),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5168, 41, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5089, 21, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5038, 11, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5023, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5008, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5000, 0, 84),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5164, 41, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5077, 21, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5034, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5008, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5005, 3, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5003, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5002, 75, 74), //read|write
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5004, 74, 73), //close
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5020, 73, 72), //lseek|mmap|mprotect|munmap|brk|rt_sigaction|rt_sigprocmask|ioctl|pread64|pwrite64|readv|writev
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5034, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5031, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5028, 70, 69), //sched_yield|mremap|msync|mincore|madvise
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5032, 69, 68), //dup
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5037, 68, 67), //nanosleep|getitimer|setitimer
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5070, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5057, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5043, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5042, 64, 63), //getpid|sendfile|socket|connect
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5056, 63, 62), //sendto|recvfrom|sendmsg|recvmsg|shutdown|bind|listen|getsockname|getpeername|socketpair|setsockopt|getsockopt|clone
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5002, 77, 76), //read|write
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5004, 76, 75), //close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5006, 75, 74), //fstat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5031, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5023, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5020, 72, 71), //lseek|mmap|mprotect|munmap|brk|rt_sigaction|rt_sigprocmask|ioctl|pread64|pwrite64|readv|writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5028, 71, 70), //sched_yield|mremap|msync|mincore|madvise
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5032, 70, 69), //dup
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5057, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5043, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5038, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5037, 66, 65), //nanosleep|getitimer|setitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5042, 65, 64), //getpid|sendfile|socket|connect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5056, 64, 63), //sendto|recvfrom|sendmsg|recvmsg|shutdown|bind|listen|getsockname|getpeername|socketpair|setsockopt|getsockopt|clone
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5070, 1, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5062, 62, 61), //execve|exit|wait4|kill|uname
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5077, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5076, 60, 59), //fcntl|flock|fsync|fdatasync|truncate|ftruncate
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5080, 59, 58), //getcwd|chdir|fchdir
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5134, 9, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5110, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5093, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5091, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5090, 54, 53), //fchmod
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5092, 53, 52), //fchown
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5076, 61, 60), //fcntl|flock|fsync|fdatasync|truncate|ftruncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5132, 9, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5093, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5091, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5089, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5080, 56, 55), //getcwd|chdir|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5090, 55, 54), //fchmod
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5092, 54, 53), //fchown
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5110, 1, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5109, 52, 51), //umask|gettimeofday|getrlimit|getrusage|sysinfo|times|ptrace|getuid|syslog|getgid|setuid|setgid|geteuid|getegid|setpgid|getppid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5132, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5130, 50, 49), //setsid|setreuid|setregid|getgroups|setgroups|setresuid|getresuid|setresgid|getresgid|getpgid|setfsuid|setfsgid|getsid|capget|capset|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|sigaltstack
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5133, 49, 48), //personality
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5153, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5151, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5137, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5136, 45, 44), //statfs|fstatfs
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5150, 44, 43), //getpriority|setpriority|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|mlock|munlock|mlockall|munlockall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5130, 51, 50), //setsid|setreuid|setregid|getgroups|setgroups|setresuid|getresuid|setresgid|getresgid|getpgid|setfsuid|setfsgid|getsid|capget|capset|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|sigaltstack
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5151, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5137, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5134, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5133, 47, 46), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5136, 46, 45), //statfs|fstatfs
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5150, 45, 44), //getpriority|setpriority|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|mlock|munlock|mlockall|munlockall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5153, 1, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5152, 43, 42), //pivot_root
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5164, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5162, 41, 40), //prctl|adjtimex|setrlimit|chroot|sync|acct|settimeofday|mount|umount2
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5167, 40, 39), //reboot|sethostname|setdomainname
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5244, 19, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5208, 9, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5194, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5178, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5172, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5170, 34, 33), //init_module|delete_module
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5173, 33, 32), //quotactl
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5193, 32, 31), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5205, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5197, 30, 29), //futex|sched_setaffinity|sched_getaffinity
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5162, 42, 41), //prctl|adjtimex|setrlimit|chroot|sync|acct|settimeofday|mount|umount2
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5244, 21, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5208, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5178, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5172, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5168, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5167, 36, 35), //reboot|sethostname|setdomainname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5170, 35, 34), //init_module|delete_module
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5173, 34, 33), //quotactl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5205, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5194, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5193, 31, 30), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5198, 30, 29), //futex|sched_setaffinity|sched_getaffinity|cacheflush
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5206, 29, 28), //exit_group
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5237, 5, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5215, 3, 0),
@@ -70,11 +72,11 @@
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5243, 20, 19), //set_thread_area
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5297, 9, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5271, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5253, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5252, 3, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5247, 1, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5246, 15, 14), //inotify_add_watch|inotify_rm_watch
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5251, 14, 13), //openat|mkdirat|mknodat|fchownat
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5267, 13, 12), //unlinkat|renameat|linkat|symlinkat|readlinkat|fchmodat|faccessat|pselect6|ppoll|unshare|splice|sync_file_range|tee|vmsplice
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5267, 13, 12), //newfstatat|unlinkat|renameat|linkat|symlinkat|readlinkat|fchmodat|faccessat|pselect6|ppoll|unshare|splice|sync_file_range|tee|vmsplice
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5279, 1, 0),
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5276, 11, 10), //getcpu|epoll_pwait|ioprio_set|ioprio_get|utimensat
 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5295, 10, 9), //fallocate|timerfd_create|timerfd_gettime|timerfd_settime|signalfd4|eventfd2|epoll_create1|dup3|pipe2|inotify_init1|preadv|pwritev|rt_tgsigqueueinfo|perf_event_open|accept4|recvmmsg
diff --git a/libc/seccomp/seccomp_policy.cpp b/libc/seccomp/seccomp_policy.cpp
index fd2179b..fe83af0 100644
--- a/libc/seccomp/seccomp_policy.cpp
+++ b/libc/seccomp/seccomp_policy.cpp
@@ -51,10 +51,10 @@
 #elif defined __mips__ || defined __mips64__
 
 #define DUAL_ARCH
-#define PRIMARY_ARCH AUDIT_ARCH_MIPS64
+#define PRIMARY_ARCH AUDIT_ARCH_MIPSEL64
 static const struct sock_filter* primary_filter = mips64_filter;
 static const size_t primary_filter_size = mips64_filter_size;
-#define SECONDARY_ARCH AUDIT_ARCH_MIPS
+#define SECONDARY_ARCH AUDIT_ARCH_MIPSEL
 static const struct sock_filter* secondary_filter = mips_filter;
 static const size_t secondary_filter_size = mips_filter_size;
 
diff --git a/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp
index f2f58c6..ebc705c 100644
--- a/libc/stdio/stdio_ext.cpp
+++ b/libc/stdio/stdio_ext.cpp
@@ -31,8 +31,9 @@
 #include <errno.h>
 #include <stdlib.h>
 
+#include <async_safe/log.h>
+
 #include "local.h"
-#include "private/libc_logging.h"
 
 size_t __fbufsize(FILE* fp) {
   return fp->_bf._size;
@@ -83,7 +84,7 @@
 
   if (type != FSETLOCKING_INTERNAL && type != FSETLOCKING_BYCALLER) {
     // The API doesn't let us report an error, so blow up.
-    __libc_fatal("Bad type (%d) passed to __fsetlocking", type);
+    async_safe_fatal("Bad type (%d) passed to __fsetlocking", type);
   }
 
   _EXT(fp)->_caller_handles_locking = (type == FSETLOCKING_BYCALLER);
diff --git a/libc/upstream-openbsd/android/include/arc4random.h b/libc/upstream-openbsd/android/include/arc4random.h
index 0d70c81..d006045 100644
--- a/libc/upstream-openbsd/android/include/arc4random.h
+++ b/libc/upstream-openbsd/android/include/arc4random.h
@@ -27,8 +27,9 @@
 #include <pthread.h>
 #include <signal.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_prctl.h"
-#include "private/libc_logging.h"
 
 // Android gets these from "thread_private.h".
 #include "thread_private.h"
@@ -47,7 +48,7 @@
 static inline void
 _getentropy_fail(void)
 {
-	__libc_fatal("getentropy failed");
+	async_safe_fatal("getentropy failed");
 }
 
 volatile sig_atomic_t _rs_forked;
diff --git a/linker/Android.bp b/linker/Android.bp
index d617189..efd91ac 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -9,6 +9,8 @@
 
     // We need to access Bionic private headers in the linker.
     include_dirs: ["bionic/libc"],
+
+    static_libs: ["libasync_safe"],
 }
 
 cc_binary {
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 7c26073..cd2c55b 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -46,6 +46,8 @@
 
 #include <android-base/scopeguard.h>
 
+#include <async_safe/log.h>
+
 // Private C library headers.
 
 #include "linker.h"
@@ -344,7 +346,7 @@
 
 static bool realpath_fd(int fd, std::string* realpath) {
   std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
-  __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
+  async_safe_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
   if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
     PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
     return false;
@@ -493,7 +495,7 @@
   }
 
   if (ref_count_ == 0) { // overflow
-    __libc_fatal("Too many nested calls to dlopen()");
+    async_safe_fatal("Too many nested calls to dlopen()");
   }
 }
 
@@ -992,7 +994,7 @@
 }
 
 static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
-  int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
+  int n = async_safe_format_buffer(buf, buf_size, "%s/%s", path, name);
   if (n < 0 || n >= static_cast<int>(buf_size)) {
     PRINT("Warning: ignoring very long library path: %s/%s", path, name);
     return false;
@@ -1781,7 +1783,7 @@
       }
     } else {
 #if !defined(__work_around_b_24465209__)
-      __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
+      async_safe_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
 #else
       PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
       for_each_dt_needed(si, [&] (const char* library_name) {
@@ -1855,8 +1857,8 @@
   }
 
   if (buffer_size < required_size) {
-    __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
-                 "buffer len %zu, required len %zu", buffer_size, required_size);
+    async_safe_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
+                     "buffer len %zu, required len %zu", buffer_size, required_size);
   }
 
   char* end = buffer;
diff --git a/linker/linker.h b/linker/linker.h
index 53dac6c..fdd7b66 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -38,7 +38,6 @@
 #include <unistd.h>
 
 #include "private/bionic_page.h"
-#include "private/libc_logging.h"
 #include "linked_list.h"
 #include "linker_common_types.h"
 #include "linker_logger.h"
diff --git a/linker/linker_allocator.cpp b/linker/linker_allocator.cpp
index 723ea2b..fd6f496 100644
--- a/linker/linker_allocator.cpp
+++ b/linker/linker_allocator.cpp
@@ -37,6 +37,8 @@
 #include <sys/mman.h>
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_prctl.h"
 
 //
@@ -149,7 +151,7 @@
   ssize_t offset = reinterpret_cast<uintptr_t>(ptr) - sizeof(page_info);
 
   if (offset % block_size_ != 0) {
-    __libc_fatal("invalid pointer: %p (block_size=%zd)", ptr, block_size_);
+    async_safe_fatal("invalid pointer: %p (block_size=%zd)", ptr, block_size_);
   }
 
   memset(ptr, 0, block_size_);
@@ -180,7 +182,7 @@
 
   if (it == page_records_.end() || it->page_addr != addr) {
     // not found...
-    __libc_fatal("page record for %p was not found (block_size=%zd)", ptr, block_size_);
+    async_safe_fatal("page record for %p was not found (block_size=%zd)", ptr, block_size_);
   }
 
   return it;
@@ -203,7 +205,7 @@
   void* map_ptr = mmap(nullptr, PAGE_SIZE,
       PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
   if (map_ptr == MAP_FAILED) {
-    __libc_fatal("mmap failed");
+    async_safe_fatal("mmap failed");
   }
 
   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_ptr, PAGE_SIZE, "linker_alloc_small_objects");
@@ -248,7 +250,7 @@
       PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
 
   if (map_ptr == MAP_FAILED) {
-    __libc_fatal("mmap failed");
+    async_safe_fatal("mmap failed");
   }
 
   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_ptr, allocated_size, "linker_alloc_lob");
@@ -283,7 +285,7 @@
 page_info* LinkerMemoryAllocator::get_page_info(void* ptr) {
   page_info* info = reinterpret_cast<page_info*>(PAGE_START(reinterpret_cast<size_t>(ptr)));
   if (memcmp(info->signature, kSignature, sizeof(kSignature)) != 0) {
-    __libc_fatal("invalid pointer %p (page signature mismatch)", ptr);
+    async_safe_fatal("invalid pointer %p (page signature mismatch)", ptr);
   }
 
   return info;
@@ -308,7 +310,7 @@
   } else {
     LinkerSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
     if (allocator != info->allocator_addr) {
-      __libc_fatal("invalid pointer %p (page signature mismatch)", ptr);
+      async_safe_fatal("invalid pointer %p (page signature mismatch)", ptr);
     }
 
     old_size = allocator->get_block_size();
@@ -336,7 +338,7 @@
   } else {
     LinkerSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
     if (allocator != info->allocator_addr) {
-      __libc_fatal("invalid pointer %p (invalid allocator address for the page)", ptr);
+      async_safe_fatal("invalid pointer %p (invalid allocator address for the page)", ptr);
     }
 
     allocator->free(ptr);
@@ -345,7 +347,7 @@
 
 LinkerSmallObjectAllocator* LinkerMemoryAllocator::get_small_object_allocator(uint32_t type) {
   if (type < kSmallObjectMinSizeLog2 || type > kSmallObjectMaxSizeLog2) {
-    __libc_fatal("invalid type: %u", type);
+    async_safe_fatal("invalid type: %u", type);
   }
 
   initialize_allocators();
diff --git a/linker/linker_allocator.h b/linker/linker_allocator.h
index beffc52..80ae508 100644
--- a/linker/linker_allocator.h
+++ b/linker/linker_allocator.h
@@ -37,8 +37,9 @@
 
 #include <vector>
 
+#include <async_safe/log.h>
+
 #include "private/bionic_prctl.h"
-#include "private/libc_logging.h"
 
 const uint32_t kSmallObjectMaxSizeLog2 = 10;
 const uint32_t kSmallObjectMinSizeLog2 = 4;
@@ -92,7 +93,7 @@
     if (ptr == MAP_FAILED) {
       // Spec says we need to throw std::bad_alloc here but because our
       // code does not support exception handling anyways - we are going to abort.
-      __libc_fatal("mmap failed");
+      async_safe_fatal("mmap failed");
     }
 
     prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, size, "linker_alloc_vector");
diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp
index f614ba0..0a9aeab 100644
--- a/linker/linker_config.cpp
+++ b/linker/linker_config.cpp
@@ -36,6 +36,8 @@
 #include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 
+#include <async_safe/log.h>
+
 #include <stdlib.h>
 
 #include <string>
@@ -149,7 +151,7 @@
                                     size_t lineno,
                                     const std::string& msg) {
   char buf[1024];
-  __libc_format_buffer(buf, sizeof(buf), "%s:%zu: error: %s", file, lineno, msg.c_str());
+  async_safe_format_buffer(buf, sizeof(buf), "%s:%zu: error: %s", file, lineno, msg.c_str());
 
   return std::string(buf);
 }
@@ -328,7 +330,7 @@
     params.push_back({ "LIB", kLibParamValue });
     if (target_sdk_version_ != 0) {
       char buf[16];
-      __libc_format_buffer(buf, sizeof(buf), "%d", target_sdk_version_);
+      async_safe_format_buffer(buf, sizeof(buf), "%d", target_sdk_version_);
       params.push_back({ "SDK_VER", buf });
     }
 
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 42796e9..7ceab08 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -54,20 +54,21 @@
  * To enable/disable specific debug options, change the defines above
  *********************************************************************/
 
-#include "private/libc_logging.h"
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 __LIBC_HIDDEN__ extern int g_ld_debug_verbosity;
 
 #if LINKER_DEBUG_TO_LOG
 #define _PRINTVF(v, x...) \
     do { \
-      if (g_ld_debug_verbosity > (v)) __libc_format_log(5-(v), "linker", x); \
+      if (g_ld_debug_verbosity > (v)) async_safe_format_log(5-(v), "linker", x); \
     } while (0)
 #else /* !LINKER_DEBUG_TO_LOG */
 #define _PRINTVF(v, x...) \
     do { \
-      if (g_ld_debug_verbosity > (v)) { __libc_format_fd(1, x); write(1, "\n", 1); } \
+      if (g_ld_debug_verbosity > (v)) { async_safe_format_fd(1, x); write(1, "\n", 1); } \
     } while (0)
 #endif /* !LINKER_DEBUG_TO_LOG */
 
diff --git a/linker/linker_globals.h b/linker/linker_globals.h
index 1ed479c..d8134af 100644
--- a/linker/linker_globals.h
+++ b/linker/linker_globals.h
@@ -34,20 +34,20 @@
 
 #include <unordered_map>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 #define DL_ERR(fmt, x...) \
     do { \
-      __libc_format_buffer(linker_get_error_buffer(), linker_get_error_buffer_size(), fmt, ##x); \
+      async_safe_format_buffer(linker_get_error_buffer(), linker_get_error_buffer_size(), fmt, ##x); \
       /* If LD_DEBUG is set high enough, log every dlerror(3) message. */ \
     } while (false)
 
 #define DL_WARN(fmt, x...) \
     do { \
-      __libc_format_log(ANDROID_LOG_WARN, "linker", fmt, ##x); \
-      __libc_format_fd(2, "WARNING: linker: "); \
-      __libc_format_fd(2, fmt, ##x); \
-      __libc_format_fd(2, "\n"); \
+      async_safe_format_log(ANDROID_LOG_WARN, "linker", fmt, ##x); \
+      async_safe_format_fd(2, "WARNING: linker: "); \
+      async_safe_format_fd(2, fmt, ##x); \
+      async_safe_format_fd(2, "\n"); \
     } while (false)
 
 #define DL_ERR_AND_LOG(fmt, x...) \
diff --git a/linker/linker_libcxx_support.cpp b/linker/linker_libcxx_support.cpp
index e7b23e0..11e0f40 100644
--- a/linker/linker_libcxx_support.cpp
+++ b/linker/linker_libcxx_support.cpp
@@ -26,8 +26,8 @@
  * SUCH DAMAGE.
  */
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 void* __find_icu_symbol(const char* symbol_name __attribute__((__unused__))) {
-  __libc_fatal("__find_icu_symbol should not be called in the linker");
+  async_safe_fatal("__find_icu_symbol should not be called in the linker");
 }
diff --git a/linker/linker_logger.cpp b/linker/linker_logger.cpp
index 717667c..4c6603b 100644
--- a/linker/linker_logger.cpp
+++ b/linker/linker_logger.cpp
@@ -35,9 +35,10 @@
 #include <string>
 #include <vector>
 
+#include <async_safe/log.h>
+
 #include "android-base/strings.h"
 #include "private/CachedProperty.h"
-#include "private/libc_logging.h"
 
 LinkerLogger g_linker_logger;
 bool g_greylist_disabled = false;
@@ -59,8 +60,8 @@
     } else if (o == "dlsym") {
       flags |= kLogDlsym;
     } else {
-      __libc_format_log(ANDROID_LOG_WARN, "linker", "Ignoring unknown debug.ld option \"%s\"",
-                        o.c_str());
+      async_safe_format_log(ANDROID_LOG_WARN, "linker", "Ignoring unknown debug.ld option \"%s\"",
+                            o.c_str());
     }
   }
 
@@ -95,8 +96,8 @@
   bool old_value = g_greylist_disabled;
   g_greylist_disabled = (strcmp(greylist_disabled.Get(), "true") == 0);
   if (g_greylist_disabled != old_value) {
-    __libc_format_log(ANDROID_LOG_INFO, "linker", "%s greylist",
-                      g_greylist_disabled ? "Disabling" : "Enabling");
+    async_safe_format_log(ANDROID_LOG_INFO, "linker", "%s greylist",
+                          g_greylist_disabled ? "Disabling" : "Enabling");
   }
 
   flags_ = 0;
@@ -124,6 +125,6 @@
 
   va_list ap;
   va_start(ap, format);
-  __libc_format_log_va_list(ANDROID_LOG_DEBUG, "linker", format, ap);
+  async_safe_format_log_va_list(ANDROID_LOG_DEBUG, "linker", format, ap);
   va_end(ap);
 }
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 40f82a1..3d26e91 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -45,6 +45,8 @@
 #include "debuggerd/handler.h"
 #endif
 
+#include <async_safe/log.h>
+
 #include <vector>
 
 extern void __libc_init_globals(KernelArgumentBlock&);
@@ -189,7 +191,7 @@
     char path[PATH_MAX];
     ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
     if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
-      __libc_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
+      async_safe_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
     }
     executable_path = std::string(path, path_len);
   }
@@ -267,13 +269,13 @@
   // the executable could be unlinked by this point and it should
   // not cause a crash (see http://b/31084669)
   if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {
-    __libc_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
+    async_safe_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
   }
 
   const char* executable_path = get_executable_path();
   soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL);
   if (si == nullptr) {
-    __libc_fatal("Couldn't allocate soinfo: out of memory?");
+    async_safe_fatal("Couldn't allocate soinfo: out of memory?");
   }
 
   /* bootstrap the link map, the main exe always needs to be first */
@@ -319,7 +321,7 @@
     // tombstone for them. The tombstone never provided any detail relevant to
     // fixing the problem anyway, and the utility of drawing extra attention
     // to the problem is non-existent at this late date.
-    __libc_format_fd(STDERR_FILENO,
+    async_safe_format_fd(STDERR_FILENO,
                      "\"%s\": error: Android 5.0 and later only support "
                      "position-independent executables (-fPIE).\n",
                      g_argv[0]);
@@ -335,7 +337,7 @@
   init_default_namespace(executable_path);
 
   if (!si->prelink_image()) {
-    __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+    async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
   }
 
   // add somain to global group
@@ -369,10 +371,10 @@
                       nullptr,
                       true /* add_as_children */,
                       true /* search_linked_namespaces */)) {
-    __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+    async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
   } else if (needed_libraries_count == 0) {
     if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr)) {
-      __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+      async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
     }
     si->increment_ref_count();
   }
@@ -380,7 +382,7 @@
   add_vdso(args);
 
   if (!get_cfi_shadow()->InitialLinkDone(solist)) {
-    __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+    async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
   }
 
   si->call_pre_init_constructors();
@@ -464,7 +466,7 @@
 }
 
 static void __linker_cannot_link(const char* argv0) {
-  __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", argv0, linker_get_error_buffer());
+  async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", argv0, linker_get_error_buffer());
 }
 
 /*
@@ -546,7 +548,7 @@
   // This happens when user tries to run 'adb shell /system/bin/linker'
   // see also https://code.google.com/p/android/issues/detail?id=63174
   if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
-    __libc_format_fd(STDOUT_FILENO,
+    async_safe_format_fd(STDOUT_FILENO,
                      "This is %s, the helper program for dynamic executables.\n",
                      args.argv[0]);
     exit(0);
diff --git a/linker/linker_memory.cpp b/linker/linker_memory.cpp
index f8852e1..472c4e8 100644
--- a/linker/linker_memory.cpp
+++ b/linker/linker_memory.cpp
@@ -32,7 +32,7 @@
 #include <sys/cdefs.h>
 #include <unistd.h>
 
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
 
 static LinkerMemoryAllocator g_linker_allocator;
 static pid_t fallback_tid = 0;
@@ -41,7 +41,7 @@
 // case the linker heap is corrupted. Do not use this function.
 extern "C" void __linker_enable_fallback_allocator() {
   if (fallback_tid != 0) {
-    __libc_fatal("attempted to use currently-in-use fallback allocator");
+    async_safe_fatal("attempted to use currently-in-use fallback allocator");
   }
 
   fallback_tid = gettid();
@@ -49,7 +49,7 @@
 
 extern "C" void __linker_disable_fallback_allocator() {
   if (fallback_tid == 0) {
-    __libc_fatal("attempted to disable unused fallback allocator");
+    async_safe_fatal("attempted to disable unused fallback allocator");
   }
 
   fallback_tid = 0;
diff --git a/linker/linker_sleb128.h b/linker/linker_sleb128.h
index 74b69e4..01e127d 100644
--- a/linker/linker_sleb128.h
+++ b/linker/linker_sleb128.h
@@ -31,6 +31,8 @@
 
 #include <stdint.h>
 
+#include <async_safe/log.h>
+
 #include "linker_debug.h"
 
 // Helper classes for decoding LEB128, used in packed relocation data.
@@ -50,7 +52,7 @@
 
     do {
       if (current_ >= end_) {
-        __libc_fatal("sleb128_decoder ran out of bounds");
+        async_safe_fatal("sleb128_decoder ran out of bounds");
       }
       byte = *current_++;
       value |= (static_cast<size_t>(byte & 127) << shift);
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 1d59dbb..fbff7cf 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -34,6 +34,8 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include <async_safe/log.h>
+
 #include "linker_debug.h"
 #include "linker_globals.h"
 #include "linker_logger.h"
@@ -636,7 +638,7 @@
 
 const char* soinfo::get_string(ElfW(Word) index) const {
   if (has_min_version(1) && (index >= strtab_size_)) {
-    __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
+    async_safe_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
         get_realpath(), strtab_size_, index);
   }
 
diff --git a/linker/tests/Android.mk b/linker/tests/Android.mk
index 61c43c9..8284bea 100644
--- a/linker/tests/Android.mk
+++ b/linker/tests/Android.mk
@@ -51,9 +51,6 @@
   ../linker_config.cpp \
   ../linker_utils.cpp \
 
-# for __libc_fatal
-LOCAL_SRC_FILES += ../../libc/bionic/libc_logging.cpp
-
-LOCAL_STATIC_LIBRARIES += libbase
+LOCAL_STATIC_LIBRARIES += libasync_safe libbase
 
 include $(BUILD_NATIVE_TEST)
diff --git a/tests/Android.bp b/tests/Android.bp
index d4e3800..4605267 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -52,6 +52,7 @@
     defaults: ["bionic_tests_defaults"],
     srcs: [
         "arpa_inet_test.cpp",
+        "async_safe_test.cpp",
         "assert_test.cpp",
         "buffer_tests.cpp",
         "bug_26110743_test.cpp",
@@ -72,7 +73,6 @@
         "inttypes_test.cpp",
         "langinfo_test.cpp",
         "leak_test.cpp",
-        "libc_logging_test.cpp",
         "libgen_basename_test.cpp",
         "libgen_test.cpp",
         "linux_swab_test.cpp",
@@ -151,6 +151,12 @@
         "external/tinyxml2",
     ],
 
+    target: {
+        android: {
+            whole_static_libs: ["libasync_safe"],
+        },
+    },
+
     static_libs: [
         "libtinyxml2",
         "liblog",
diff --git a/tests/async_safe_test.cpp b/tests/async_safe_test.cpp
new file mode 100644
index 0000000..3d6fcaa
--- /dev/null
+++ b/tests/async_safe_test.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#if defined(__BIONIC__)
+#include <async_safe/log.h>
+#endif // __BIONIC__
+
+TEST(async_safe_log, smoke) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+
+  async_safe_format_buffer(buf, sizeof(buf), "a");
+  EXPECT_STREQ("a", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "%%");
+  EXPECT_STREQ("%", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "01234");
+  EXPECT_STREQ("01234", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%sb", "01234");
+  EXPECT_STREQ("a01234b", buf);
+
+  char* s = NULL;
+  async_safe_format_buffer(buf, sizeof(buf), "a%sb", s);
+  EXPECT_STREQ("a(null)b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "aa%scc", "bb");
+  EXPECT_STREQ("aabbcc", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%cc", 'b');
+  EXPECT_STREQ("abc", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%db", 1234);
+  EXPECT_STREQ("a1234b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%db", -8123);
+  EXPECT_STREQ("a-8123b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%hdb", static_cast<short>(0x7fff0010));
+  EXPECT_STREQ("a16b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%hhdb", static_cast<char>(0x7fffff10));
+  EXPECT_STREQ("a16b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%lldb", 0x1000000000LL);
+  EXPECT_STREQ("a68719476736b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%ldb", 70000L);
+  EXPECT_STREQ("a70000b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%pb", reinterpret_cast<void*>(0xb0001234));
+  EXPECT_STREQ("a0xb0001234b", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%xz", 0x12ab);
+  EXPECT_STREQ("a12abz", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%Xz", 0x12ab);
+  EXPECT_STREQ("a12ABz", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%08xz", 0x123456);
+  EXPECT_STREQ("a00123456z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%5dz", 1234);
+  EXPECT_STREQ("a 1234z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%05dz", 1234);
+  EXPECT_STREQ("a01234z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%8dz", 1234);
+  EXPECT_STREQ("a    1234z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%-8dz", 1234);
+  EXPECT_STREQ("a1234    z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "A%-11sZ", "abcdef");
+  EXPECT_STREQ("Aabcdef     Z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "A%s:%dZ", "hello", 1234);
+  EXPECT_STREQ("Ahello:1234Z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5);
+  EXPECT_STREQ("a005:5:05z", buf);
+
+  void* p = NULL;
+  async_safe_format_buffer(buf, sizeof(buf), "a%d,%pz", 5, p);
+  EXPECT_STREQ("a5,0x0z", buf);
+
+  async_safe_format_buffer(buf, sizeof(buf), "a%lld,%d,%d,%dz", 0x1000000000LL, 6, 7, 8);
+  EXPECT_STREQ("a68719476736,6,7,8z", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, d_INT_MAX) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%d", INT_MAX);
+  EXPECT_STREQ("2147483647", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, d_INT_MIN) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%d", INT_MIN);
+  EXPECT_STREQ("-2147483648", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, ld_LONG_MAX) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%ld", LONG_MAX);
+#if defined(__LP64__)
+  EXPECT_STREQ("9223372036854775807", buf);
+#else
+  EXPECT_STREQ("2147483647", buf);
+#endif
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, ld_LONG_MIN) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%ld", LONG_MIN);
+#if defined(__LP64__)
+  EXPECT_STREQ("-9223372036854775808", buf);
+#else
+  EXPECT_STREQ("-2147483648", buf);
+#endif
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, lld_LLONG_MAX) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%lld", LLONG_MAX);
+  EXPECT_STREQ("9223372036854775807", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, lld_LLONG_MIN) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  async_safe_format_buffer(buf, sizeof(buf), "%lld", LLONG_MIN);
+  EXPECT_STREQ("-9223372036854775808", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
+
+TEST(async_safe_log, buffer_overrun) {
+#if defined(__BIONIC__)
+  char buf[BUFSIZ];
+  ASSERT_EQ(11, async_safe_format_buffer(buf, sizeof(buf), "hello %s", "world"));
+  EXPECT_STREQ("hello world", buf);
+  ASSERT_EQ(11, async_safe_format_buffer(buf, 8, "hello %s", "world"));
+  EXPECT_STREQ("hello w", buf);
+#else // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
diff --git a/tests/libc_logging_test.cpp b/tests/libc_logging_test.cpp
deleted file mode 100644
index 4150483..0000000
--- a/tests/libc_logging_test.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#if defined(__BIONIC__)
-#include "../libc/bionic/libc_logging.cpp"
-extern int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...);
-#endif // __BIONIC__
-
-TEST(libc_logging, smoke) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-
-  __libc_format_buffer(buf, sizeof(buf), "a");
-  EXPECT_STREQ("a", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "%%");
-  EXPECT_STREQ("%", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "01234");
-  EXPECT_STREQ("01234", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%sb", "01234");
-  EXPECT_STREQ("a01234b", buf);
-
-  char* s = NULL;
-  __libc_format_buffer(buf, sizeof(buf), "a%sb", s);
-  EXPECT_STREQ("a(null)b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "aa%scc", "bb");
-  EXPECT_STREQ("aabbcc", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%cc", 'b');
-  EXPECT_STREQ("abc", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%db", 1234);
-  EXPECT_STREQ("a1234b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%db", -8123);
-  EXPECT_STREQ("a-8123b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%hdb", static_cast<short>(0x7fff0010));
-  EXPECT_STREQ("a16b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%hhdb", static_cast<char>(0x7fffff10));
-  EXPECT_STREQ("a16b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%lldb", 0x1000000000LL);
-  EXPECT_STREQ("a68719476736b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%ldb", 70000L);
-  EXPECT_STREQ("a70000b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%pb", reinterpret_cast<void*>(0xb0001234));
-  EXPECT_STREQ("a0xb0001234b", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%xz", 0x12ab);
-  EXPECT_STREQ("a12abz", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%Xz", 0x12ab);
-  EXPECT_STREQ("a12ABz", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%08xz", 0x123456);
-  EXPECT_STREQ("a00123456z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%5dz", 1234);
-  EXPECT_STREQ("a 1234z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%05dz", 1234);
-  EXPECT_STREQ("a01234z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%8dz", 1234);
-  EXPECT_STREQ("a    1234z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%-8dz", 1234);
-  EXPECT_STREQ("a1234    z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "A%-11sZ", "abcdef");
-  EXPECT_STREQ("Aabcdef     Z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "A%s:%dZ", "hello", 1234);
-  EXPECT_STREQ("Ahello:1234Z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5);
-  EXPECT_STREQ("a005:5:05z", buf);
-
-  void* p = NULL;
-  __libc_format_buffer(buf, sizeof(buf), "a%d,%pz", 5, p);
-  EXPECT_STREQ("a5,0x0z", buf);
-
-  __libc_format_buffer(buf, sizeof(buf), "a%lld,%d,%d,%dz", 0x1000000000LL, 6, 7, 8);
-  EXPECT_STREQ("a68719476736,6,7,8z", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, d_INT_MAX) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%d", INT_MAX);
-  EXPECT_STREQ("2147483647", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, d_INT_MIN) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%d", INT_MIN);
-  EXPECT_STREQ("-2147483648", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, ld_LONG_MAX) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%ld", LONG_MAX);
-#if defined(__LP64__)
-  EXPECT_STREQ("9223372036854775807", buf);
-#else
-  EXPECT_STREQ("2147483647", buf);
-#endif
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, ld_LONG_MIN) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%ld", LONG_MIN);
-#if defined(__LP64__)
-  EXPECT_STREQ("-9223372036854775808", buf);
-#else
-  EXPECT_STREQ("-2147483648", buf);
-#endif
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, lld_LLONG_MAX) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%lld", LLONG_MAX);
-  EXPECT_STREQ("9223372036854775807", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, lld_LLONG_MIN) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  __libc_format_buffer(buf, sizeof(buf), "%lld", LLONG_MIN);
-  EXPECT_STREQ("-9223372036854775808", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
-
-TEST(libc_logging, buffer_overrun) {
-#if defined(__BIONIC__)
-  char buf[BUFSIZ];
-  ASSERT_EQ(11, __libc_format_buffer(buf, sizeof(buf), "hello %s", "world"));
-  EXPECT_STREQ("hello world", buf);
-  ASSERT_EQ(11, __libc_format_buffer(buf, 8, "hello %s", "world"));
-  EXPECT_STREQ("hello w", buf);
-#else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
-}
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index 385fe33..0d42b05 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -1372,20 +1372,56 @@
   RunCmpBufferOverreadTest(DoMemcmpTest, DoMemcmpFailTest);
 }
 
+static void DoMemchrTest(uint8_t* buf, size_t len) {
+  if (len >= 1) {
+    int value = len % 128;
+    int search_value = (len % 128) + 1;
+    memset(buf, value, len);
+    // The buffer does not contain the search value.
+    ASSERT_EQ(nullptr, memchr(buf, search_value, len));
+    if (len >= 2) {
+      buf[0] = search_value;
+      // The search value is the first element in the buffer.
+      ASSERT_EQ(&buf[0], memchr(buf, search_value, len));
+
+      buf[0] = value;
+      buf[len - 1] = search_value;
+      // The search value is the last element in the buffer.
+      ASSERT_EQ(&buf[len - 1], memchr(buf, search_value, len));
+    }
+  }
+}
+
+TEST(STRING_TEST, memchr_align) {
+  RunSingleBufferAlignTest(MEDIUM, DoMemchrTest);
+}
+
+TEST(STRING_TEST, memchr_overread) {
+  RunSingleBufferOverreadTest(DoMemchrTest);
+}
+
 static void DoStrchrTest(uint8_t* buf, size_t len) {
   if (len >= 1) {
     char value = 32 + (len % 96);
     char search_value = 33 + (len % 96);
     memset(buf, value, len - 1);
-    buf[len-1] = '\0';
-    ASSERT_EQ(NULL, strchr(reinterpret_cast<char*>(buf), search_value));
-    ASSERT_EQ(reinterpret_cast<char*>(&buf[len-1]), strchr(reinterpret_cast<char*>(buf), '\0'));
+    buf[len - 1] = '\0';
+    // The buffer does not contain the search value.
+    ASSERT_EQ(nullptr, strchr(reinterpret_cast<char*>(buf), search_value));
+    // Search for the special '\0' character.
+    ASSERT_EQ(reinterpret_cast<char*>(&buf[len - 1]), strchr(reinterpret_cast<char*>(buf), '\0'));
     if (len >= 2) {
       buf[0] = search_value;
-      ASSERT_EQ(reinterpret_cast<char*>(&buf[0]), strchr(reinterpret_cast<char*>(buf), search_value));
+      // The search value is the first element in the buffer.
+      ASSERT_EQ(reinterpret_cast<char*>(&buf[0]), strchr(reinterpret_cast<char*>(buf),
+                                                         search_value));
+
       buf[0] = value;
-      buf[len-2] = search_value;
-      ASSERT_EQ(reinterpret_cast<char*>(&buf[len-2]), strchr(reinterpret_cast<char*>(buf), search_value));
+      buf[len - 2] = search_value;
+      // The search value is the second to last element in the buffer.
+      // The last element is the '\0' character.
+      ASSERT_EQ(reinterpret_cast<char*>(&buf[len - 2]), strchr(reinterpret_cast<char*>(buf),
+                                                               search_value));
     }
   }
 }
@@ -1398,6 +1434,40 @@
   RunSingleBufferOverreadTest(DoStrchrTest);
 }
 
+static void DoStrrchrTest(uint8_t* buf, size_t len) {
+  if (len >= 1) {
+    char value = 32 + (len % 96);
+    char search_value = 33 + (len % 96);
+    memset(buf, value, len - 1);
+    buf[len - 1] = '\0';
+    // The buffer does not contain the search value.
+    ASSERT_EQ(nullptr, strrchr(reinterpret_cast<char*>(buf), search_value));
+    // Search for the special '\0' character.
+    ASSERT_EQ(reinterpret_cast<char*>(&buf[len - 1]), strrchr(reinterpret_cast<char*>(buf), '\0'));
+    if (len >= 2) {
+      buf[0] = search_value;
+      // The search value is the first element in the buffer.
+      ASSERT_EQ(reinterpret_cast<char*>(&buf[0]), strrchr(reinterpret_cast<char*>(buf),
+                                                          search_value));
+
+      buf[0] = value;
+      buf[len - 2] = search_value;
+      // The search value is the second to last element in the buffer.
+      // The last element is the '\0' character.
+      ASSERT_EQ(reinterpret_cast<char*>(&buf[len - 2]), strrchr(reinterpret_cast<char*>(buf),
+                                                                search_value));
+    }
+  }
+}
+
+TEST(STRING_TEST, strrchr_align) {
+  RunSingleBufferAlignTest(MEDIUM, DoStrrchrTest);
+}
+
+TEST(STRING_TEST, strrchr_overread) {
+  RunSingleBufferOverreadTest(DoStrrchrTest);
+}
+
 static void TestBasename(const char* in, const char* expected_out) {
   errno = 0;
   const char* out = basename(in);
diff --git a/tools/versioner/dependencies b/tools/versioner/dependencies
new file mode 120000
index 0000000..4ec3391
--- /dev/null
+++ b/tools/versioner/dependencies
@@ -0,0 +1 @@
+../../libc/versioner-dependencies
\ No newline at end of file
diff --git a/tools/versioner/src/versioner.cpp b/tools/versioner/src/versioner.cpp
index 688de5b..735ea04 100644
--- a/tools/versioner/src/versioner.cpp
+++ b/tools/versioner/src/versioner.cpp
@@ -41,6 +41,7 @@
 
 #include <llvm/ADT/StringRef.h>
 
+#include <android-base/file.h>
 #include <android-base/macros.h>
 #include <android-base/parseint.h>
 
@@ -576,8 +577,9 @@
       platform_dir = versioner_dir + "/platforms";
     }
   } else {
-    // Intentional leak.
-    header_dir = realpath(argv[optind], nullptr);
+    if (!android::base::Realpath(argv[optind], &header_dir)) {
+      err(1, "failed to get realpath for path '%s'", argv[optind]);
+    }
 
     if (argc - optind == 2) {
       dependency_dir = argv[optind + 1];