Merge "Exclude libclang_rt.builtins symbols"
diff --git a/README.md b/README.md
index a6cf467..12c5235 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,17 @@
-Using bionic
-============
+# bionic
 
-See the [additional documentation](docs/).
+[bionic](https://en.wikipedia.org/wiki/Bionic_(software)) is Android's
+C library, math library, and dynamic linker.
 
-Working on bionic
-=================
+# Using bionic as an app developer
 
-What are the big pieces of bionic?
-----------------------------------
+See the [user documentation](docs/).
+
+# Working on bionic itself
+
+This documentation is about making changes to bionic itself.
+
+## What are the big pieces of bionic?
 
 #### libc/ --- libc.so, libc.a
 
@@ -51,10 +55,9 @@
 The `benchmarks/` directory contains benchmarks, with its own [documentation](benchmarks/README.md).
 
 
-What's in libc/?
-----------------
+## What's in libc/?
 
-<pre>
+```
 libc/
   arch-arm/
   arch-arm64/
@@ -69,12 +72,6 @@
     bionic/
       # Every architecture needs a handful of machine-specific assembler files.
       # They live here.
-    include/
-      machine/
-        # The majority of header files are actually in libc/include/, but many
-        # of them pull in a <machine/something.h> for things like limits,
-        # endianness, and how floating point numbers are represented. Those
-        # headers live here.
     string/
       # Most architectures have a handful of optional assembler files
       # implementing optimized versions of various routines. The <string.h>
@@ -141,11 +138,10 @@
   zoneinfo/
     # Android-format time zone data.
     # See 'Updating tzdata' later.
-</pre>
+```
 
 
-Adding libc wrappers for system calls
--------------------------------------
+## Adding libc wrappers for system calls
 
 The first question you should ask is "should I add a libc wrapper for
 this system call?". The answer is usually "no".
@@ -183,8 +179,7 @@
      correct system call is being made.)
 
 
-Updating kernel header files
-----------------------------
+## Updating kernel header files
 
 As mentioned above, this is currently a two-step process:
 
@@ -197,8 +192,7 @@
 `TARGET_DEVICE_KERNEL_HEADERS` and friends described in [config.mk](https://android.googlesource.com/platform/build/+/master/core/config.mk#186).
 
 
-Updating tzdata
----------------
+## Updating tzdata
 
 This is fully automated (and these days handled by the libcore team, because
 they own icu, and that needs to be updated in sync with bionic):
@@ -206,8 +200,7 @@
   1. Run update-tzdata.py in external/icu/tools/.
 
 
-Verifying changes
------------------
+## Verifying changes
 
 If you make a change that is likely to have a wide effect on the tree (such as a
 libc header change), you should run `make checkbuild`. A regular `make` will
@@ -218,8 +211,7 @@
 `make checkbuild` is enough.
 
 
-Running the tests
------------------
+## Running the tests
 
 The tests are all built from the tests/ directory.
 
@@ -285,8 +277,7 @@
     $ ./tests/run-on-host.sh glibc
 
 
-Gathering test coverage
------------------------
+## Gathering test coverage
 
 For either host or target coverage, you must first:
 
@@ -319,8 +310,7 @@
 The coverage report is now available at `covreport/index.html`.
 
 
-Attaching GDB to the tests
---------------------------
+## Attaching GDB to the tests
 
 Bionic's test runner will run each test in its own process by default to prevent
 tests failures from impacting other tests. This also has the added benefit of
@@ -330,7 +320,6 @@
 each test from being forked, run the tests with the flag `--no-isolate`.
 
 
-32-bit ABI bugs
----------------
+## 32-bit ABI bugs
 
 See [32-bit ABI bugs](docs/32-bit-abi.md).
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
index 842f7cb..bf8b10d 100644
--- a/benchmarks/Android.bp
+++ b/benchmarks/Android.bp
@@ -40,11 +40,13 @@
         "time_benchmark.cpp",
         "unistd_benchmark.cpp",
     ],
-    shared_libs: ["libtinyxml2"],
+    shared_libs: ["liblog"],
     static_libs: [
         "libbase",
         "libBionicBenchmarksUtils",
+        "libtinyxml2",
     ],
+    stl: "libc++_static",
 }
 
 cc_defaults {
diff --git a/benchmarks/README.md b/benchmarks/README.md
index b3f0c3d..2616a51 100644
--- a/benchmarks/README.md
+++ b/benchmarks/README.md
@@ -13,8 +13,8 @@
     $ mma
     $ adb remount
     $ adb sync
-    $ adb shell /data/nativetest/bionic-benchmarks/bionic-benchmarks
-    $ adb shell /data/nativetest64/bionic-benchmarks/bionic-benchmarks
+    $ adb shell /data/benchmarktest/bionic-benchmarks/bionic-benchmarks
+    $ adb shell /data/benchmarktest64/bionic-benchmarks/bionic-benchmarks
 
 When operated without specifying an xml file, the default is to run all
 of the benchmarks in alphabetical order.
diff --git a/benchmarks/stdlib_benchmark.cpp b/benchmarks/stdlib_benchmark.cpp
index 880bc1d..7330dc4 100644
--- a/benchmarks/stdlib_benchmark.cpp
+++ b/benchmarks/stdlib_benchmark.cpp
@@ -18,17 +18,24 @@
 #include <langinfo.h>
 #include <locale.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 #include <benchmark/benchmark.h>
 #include "util.h"
 
 static void BM_stdlib_malloc_free(benchmark::State& state) {
   const size_t nbytes = state.range(0);
+  int pagesize = getpagesize();
 
-  void* c;
-  while (state.KeepRunning()) {
-    c = malloc(nbytes);
-    free(c);
+  void* ptr;
+  for (auto _ : state) {
+    ptr = malloc(nbytes);
+    // Make the entire allocation resident.
+    uint8_t* data = reinterpret_cast<uint8_t*>(ptr);
+    for (size_t i = 0; i < nbytes; i += pagesize) {
+      data[i] = 1;
+    }
+    free(ptr);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
@@ -70,7 +77,7 @@
   buf[l++] = 0;
 
   volatile size_t c __attribute__((unused)) = 0;
-  while (state.KeepRunning()) {
+  for (auto _ : state) {
     c = mbstowcs(widebuf_aligned, buf_aligned, 500000);
   }
 
@@ -110,7 +117,7 @@
   buf[l++] = 0;
 
   wchar_t wc = 0;
-  while (state.KeepRunning()) {
+  for (auto _ : state) {
     for (j = 0; buf_aligned[j]; j+=mbrtowc(&wc, buf_aligned + j, 4, nullptr)) {
     }
   }
@@ -120,42 +127,42 @@
 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_mbrtowc, "0");
 
 void BM_stdlib_atoi(benchmark::State& state) {
-  while (state.KeepRunning()) {
+  for (auto _ : state) {
     benchmark::DoNotOptimize(atoi(" -123"));
   }
 }
 BIONIC_BENCHMARK(BM_stdlib_atoi);
 
 void BM_stdlib_atol(benchmark::State& state) {
-  while (state.KeepRunning()) {
+  for (auto _ : state) {
     benchmark::DoNotOptimize(atol(" -123"));
   }
 }
 BIONIC_BENCHMARK(BM_stdlib_atol);
 
 void BM_stdlib_strtol(benchmark::State& state) {
-  while (state.KeepRunning()) {
+  for (auto _ : state) {
     benchmark::DoNotOptimize(strtol(" -123", nullptr, 0));
   }
 }
 BIONIC_BENCHMARK(BM_stdlib_strtol);
 
 void BM_stdlib_strtoll(benchmark::State& state) {
-  while (state.KeepRunning()) {
+  for (auto _ : state) {
     benchmark::DoNotOptimize(strtoll(" -123", nullptr, 0));
   }
 }
 BIONIC_BENCHMARK(BM_stdlib_strtoll);
 
 void BM_stdlib_strtoul(benchmark::State& state) {
-  while (state.KeepRunning()) {
+  for (auto _ : state) {
     benchmark::DoNotOptimize(strtoul(" -123", nullptr, 0));
   }
 }
 BIONIC_BENCHMARK(BM_stdlib_strtoul);
 
 void BM_stdlib_strtoull(benchmark::State& state) {
-  while (state.KeepRunning()) {
+  for (auto _ : state) {
     benchmark::DoNotOptimize(strtoull(" -123", nullptr, 0));
   }
 }
diff --git a/benchmarks/tests/interface_test.cpp b/benchmarks/tests/interface_test.cpp
index 89b6011..8e0e4f2 100644
--- a/benchmarks/tests/interface_test.cpp
+++ b/benchmarks/tests/interface_test.cpp
@@ -540,6 +540,15 @@
     "BM_string_strlen/32768/0/iterations:1\n"
     "BM_string_strlen/65536/0/iterations:1\n"
     "BM_string_strlen/131072/0/iterations:1\n"
+    "BM_string_strncmp/8/0/0/iterations:1\n"
+    "BM_string_strncmp/64/0/0/iterations:1\n"
+    "BM_string_strncmp/512/0/0/iterations:1\n"
+    "BM_string_strncmp/1024/0/0/iterations:1\n"
+    "BM_string_strncmp/8192/0/0/iterations:1\n"
+    "BM_string_strncmp/16384/0/0/iterations:1\n"
+    "BM_string_strncmp/32768/0/0/iterations:1\n"
+    "BM_string_strncmp/65536/0/0/iterations:1\n"
+    "BM_string_strncmp/131072/0/0/iterations:1\n"
     "BM_string_strstr/8/0/0/iterations:1\n"
     "BM_string_strstr/64/0/0/iterations:1\n"
     "BM_string_strstr/512/0/0/iterations:1\n"
diff --git a/docs/fdsan.md b/docs/fdsan.md
new file mode 100644
index 0000000..0e6783d
--- /dev/null
+++ b/docs/fdsan.md
@@ -0,0 +1,371 @@
+## fdsan
+
+[TOC]
+
+### Background
+*What problem is fdsan trying to solve? Why should I care?*
+
+fdsan (file descriptor sanitizer) detects mishandling of file descriptor ownership, which tend to manifest as *use-after-close* and *double-close*. These errors are direct analogues of the memory allocation *use-after-free* and *double-free* bugs, but tend to be much more difficult to diagnose and fix. With `malloc` and `free`, implementations have free reign to detect errors and abort on double free. File descriptors, on the other hand, are mandated by the POSIX standard to be allocated with the lowest available number being returned for new allocations. As a result, many file descriptor bugs can *never* be noticed on the thread on which the error occurred, and will manifest as "impossible" behavior on another thread.
+
+For example, given two threads running the following code:
+```cpp
+void thread_one() {
+    int fd = open("/dev/null", O_RDONLY);
+    close(fd);
+    close(fd);
+}
+
+void thread_two() {
+    while (true) {
+        int fd = open("log", O_WRONLY | O_APPEND);
+        if (write(fd, "foo", 3) != 3) {
+            err(1, "write failed!");
+        }
+    }
+}
+```
+the following interleaving is possible:
+```cpp
+thread one                                thread two
+open("/dev/null", O_RDONLY) = 123
+close(123) = 0
+                                          open("log", O_WRONLY | APPEND) = 123
+close(123) = 0
+                                          write(123, "foo", 3) = -1 (EBADF)
+                                          err(1, "write failed!")
+```
+
+Assertion failures are probably the most innocuous result that can arise from these bugs: silent data corruption [[1](#footnotes), [2](#footnotes)] or security vulnerabilities are also possible (e.g. suppose thread two was saving user data to disk when a third thread came in and opened a socket to the Internet).
+
+### Design
+*What does fdsan do?*
+
+fdsan attempts to detect and/or prevent file descriptor mismanagement by enforcing file descriptor ownership. Like how most memory allocations can have their ownership handled by types such as `std::unique_ptr`, almost all file descriptors can be associated with a unique owner which is responsible for their closure. fdsan provides functions to associate a file descriptor with an owner; if someone tries to close a file descriptor that they don't own, depending on configuration, either a warning is emitted, or the process aborts.
+
+The way this is implemented is by providing functions to set a 64-bit closure tag on a file descriptor. The tag consists of an 8-bit type byte that identifies the type of the owner (`enum android_fdan_owner_type` in [`<android/fdsan.h>`](https://android.googlesource.com/platform/bionic/+/master/libc/include/android/fdsan.h)), and a 56-bit value. The value should ideally be something that uniquely identifies the object (object address for native objects and `System.identityHashCode` for Java objects), but in cases where it's hard to derive an identifier for the "owner" that should close a file descriptor, even using the same value for all file descriptors in the module can be useful, since it'll catch other code that closes your file descriptors.
+
+If a file descriptor that's been marked with a tag is closed with an incorrect tag, or without a tag, we know something has gone wrong, and can generate diagnostics or abort.
+
+### Enabling fdsan (as a user)
+*How do I use fdsan?*
+
+fdsan has four severity levels:
+ - disabled (`ANDROID_FDSAN_ERROR_LEVEL_DISABLED`)
+ - warn-once (`ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE`)
+   - Upon detecting an error, emit a warning to logcat, generate a tombstone, and then continue execution with fdsan disabled.
+ - warn-always (`ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS`)
+   - Same as warn-once, except without disabling after the first warning.
+ - fatal (`ANDROID_FDSAN_ERROR_LEVEL_FATAL`)
+   - Abort upon detecting an error.
+
+In Android Q, fdsan has a global default of warn-once. fdsan can be made more or less strict at runtime via the `android_fdsan_set_error_level` function in [`<android/fdsan.h>`](https://android.googlesource.com/platform/bionic/+/master/libc/include/android/fdsan.h).
+
+The likelihood of fdsan catching a file descriptor error is proportional to the percentage of file descriptors in your process that are tagged with an owner.
+
+### Using fdsan to fix a bug
+*No, really, how do I use fdsan?*
+
+Let's look at a simple contrived example that uses sleeps to force a particular interleaving of thread execution.
+
+```cpp
+#include <err.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <thread>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+
+using namespace std::chrono_literals;
+using std::this_thread::sleep_for;
+
+void victim() {
+  sleep_for(300ms);
+  int fd = dup(STDOUT_FILENO);
+  sleep_for(200ms);
+  ssize_t rc = write(fd, "good\n", 5);
+  if (rc == -1) {
+    err(1, "good failed to write?!");
+  }
+  close(fd);
+}
+
+void bystander() {
+  sleep_for(100ms);
+  int fd = dup(STDOUT_FILENO);
+  sleep_for(300ms);
+  close(fd);
+}
+
+void offender() {
+  int fd = dup(STDOUT_FILENO);
+  close(fd);
+  sleep_for(200ms);
+  close(fd);
+}
+
+int main() {
+  std::vector<std::thread> threads;
+  for (auto function : { victim, bystander, offender }) {
+    threads.emplace_back(function);
+  }
+  for (auto& thread : threads) {
+    thread.join();
+  }
+}
+```
+
+When running the program, the threads' executions will be interleaved as follows:
+
+```cpp
+// victim                         bystander                       offender
+                                                                  int fd = dup(1); // 3
+                                                                  close(3);
+                                  int fd = dup(1); // 3
+                                                                  close(3);
+int fd = dup(1); // 3
+                                  close(3);
+write(3, "good\n") = 😞;
+```
+
+which results in the following output:
+
+    fdsan_test: good failed to write?!: Bad file descriptor
+
+This implies that either we're accidentally closing out file descriptor too early, or someone else is helpfully closing it for us. Let's use `android::base::unique_fd` in `victim` to guard the file descriptor with fdsan:
+
+```diff
+--- a/fdsan_test.cpp
++++ b/fdsan_test.cpp
+@@ -12,13 +12,12 @@ using std::this_thread::sleep_for;
+
+ void victim() {
+   sleep_for(200ms);
+-  int fd = dup(STDOUT_FILENO);
++  android::base::unique_fd fd(dup(STDOUT_FILENO));
+   sleep_for(200ms);
+   ssize_t rc = write(fd, "good\n", 5);
+   if (rc == -1) {
+     err(1, "good failed to write?!");
+   }
+-  close(fd);
+ }
+
+ void bystander() {
+```
+
+Now that we've guarded the file descriptor with fdsan, we should be able to find where the double close is:
+
+```
+pid: 25587, tid: 25589, name: fdsan_test  >>> fdsan_test <<<
+signal 35 (<debuggerd signal>), code -1 (SI_QUEUE), fault addr --------
+Abort message: 'attempted to close file descriptor 3, expected to be unowned, actually owned by unique_fd 0x7bf15dc448'
+    x0  0000000000000000  x1  00000000000063f5  x2  0000000000000023  x3  0000007bf14de338
+    x4  0000007bf14de3b8  x5  3463643531666237  x6  3463643531666237  x7  3834346364353166
+    x8  00000000000000f0  x9  0000000000000000  x10 0000000000000059  x11 0000000000000035
+    x12 0000007bf1bebcfa  x13 0000007bf14ddf0a  x14 0000007bf14ddf0a  x15 0000000000000000
+    x16 0000007bf1c33048  x17 0000007bf1ba9990  x18 0000000000000000  x19 00000000000063f3
+    x20 00000000000063f5  x21 0000007bf14de588  x22 0000007bf1f1b864  x23 0000000000000001
+    x24 0000007bf14de130  x25 0000007bf13e1000  x26 0000007bf1f1f580  x27 0000005ab43ab8f0
+    x28 0000000000000000  x29 0000007bf14de400
+    sp  0000007bf14ddff0  lr  0000007bf1b5fd6c  pc  0000007bf1b5fd90
+
+backtrace:
+    #00 pc 0000000000008d90  /system/lib64/libc.so (fdsan_error(char const*, ...)+384)
+    #01 pc 0000000000008ba8  /system/lib64/libc.so (android_fdsan_close_with_tag+632)
+    #02 pc 00000000000092a0  /system/lib64/libc.so (close+16)
+    #03 pc 00000000000003e4  /system/bin/fdsan_test (bystander()+84)
+    #04 pc 0000000000000918  /system/bin/fdsan_test
+    #05 pc 000000000006689c  /system/lib64/libc.so (__pthread_start(void*)+36)
+    #06 pc 000000000000712c  /system/lib64/libc.so (__start_thread+68)
+```
+
+...in the obviously correct bystander? What's going on here?
+
+The reason for this is (hopefully!) not a bug in fdsan, and will commonly be seen when tracking down double-closes in processes that have sparse fdsan coverage. What actually happened is that the culprit closed `bystander`'s file descriptor between its open and close, which resulted in `bystander` being blamed for closing `victim`'s fd. If we store `bystander`'s fd in a `unique_fd` as well, we should get something more useful:
+```diff
+--- a/tmp/fdsan_test.cpp
++++ b/tmp/fdsan_test.cpp
+@@ -23,9 +23,8 @@ void victim() {
+
+ void bystander() {
+   sleep_for(100ms);
+-  int fd = dup(STDOUT_FILENO);
++  android::base::unique_fd fd(dup(STDOUT_FILENO));
+   sleep_for(200ms);
+-  close(fd);
+ }
+```
+giving us:
+```
+pid: 25779, tid: 25782, name: fdsan_test  >>> fdsan_test <<<
+signal 35 (<debuggerd signal>), code -1 (SI_QUEUE), fault addr --------
+Abort message: 'attempted to close file descriptor 3, expected to be unowned, actually owned by unique_fd 0x6fef9ff448'
+    x0  0000000000000000  x1  00000000000064b6  x2  0000000000000023  x3  0000006fef901338
+    x4  0000006fef9013b8  x5  3466663966656636  x6  3466663966656636  x7  3834346666396665
+    x8  00000000000000f0  x9  0000000000000000  x10 0000000000000059  x11 0000000000000039
+    x12 0000006ff0055cfa  x13 0000006fef900f0a  x14 0000006fef900f0a  x15 0000000000000000
+    x16 0000006ff009d048  x17 0000006ff0013990  x18 0000000000000000  x19 00000000000064b3
+    x20 00000000000064b6  x21 0000006fef901588  x22 0000006ff04ff864  x23 0000000000000001
+    x24 0000006fef901130  x25 0000006fef804000  x26 0000006ff0503580  x27 0000006368aa18f8
+    x28 0000000000000000  x29 0000006fef901400
+    sp  0000006fef900ff0  lr  0000006feffc9d6c  pc  0000006feffc9d90
+
+backtrace:
+    #00 pc 0000000000008d90  /system/lib64/libc.so (fdsan_error(char const*, ...)+384)
+    #01 pc 0000000000008ba8  /system/lib64/libc.so (android_fdsan_close_with_tag+632)
+    #02 pc 00000000000092a0  /system/lib64/libc.so (close+16)
+    #03 pc 000000000000045c  /system/bin/fdsan_test (offender()+68)
+    #04 pc 0000000000000920  /system/bin/fdsan_test
+    #05 pc 000000000006689c  /system/lib64/libc.so (__pthread_start(void*)+36)
+    #06 pc 000000000000712c  /system/lib64/libc.so (__start_thread+68)
+```
+
+Hooray!
+
+In a real application, things are probably not going to be as detectable or reproducible as our toy example, which is a good reason to try to maximize the usage of fdsan-enabled types like `unique_fd` and `ParcelFileDescriptor`, to improve the odds that double closes in other code get detected.
+
+### Enabling fdsan (as a C++ library implementer)
+
+fdsan operates via two main primitives. `android_fdsan_exchange_owner_tag` modifies a file descriptor's close tag, and `android_fdsan_close_with_tag` closes a file descriptor with its tag. In the `<android/fdsan.h>` header, these are marked with `__attribute__((weak))`, so instead of passing down the platform version from JNI, availability of the functions can be queried directly. An example implementation of unique_fd follows:
+
+```cpp
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <android/fdsan.h>
+#include <unistd.h>
+
+#include <utility>
+
+struct unique_fd {
+    unique_fd() = default;
+
+    explicit unique_fd(int fd) {
+        reset(fd);
+    }
+
+    unique_fd(const unique_fd& copy) = delete;
+    unique_fd(unique_fd&& move) {
+        *this = std::move(move);
+    }
+
+    ~unique_fd() {
+        reset();
+    }
+
+    unique_fd& operator=(const unique_fd& copy) = delete;
+    unique_fd& operator=(unique_fd&& move) {
+        if (this == &move) {
+            return *this;
+        }
+
+        reset();
+
+        if (move.fd_ != -1) {
+            fd_ = move.fd_;
+            move.fd_ = -1;
+
+            // Acquire ownership from the moved-from object.
+            exchange_tag(fd_, move.tag(), tag());
+        }
+
+        return *this;
+    }
+
+    int get() { return fd_; }
+
+    int release() {
+        if (fd_ == -1) {
+            return -1;
+        }
+
+        int fd = fd_;
+        fd_ = -1;
+
+        // Release ownership.
+        exchange_tag(fd, tag(), 0);
+        return fd;
+    }
+
+    void reset(int new_fd = -1) {
+        if (fd_ != -1) {
+            close(fd_, tag());
+            fd_ = -1;
+        }
+
+        if (new_fd != -1) {
+            fd_ = new_fd;
+
+            // Acquire ownership of the presumably unowned fd.
+            exchange_tag(fd_, 0, tag());
+        }
+    }
+
+  private:
+    int fd_ = -1;
+
+    // The obvious choice of tag to use is the address of the object.
+    uint64_t tag() {
+        return reinterpret_cast<uint64_t>(this);
+    }
+
+    // These functions are marked with __attribute__((weak)), so that their
+    // availability can be determined at runtime. These wrappers will use them
+    // if available, and fall back to no-ops or regular close on pre-Q devices.
+    static void exchange_tag(int fd, uint64_t old_tag, uint64_t new_tag) {
+        if (android_fdsan_exchange_owner_tag) {
+            android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
+        }
+    }
+
+    static int close(int fd, uint64_t tag) {
+        if (android_fdsan_close_with_tag) {
+            return android_fdsan_close_with_tag(fd, tag);
+        } else {
+            return ::close(fd);
+        }
+    }
+};
+```
+
+### Frequently seen bugs
+ * Native APIs not making it clear when they take ownership of a file descriptor. <br/>
+   * Solution: accept `unique_fd` instead of `int` in functions that take ownership.
+   * [Example one](https://android-review.googlesource.com/c/platform/system/core/+/721985), [two](https://android-review.googlesource.com/c/platform/frameworks/native/+/709451)
+ * Receiving a `ParcelFileDescriptor` via Intent, and then passing it into JNI code that ends up calling close on it. <br/>
+   * Solution: ¯\\\_(ツ)\_/¯. Use fdsan?
+   * [Example one](https://android-review.googlesource.com/c/platform/system/bt/+/710104), [two](https://android-review.googlesource.com/c/platform/frameworks/base/+/732305)
+
+### Footnotes
+1. [How To Corrupt An SQLite Database File](https://www.sqlite.org/howtocorrupt.html#_continuing_to_use_a_file_descriptor_after_it_has_been_closed)
+
+2. [<b><i>50%</i></b> of Facebook's iOS crashes caused by a file descriptor double close leading to SQLite database corruption](https://code.fb.com/ios/debugging-file-corruption-on-ios/)
diff --git a/docs/status.md b/docs/status.md
index e41baa6..0106ccd 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -27,7 +27,7 @@
 Missing functionality:
   * `<aio.h>`
   * `<wordexp.h>`
-  * Thread cancellation
+  * Thread cancellation (`pthread_cancel`).
   * Robust mutexes
 
 Run `./libc/tools/check-symbols-glibc.py` in bionic/ for the current
@@ -39,7 +39,14 @@
 
 New libc functions in Q (API level 29):
   * `timespec_get` (C11 `<time.h>` addition)
+  * `reallocarray` (BSD/GNU extension in `<malloc.h>` and `<stdlib.h>`)
   * `res_randomid` (in `<resolv.h>`)
+  * `pthread_sigqueue` (GNU extension)
+
+New libc behavior in Q (API level 29):
+  * Whole printf family now supports the GNU `%m` extension, rather than a special-case hack in `syslog`
+  * `popen` now always uses `O_CLOEXEC`, not just with the `e` extension
+  * Bug fixes to handling of UTF-8 U+fffe/U+ffff and code points above U+10ffff
 
 New libc functions in P (API level 28):
   * `__freading`/`__fwriting` (completing <stdio_ext.h>)
diff --git a/libc/Android.bp b/libc/Android.bp
index fe65ace..cc0a2bb 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -189,7 +189,6 @@
 
         "upstream-netbsd/lib/libc/isc/ev_streams.c",
         "upstream-netbsd/lib/libc/isc/ev_timers.c",
-        "upstream-netbsd/lib/libc/resolv/mtctxres.c",
     ],
 
     cflags: [
@@ -480,7 +479,6 @@
         "upstream-openbsd/lib/libc/stdlib/labs.c",
         "upstream-openbsd/lib/libc/stdlib/llabs.c",
         "upstream-openbsd/lib/libc/stdlib/lsearch.c",
-        "upstream-openbsd/lib/libc/stdlib/reallocarray.c",
         "upstream-openbsd/lib/libc/stdlib/remque.c",
         "upstream-openbsd/lib/libc/stdlib/setenv.c",
         "upstream-openbsd/lib/libc/stdlib/tfind.c",
@@ -1298,6 +1296,7 @@
         "bionic/getpid.cpp",
         "bionic/getpriority.cpp",
         "bionic/gettid.cpp",
+        "bionic/get_device_api_level.cpp",
         "bionic/grp_pwd.cpp",
         "bionic/grp_pwd_file.cpp",
         "bionic/iconv.cpp",
@@ -1858,6 +1857,7 @@
             cflags: ["-fPIC"],
         },
     },
+    stl: "none",
 }
 
 // crt obj files
diff --git a/libc/NOTICE b/libc/NOTICE
index 486c615..5cce4d4 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -4738,22 +4738,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
-
-Permission to use, copy, modify, and distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
--------------------------------------------------------------------
-
 Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
 
 Permission to use, copy, modify, and distribute this software for any
diff --git a/libc/SECCOMP_WHITELIST_APP.TXT b/libc/SECCOMP_WHITELIST_APP.TXT
index faa2d63..9aa4260 100644
--- a/libc/SECCOMP_WHITELIST_APP.TXT
+++ b/libc/SECCOMP_WHITELIST_APP.TXT
@@ -25,17 +25,10 @@
 #
 # This file is processed by a python script named genseccomp.py.
 
-# Needed for debugging 32-bit Chrome
-int	pipe:pipe(int pipefd[2])	arm,x86,mips
-
 # b/34651972
 int	access:access(const char *pathname, int mode)	arm,x86,mips
 int	stat64:stat64(const char*, struct stat64*)	arm,x86,mips
 
-# b/34813887
-int	open:open(const char *path, int oflag, ... ) arm,x86,x86_64,mips
-int	getdents:getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count) arm,x86,x86_64,mips
-
 # b/34719286
 int	eventfd:eventfd(unsigned int initval, int flags)	arm,x86,mips
 
diff --git a/libc/SECCOMP_WHITELIST_COMMON.TXT b/libc/SECCOMP_WHITELIST_COMMON.TXT
index 60568e6..2faa559 100644
--- a/libc/SECCOMP_WHITELIST_COMMON.TXT
+++ b/libc/SECCOMP_WHITELIST_COMMON.TXT
@@ -51,6 +51,13 @@
 # b/34763393
 int	seccomp:seccomp(unsigned int operation, unsigned int flags, void *args)	all
 
+# Needed for debugging 32-bit Chrome
+int	pipe:pipe(int pipefd[2])	arm,x86,mips
+
+# b/34813887
+int	open:open(const char *path, int oflag, ... ) arm,x86,x86_64,mips
+int	getdents:getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count) arm,x86,x86_64,mips
+
 # syscalls needed to boot android
 int	sigreturn:sigreturn(unsigned long __unused)	arm,x86,mips
 
@@ -59,6 +66,9 @@
 # already allowed.
 ssize_t	readlink:readlink(const char *path, char *buf, size_t bufsiz)	arm,x86,x86_64,mips
 
+# Probed for and conditionally used by ART.
+int membarrier(int cmd, int flags) all
+
 # Useful new syscalls which we don't yet use in bionic.
 int sched_getattr(pid_t pid, struct sched_attr* attr, unsigned int flags) all
 int sched_setattr(pid_t pid, struct sched_attr* attr, unsigned int size, unsigned int flags) all
diff --git a/libc/arch-arm64/bionic/setjmp.S b/libc/arch-arm64/bionic/setjmp.S
index ee618b1..5e62c28 100644
--- a/libc/arch-arm64/bionic/setjmp.S
+++ b/libc/arch-arm64/bionic/setjmp.S
@@ -191,6 +191,28 @@
   bne __bionic_setjmp_checksum_mismatch
 #endif
 
+#if __has_feature(hwaddress_sanitizer)
+  stp x0, x30, [sp, #-16]!
+  .cfi_adjust_cfa_offset 16
+  .cfi_rel_offset x0, 0
+  .cfi_rel_offset x30, 8
+  mov x19, x1 // Save 'value'.
+
+  // load and unmangle destination SP
+  ldr x2, [x0, #(_JB_SIGFLAG * 8)]
+  bic x2, x2, #1
+  ldr x0, [x0, #(_JB_X30_SP  * 8 + 8)]
+  eor x0, x0, x2
+  bl __hwasan_handle_longjmp
+
+  mov x1, x19 // Restore 'value'.
+  // Restore original x0 and lr.
+  ldp x0, x30, [sp], #16
+  .cfi_adjust_cfa_offset -16
+  .cfi_restore x0
+  .cfi_restore x30
+#endif
+
   // Do we need to restore the signal mask?
   ldr x2, [x0, #(_JB_SIGFLAG * 8)]
   tbz w2, #0, 1f
diff --git a/libc/arch-arm64/generic/bionic/__memcpy_chk.S b/libc/arch-arm64/generic/bionic/__memcpy_chk.S
index 4217775..a6eeca4 100644
--- a/libc/arch-arm64/generic/bionic/__memcpy_chk.S
+++ b/libc/arch-arm64/generic/bionic/__memcpy_chk.S
@@ -30,8 +30,11 @@
 
 ENTRY(__memcpy_chk)
   cmp x2, x3
-  bls memcpy
+  // Direct b.ls memcpy may not have enough range
+  b.hi .L_memcpy_chk_fail
+  b memcpy
 
+.L_memcpy_chk_fail:
   // Preserve for accurate backtrace.
   stp x29, x30, [sp, -16]!
   .cfi_def_cfa_offset 16
diff --git a/libc/bionic/NetdClient.cpp b/libc/bionic/NetdClient.cpp
index a1071d2..a5c519e 100644
--- a/libc/bionic/NetdClient.cpp
+++ b/libc/bionic/NetdClient.cpp
@@ -24,6 +24,8 @@
 
 #include <dlfcn.h>
 #include <pthread.h>
+#include <string.h>
+#include <unistd.h>
 
 template <typename FunctionType>
 static void netdClientInitFunction(void* handle, const char* symbol, FunctionType* function) {
@@ -35,6 +37,14 @@
 }
 
 static void netdClientInitImpl() {
+    // Prevent netd from looping back fwmarkd connections to itself. It would work, but it's
+    // a deadlock hazard and unnecessary overhead for the resolver.
+    if (getuid() == 0 && strcmp(basename(getprogname()), "netd") == 0) {
+        async_safe_format_log(ANDROID_LOG_INFO, "netdClient",
+                              "Skipping libnetd_client init since *we* are netd");
+        return;
+    }
+
     void* netdClientHandle = dlopen("libnetd_client.so", RTLD_NOW);
     if (netdClientHandle == NULL) {
         // If the library is not available, it's not an error. We'll just use
@@ -54,6 +64,6 @@
 
 extern "C" __LIBC_HIDDEN__ void netdClientInit() {
     if (pthread_once(&netdClientInitOnce, netdClientInitImpl)) {
-        async_safe_format_log(ANDROID_LOG_ERROR, "netdClient", "Failed to initialize netd_client");
+        async_safe_format_log(ANDROID_LOG_ERROR, "netdClient", "Failed to initialize libnetd_client");
     }
 }
diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
index 8645df2..758b295 100644
--- a/libc/bionic/__libc_init_main_thread.cpp
+++ b/libc/bionic/__libc_init_main_thread.cpp
@@ -36,12 +36,18 @@
 #include "private/bionic_ssp.h"
 #include "pthread_internal.h"
 
-extern "C" int __set_tls(void* ptr);
 extern "C" int __set_tid_address(int* tid_address);
 
 // Declared in "private/bionic_ssp.h".
 uintptr_t __stack_chk_guard = 0;
 
+static pthread_internal_t main_thread;
+
+__attribute__((no_sanitize("hwaddress")))
+pthread_internal_t* __get_main_thread() {
+  return &main_thread;
+}
+
 // Setup for the main thread. For dynamic executables, this is called by the
 // linker _before_ libc is mapped in memory. This means that all writes to
 // globals from this function will apply to linker-private copies and will not
@@ -62,8 +68,6 @@
   __libc_init_sysinfo(args);
 #endif
 
-  static pthread_internal_t main_thread;
-
   // The -fstack-protector implementation uses TLS, so make sure that's
   // set up before we call any function that might get a stack check inserted.
   // TLS also needs to be set up before errno (and therefore syscalls) can be used.
diff --git a/libc/bionic/abort.cpp b/libc/bionic/abort.cpp
index d2c99a5..c8bba01 100644
--- a/libc/bionic/abort.cpp
+++ b/libc/bionic/abort.cpp
@@ -32,32 +32,9 @@
 #include <sys/syscall.h>
 #include <unistd.h>
 
-// We call tgkill(2) directly instead of raise (or even the libc tgkill wrapper), to reduce the
-// number of uninteresting stack frames at the top of a crash.
-static inline __always_inline void inline_tgkill(pid_t pid, pid_t tid, int sig) {
-#if defined(__arm__)
-  register int r0 __asm__("r0") = pid;
-  register int r1 __asm__("r1") = tid;
-  register int r2 __asm__("r2") = sig;
-  register int r7 __asm__("r7") = __NR_tgkill;
-  __asm__("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r7) : "memory");
-#elif defined(__aarch64__)
-  register long x0 __asm__("x0") = pid;
-  register long x1 __asm__("x1") = tid;
-  register long x2 __asm__("x2") = sig;
-  register long x8 __asm__("x8") = __NR_tgkill;
-  __asm__("svc #0" : "=r"(x0) : "r"(x0), "r"(x1), "r"(x2), "r"(x8) : "memory");
-#else
-  syscall(__NR_tgkill, pid, tid, sig);
-#endif
-}
+#include "private/bionic_inline_raise.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.
   sigset64_t mask;
@@ -65,7 +42,7 @@
   sigdelset64(&mask, SIGABRT);
 
   sigprocmask64(SIG_SETMASK, &mask, nullptr);
-  inline_tgkill(pid, tid, SIGABRT);
+  inline_raise(SIGABRT);
 
   // If SIGABRT is ignored or it's caught and the handler returns,
   // remove the SIGABRT signal handler and raise SIGABRT again.
@@ -73,7 +50,7 @@
   sigaction64(SIGABRT, &sa, nullptr);
 
   sigprocmask64(SIG_SETMASK, &mask, nullptr);
-  inline_tgkill(pid, tid, SIGABRT);
+  inline_raise(SIGABRT);
 
   // If we get this far, just exit.
   _exit(127);
diff --git a/libc/bionic/android_set_abort_message.cpp b/libc/bionic/android_set_abort_message.cpp
index 268c4f3..58f24cf 100644
--- a/libc/bionic/android_set_abort_message.cpp
+++ b/libc/bionic/android_set_abort_message.cpp
@@ -29,6 +29,8 @@
 #include <android/set_abort_message.h>
 
 #include <pthread.h>
+#include <stdint.h>
+#include <stddef.h>
 #include <string.h>
 #include <sys/mman.h>
 
@@ -41,9 +43,32 @@
   size_t size;
   char msg[0];
 };
+static_assert(
+    offsetof(abort_msg_t, msg) == sizeof(size_t),
+    "The in-memory layout of abort_msg_t is not consistent with what libdebuggerd expects.");
+
+struct magic_abort_msg_t {
+  uint64_t magic1;
+  uint64_t magic2;
+  abort_msg_t msg;
+};
+static_assert(offsetof(magic_abort_msg_t, msg) == 2 * sizeof(uint64_t),
+              "The in-memory layout of magic_abort_msg_t is not consistent with what automated "
+              "tools expect.");
 
 abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common.
 
+[[clang::optnone]]
+static void fill_abort_message_magic(magic_abort_msg_t* new_magic_abort_message) {
+  // 128-bit magic for the abort message. Chosen by fair dice roll.
+  // This function is intentionally deoptimized to avoid the magic to be present
+  // in the final binary. This causes clang to only use instructions where parts
+  // of the magic are encoded into immediate arguments for the instructions in
+  // all supported architectures.
+  new_magic_abort_message->magic1 = 0xb18e40886ac388f0ULL;
+  new_magic_abort_message->magic2 = 0xc6dfba755a1de0b5ULL;
+}
+
 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
 void android_set_abort_message(const char* msg) {
   ScopedPthreadMutexLocker locker(&g_abort_msg_lock);
@@ -59,14 +84,15 @@
     return;
   }
 
-  size_t size = sizeof(abort_msg_t) + strlen(msg) + 1;
+  size_t size = sizeof(magic_abort_msg_t) + strlen(msg) + 1;
   void* map = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
   if (map == MAP_FAILED) {
     return;
   }
 
-  abort_msg_t* new_abort_message = reinterpret_cast<abort_msg_t*>(map);
-  new_abort_message->size = size;
-  strcpy(new_abort_message->msg, msg);
-  *__abort_message_ptr = new_abort_message;
+  magic_abort_msg_t* new_magic_abort_message = reinterpret_cast<magic_abort_msg_t*>(map);
+  fill_abort_message_magic(new_magic_abort_message);
+  new_magic_abort_message->msg.size = size;
+  strcpy(new_magic_abort_message->msg.msg, msg);
+  *__abort_message_ptr = &new_magic_abort_message->msg;
 }
diff --git a/libc/bionic/clone.cpp b/libc/bionic/clone.cpp
index b895305..2a6ab41 100644
--- a/libc/bionic/clone.cpp
+++ b/libc/bionic/clone.cpp
@@ -41,6 +41,7 @@
 extern "C" __noreturn void __exit(int status);
 
 // Called from the __bionic_clone assembler to call the thread function then exit.
+__attribute__((no_sanitize("hwaddress")))
 extern "C" __LIBC_HIDDEN__ void __start_thread(int (*fn)(void*), void* arg) {
   BIONIC_STOP_UNWIND;
 
diff --git a/libc/bionic/fdsan.cpp b/libc/bionic/fdsan.cpp
index b5e141a..11ebf52 100644
--- a/libc/bionic/fdsan.cpp
+++ b/libc/bionic/fdsan.cpp
@@ -43,6 +43,7 @@
 #include <sys/system_properties.h>
 
 #include "private/bionic_globals.h"
+#include "private/bionic_inline_raise.h"
 #include "pthread_internal.h"
 
 extern "C" int ___close(int fd);
@@ -200,12 +201,11 @@
       __BIONIC_FALLTHROUGH;
     case ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS:
       // DEBUGGER_SIGNAL
-      sigval abort_msg;
-      abort_msg.sival_ptr = &abort_message;
-      pthread_sigqueue(pthread_self(), __SIGRTMIN + 3, abort_msg);
+      inline_raise(__SIGRTMIN + 3, &abort_message);
       break;
 
     case ANDROID_FDSAN_ERROR_LEVEL_FATAL:
+      inline_raise(SIGABRT);
       abort();
 
     case ANDROID_FDSAN_ERROR_LEVEL_DISABLED:
@@ -249,6 +249,12 @@
       return "sqlite";
     case ANDROID_FDSAN_OWNER_TYPE_ART_FDFILE:
       return "ART FdFile";
+    case ANDROID_FDSAN_OWNER_TYPE_DATAGRAMSOCKETIMPL:
+      return "DatagramSocketImpl";
+    case ANDROID_FDSAN_OWNER_TYPE_SOCKETIMPL:
+      return "SocketImpl";
+    case ANDROID_FDSAN_OWNER_TYPE_ZIPARCHIVE:
+      return "ZipArchive";
 
     case ANDROID_FDSAN_OWNER_TYPE_GENERIC_00:
     default:
diff --git a/libc/bionic/get_device_api_level.cpp b/libc/bionic/get_device_api_level.cpp
new file mode 100644
index 0000000..dd955d6
--- /dev/null
+++ b/libc/bionic/get_device_api_level.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE /* Out of line. */
+#include <bits/get_device_api_level_inlines.h>
diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp
index 136a098..dadda49 100644
--- a/libc/bionic/grp_pwd.cpp
+++ b/libc/bionic/grp_pwd.cpp
@@ -435,7 +435,7 @@
 
   snprintf(state->name_buffer_, sizeof(state->name_buffer_), "oem_%u", uid);
   snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
-  snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
+  snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/vendor/bin/sh");
 
   passwd* pw = &state->passwd_;
   pw->pw_name  = state->name_buffer_;
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 55506a3..38a04f8 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -127,20 +127,25 @@
   exit(slingshot(args.argc, args.argv, args.envp));
 }
 
-#if __has_feature(hwaddress_sanitizer)
+extern "C" void __hwasan_init();
+
 __attribute__((no_sanitize("hwaddress")))
-#endif
 __noreturn void __libc_init(void* raw_args,
                             void (*onexit)(void) __unused,
                             int (*slingshot)(int, char**, char**),
                             structors_array_t const * const structors) {
 #if __has_feature(hwaddress_sanitizer)
-  __hwasan_shadow_init();
+  // Install main thread TLS early. It will be initialized later in __libc_init_main_thread. For now
+  // all we need is access to TLS_SLOT_TSAN.
+  pthread_internal_t* main_thread = __get_main_thread();
+  __set_tls(main_thread->tls);
+  // Initialize HWASan. This sets up TLS_SLOT_TSAN, among other things.
+  __hwasan_init();
+  // We are ready to run HWASan-instrumented code, proceed with libc initialization...
 #endif
   __real_libc_init(raw_args, onexit, slingshot, structors);
 }
 
-
 static uint32_t g_target_sdk_version{__ANDROID_API__};
 
 extern "C" uint32_t android_get_application_target_sdk_version() {
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 5a5ec76..8bf44a1 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -184,6 +184,15 @@
   return Malloc(realloc)(old_mem, bytes);
 }
 
+extern "C" void* reallocarray(void* old_mem, size_t item_count, size_t item_size) {
+  size_t new_size;
+  if (__builtin_mul_overflow(item_count, item_size, &new_size)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return realloc(old_mem, new_size);
+}
+
 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
 extern "C" void* pvalloc(size_t bytes) {
   auto _pvalloc = __libc_globals->malloc_dispatch.pvalloc;
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index 15366af..543fdc5 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -240,17 +240,18 @@
   return 0;
 }
 
+__attribute__((no_sanitize("hwaddress")))
 static int __pthread_start(void* arg) {
   pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(arg);
 
+  __hwasan_thread_enter();
+
   // Wait for our creating thread to release us. This lets it have time to
   // notify gdb about this thread before we start doing anything.
   // This also provides the memory barrier needed to ensure that all memory
   // accesses previously made by the creating thread are visible to us.
   thread->startup_handshake_lock.lock();
 
-  __hwasan_thread_enter();
-
   __init_alternate_signal_stack(thread);
 
   void* result = thread->start_routine(thread->start_routine_arg);
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 1ec201b..65ec5ff 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -151,6 +151,9 @@
   return *__get_thread()->bionic_tls;
 }
 
+extern __LIBC_HIDDEN__ pthread_internal_t* __get_main_thread();
+extern "C" __LIBC_HIDDEN__ int __set_tls(void* ptr);
+
 __LIBC_HIDDEN__ void pthread_key_clean_all(void);
 
 // Address space is precious on LP32, so use the minimum unit: one page.
diff --git a/libc/bionic/syslog.cpp b/libc/bionic/syslog.cpp
index d1a0c5b..6b17d26 100644
--- a/libc/bionic/syslog.cpp
+++ b/libc/bionic/syslog.cpp
@@ -49,8 +49,6 @@
 }
 
 void vsyslog(int priority, const char* fmt, va_list args) {
-  int caller_errno = errno;
-
   // Check whether we're supposed to be logging messages of this priority.
   if ((syslog_priority_mask & LOG_MASK(LOG_PRI(priority))) == 0) {
     return;
@@ -75,48 +73,10 @@
     android_log_priority = ANDROID_LOG_DEBUG;
   }
 
-  // glibc's printf family support %m directly, but our BSD-based one doesn't.
-  // If the format string seems to contain "%m", rewrite it.
-  const char* log_fmt = fmt;
-  if (strstr(fmt, "%m") != nullptr) {
-    size_t dst_len = 1024;
-    char* dst = reinterpret_cast<char*>(malloc(dst_len));
-    log_fmt = dst;
-
-    const char* src = fmt;
-    for (; dst_len > 0 && *src != '\0'; ++src) {
-      if (*src == '%' && *(src + 1) == 'm') {
-        // Expand %m.
-        size_t n = strlcpy(dst, strerror(caller_errno), dst_len);
-        if (n >= dst_len) {
-          n = dst_len;
-        }
-        dst += n;
-        dst_len -= n;
-        ++src;
-      } else if (*src == '%' && *(src + 1) == '%') {
-        // We need to copy pairs of '%'s so the %m test works.
-        if (dst_len <= 2) {
-          break;
-        }
-        *dst++ = '%'; --dst_len;
-        *dst++ = '%'; --dst_len;
-        ++src;
-      } else {
-        *dst++ = *src; --dst_len;
-      }
-    }
-    *dst = '\0';
-  }
-
   // 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);
-
-  if (log_fmt != fmt) {
-    free(const_cast<char*>(log_fmt));
-  }
+  vsnprintf(log_line, sizeof(log_line), fmt, args);
 
   async_safe_format_log(android_log_priority, log_tag, "%s", log_line);
 }
diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h
index 6ed6c0a..ebce900 100644
--- a/libc/include/android/api-level.h
+++ b/libc/include/android/api-level.h
@@ -26,39 +26,80 @@
  * SUCH DAMAGE.
  */
 
-#ifndef ANDROID_API_LEVEL_H
-#define ANDROID_API_LEVEL_H
+#pragma once
+
+/**
+ * @file android/api-level.h
+ * @brief Functions and constants for dealing with multiple API levels.
+ */
 
 #include <sys/cdefs.h>
 
-/*
- * Magic version number for a current development build, which has
- * not yet turned into an official release.
- */
 #ifndef __ANDROID_API_FUTURE__
+/**
+ * Magic version number for an Android OS build which has
+ * not yet turned into an official release,
+ * for comparisons against __ANDROID_API__.
+ */
 #define __ANDROID_API_FUTURE__ 10000
 #endif
 
 #ifndef __ANDROID_API__
+/**
+ * `__ANDROID_API__` is the API level being targeted. For the OS,
+ * this is `__ANDROID_API_FUTURE__`. For the NDK, this is set by the
+ * compiler/build system based on the API level you claimed to target.
+ */
 #define __ANDROID_API__ __ANDROID_API_FUTURE__
 #else
+/**
+ * `__ANDROID_NDK__` is defined for code that's built by the NDK
+ * rather than as part of the OS.
+ */
 #define __ANDROID_NDK__ 1
 #endif
 
+/** Names the Gingerbread API level (9), for comparisons against __ANDROID_API__. */
 #define __ANDROID_API_G__ 9
-#define __ANDROID_API_I__ 14
-#define __ANDROID_API_J__ 16
-#define __ANDROID_API_J_MR1__ 17
-#define __ANDROID_API_J_MR2__ 18
-#define __ANDROID_API_K__ 19
-#define __ANDROID_API_L__ 21
-#define __ANDROID_API_L_MR1__ 22
-#define __ANDROID_API_M__ 23
-#define __ANDROID_API_N__ 24
-#define __ANDROID_API_N_MR1__ 25
-#define __ANDROID_API_O__ 26
-#define __ANDROID_API_O_MR1__ 27
-#define __ANDROID_API_P__ 28
-#define __ANDROID_API_Q__ 29
 
-#endif
+/** Names the Ice-Cream Sandwich API level (14), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_I__ 14
+
+/** Names the Jellybean API level (16), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_J__ 16
+
+/** Names the Jellybean MR1 API level (17), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_J_MR1__ 17
+
+/** Names the Jellybean MR2 API level (18), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_J_MR2__ 18
+
+/** Names the KitKat API level (19), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_K__ 19
+
+/** Names the Lollipop API level (21), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_L__ 21
+
+/** Names the Lollipop MR1 API level (22), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_L_MR1__ 22
+
+/** Names the Marshmallow API level (23), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_M__ 23
+
+/** Names the Nougat API level (24), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_N__ 24
+
+/** Names the Nougat MR1 API level (25), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_N_MR1__ 25
+
+/** Names the Oreo API level (26), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_O__ 26
+
+/** Names the Oreo MR1 API level (27), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_O_MR1__ 27
+
+/** Names the Pie API level (28), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_P__ 28
+
+/** Names the "Q" API level (29), for comparisons against __ANDROID_API__. */
+#define __ANDROID_API_Q__ 29
diff --git a/libc/include/android/fdsan.h b/libc/include/android/fdsan.h
index dc2bbd5..ea7689c 100644
--- a/libc/include/android/fdsan.h
+++ b/libc/include/android/fdsan.h
@@ -114,6 +114,15 @@
 
   /* ART FdFile */
   ANDROID_FDSAN_OWNER_TYPE_ART_FDFILE = 9,
+
+  /* java.net.DatagramSocketImpl */
+  ANDROID_FDSAN_OWNER_TYPE_DATAGRAMSOCKETIMPL = 10,
+
+  /* java.net.SocketImpl */
+  ANDROID_FDSAN_OWNER_TYPE_SOCKETIMPL = 11,
+
+  /* libziparchive's ZipArchive */
+  ANDROID_FDSAN_OWNER_TYPE_ZIPARCHIVE = 12,
 };
 
 /*
diff --git a/libc/include/android/get_device_api_level.h b/libc/include/android/get_device_api_level.h
new file mode 100644
index 0000000..39609da
--- /dev/null
+++ b/libc/include/android/get_device_api_level.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+/**
+ * @file android/get_device_api_level.h
+ * @brief Check the API level of the device we're actually running on.
+ */
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+// This file is implemented as static inlines before API level 29.
+
+/**
+ * Returns the API level of the device we're actually running on, or -1 on failure.
+ * The returned values correspond to the named constants in <android/api-level.h>,
+ * and is equivalent to the Java `Build.VERSION.SDK_INT` API.
+ */
+int android_get_device_api_level() __INTRODUCED_IN(29);
+
+#endif
+
+__END_DECLS
+
+#include <android/legacy_get_device_api_level_inlines.h>
diff --git a/libc/include/android/legacy_get_device_api_level_inlines.h b/libc/include/android/legacy_get_device_api_level_inlines.h
new file mode 100644
index 0000000..b60123c
--- /dev/null
+++ b/libc/include/android/legacy_get_device_api_level_inlines.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+#if __ANDROID_API__ < __ANDROID_API_Q__
+
+#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
+#include <bits/get_device_api_level_inlines.h>
+
+#endif
diff --git a/libc/include/bits/get_device_api_level_inlines.h b/libc/include/bits/get_device_api_level_inlines.h
new file mode 100644
index 0000000..8e17814
--- /dev/null
+++ b/libc/include/bits/get_device_api_level_inlines.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <stdlib.h>
+#include <sys/cdefs.h>
+#include <sys/system_properties.h>
+
+#if !defined(__BIONIC_GET_DEVICE_API_LEVEL_INLINE)
+#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
+#endif
+
+__BEGIN_DECLS
+
+__BIONIC_GET_DEVICE_API_LEVEL_INLINE int android_get_device_api_level() {
+  char value[PROP_VALUE_MAX] = { 0 };
+  if (__system_property_get("ro.build.version.sdk", value) < 1) return -1;
+  int api_level = atoi(value);
+  return (api_level > 0) ? api_level : -1;
+}
+
+__END_DECLS
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 7144224..f5fbedf 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -66,6 +66,18 @@
 void* realloc(void* __ptr, size_t __byte_count) __BIONIC_ALLOC_SIZE(2) __wur;
 
 /**
+ * [reallocarray(3)](http://man7.org/linux/man-pages/man3/realloc.3.html) resizes
+ * allocated memory on the heap.
+ *
+ * Equivalent to `realloc(__ptr, __item_count * __item_size)` but fails if the
+ * multiplication overflows.
+ *
+ * Returns a pointer (which may be different from `__ptr`) to the resized
+ * memory on success and returns a null pointer and sets `errno` on failure.
+ */
+void* reallocarray(void* __ptr, size_t __item_count, size_t __item_size) __BIONIC_ALLOC_SIZE(2, 3) __wur __INTRODUCED_IN(29);
+
+/**
  * [free(3)](http://man7.org/linux/man-pages/man3/free.3.html) deallocates
  * memory on the heap.
  */
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 8fb07f7..a22a8df 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1431,7 +1431,9 @@
     android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
+    android_get_device_api_level;
     pthread_sigqueue;
+    reallocarray;
     timespec_get;
 } LIBC_P;
 
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 8c5eb89..55fd587 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1352,7 +1352,9 @@
     android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
+    android_get_device_api_level;
     pthread_sigqueue;
+    reallocarray;
     timespec_get;
 } LIBC_P;
 
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index c5f0910..304dbb7 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1456,7 +1456,9 @@
     android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
+    android_get_device_api_level;
     pthread_sigqueue;
+    reallocarray;
     timespec_get;
 } LIBC_P;
 
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index fbaf508..397ff72 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1415,7 +1415,9 @@
     android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
+    android_get_device_api_level;
     pthread_sigqueue;
+    reallocarray;
     timespec_get;
 } LIBC_P;
 
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 8c5eb89..55fd587 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1352,7 +1352,9 @@
     android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
+    android_get_device_api_level;
     pthread_sigqueue;
+    reallocarray;
     timespec_get;
 } LIBC_P;
 
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index db86e55..a18657c 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1413,7 +1413,9 @@
     android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
+    android_get_device_api_level;
     pthread_sigqueue;
+    reallocarray;
     timespec_get;
 } LIBC_P;
 
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 8c5eb89..55fd587 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1352,7 +1352,9 @@
     android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
+    android_get_device_api_level;
     pthread_sigqueue;
+    reallocarray;
     timespec_get;
 } LIBC_P;
 
diff --git a/libc/private/bionic_inline_raise.h b/libc/private/bionic_inline_raise.h
new file mode 100644
index 0000000..7223b4e
--- /dev/null
+++ b/libc/private/bionic_inline_raise.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// An inline version of pthread_sigqueue(pthread_self(), ...), to reduce the number of
+// uninteresting stack frames at the top of a crash.
+static inline __always_inline void inline_raise(int sig, void* value = nullptr) {
+  // 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);
+  siginfo_t info = {};
+  info.si_code = SI_QUEUE;
+  info.si_pid = pid;
+  info.si_uid = getuid();
+  info.si_value.sival_ptr = value;
+
+#if defined(__arm__)
+  register long r0 __asm__("r0") = pid;
+  register long r1 __asm__("r1") = tid;
+  register long r2 __asm__("r2") = sig;
+  register long r3 __asm__("r3") = reinterpret_cast<long>(&info);
+  register long r7 __asm__("r7") = __NR_rt_tgsigqueueinfo;
+  __asm__("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r7) : "memory");
+#elif defined(__aarch64__)
+  register long x0 __asm__("x0") = pid;
+  register long x1 __asm__("x1") = tid;
+  register long x2 __asm__("x2") = sig;
+  register long x3 __asm__("x3") = reinterpret_cast<long>(&info);
+  register long x8 __asm__("x8") = __NR_rt_tgsigqueueinfo;
+  __asm__("svc #0" : "=r"(x0) : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x8) : "memory");
+#else
+  syscall(__NR_rt_tgsigqueueinfo, pid, tid, sig, &info);
+#endif
+}
+
diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp
index 71fdd27..d7b69dc 100644
--- a/libc/stdio/stdio.cpp
+++ b/libc/stdio/stdio.cpp
@@ -404,8 +404,7 @@
 }
 __strong_alias(freopen64, freopen);
 
-int fclose(FILE* fp) {
-  CHECK_FP(fp);
+static int __FILE_close(FILE* fp) {
   if (fp->_flags == 0) {
     // Already freed!
     errno = EBADF;
@@ -440,7 +439,11 @@
   fp->_flags = 0;
   return r;
 }
-__strong_alias(pclose, fclose);
+
+int fclose(FILE* fp) {
+  CHECK_FP(fp);
+  return __FILE_close(fp);
+}
 
 int fileno_unlocked(FILE* fp) {
   CHECK_FP(fp);
@@ -459,6 +462,7 @@
 }
 
 void clearerr_unlocked(FILE* fp) {
+  CHECK_FP(fp);
   return __sclearerr(fp);
 }
 
@@ -1235,6 +1239,11 @@
   return fp;
 }
 
+int pclose(FILE* fp) {
+  CHECK_FP(fp);
+  return __FILE_close(fp);
+}
+
 namespace {
 
 namespace phony {
diff --git a/libc/stdio/vfprintf.cpp b/libc/stdio/vfprintf.cpp
index a14963e..d99d09c 100644
--- a/libc/stdio/vfprintf.cpp
+++ b/libc/stdio/vfprintf.cpp
@@ -43,6 +43,7 @@
 #include "printf_common.h"
 
 int FUNCTION_NAME(FILE* fp, const CHAR_TYPE* fmt0, va_list ap) {
+  int caller_errno = errno;
   int n, n2;
   CHAR_TYPE* cp;            /* handy char pointer (short term usage) */
   CHAR_TYPE sign;           /* sign prefix (' ', '+', '-', or \0) */
@@ -451,6 +452,9 @@
         break;
       case 'n':
         __fortify_fatal("%%n not allowed on Android");
+      case 'm':
+        cp = strerror_r(caller_errno, buf, sizeof(buf));
+        goto string;
       case 'O':
         flags |= LONGINT;
         __BIONIC_FALLTHROUGH;
@@ -493,6 +497,7 @@
         } else if ((cp = GETARG(char*)) == nullptr) {
           cp = const_cast<char*>("(null)");
         }
+  string:
         if (prec >= 0) {
           size = CHAR_TYPE_STRNLEN(cp, prec);
         } else {
diff --git a/libc/stdio/vfwprintf.cpp b/libc/stdio/vfwprintf.cpp
index 1c3b80d..dd51eec 100644
--- a/libc/stdio/vfwprintf.cpp
+++ b/libc/stdio/vfwprintf.cpp
@@ -43,6 +43,7 @@
 #include "printf_common.h"
 
 int FUNCTION_NAME(FILE* fp, const CHAR_TYPE* fmt0, va_list ap) {
+  int caller_errno = errno;
   int n, n2;
   CHAR_TYPE* cp;   /* handy char pointer (short term usage) */
   CHAR_TYPE sign;  /* sign prefix (' ', '+', '-', or \0) */
@@ -436,6 +437,17 @@
         break;
       case 'n':
         __fortify_fatal("%%n not allowed on Android");
+      case 'm':
+        free(convbuf);
+        convbuf = helpers::mbsconv(strerror_r(caller_errno,
+                                              reinterpret_cast<char*>(buf), sizeof(buf)), prec);
+        if (convbuf == nullptr) {
+            fp->_flags |= __SERR;
+            goto error;
+        } else {
+            cp = convbuf;
+        }
+        goto string;
       case 'O':
         flags |= LONGINT;
         __BIONIC_FALLTHROUGH;
@@ -474,6 +486,7 @@
             cp = convbuf;
           }
         }
+  string:
         if (prec >= 0) {
           size = CHAR_TYPE_STRNLEN(cp, prec);
         } else {
diff --git a/libc/upstream-freebsd/android/include/freebsd-compat.h b/libc/upstream-freebsd/android/include/freebsd-compat.h
index e646e23..6f7a3f0 100644
--- a/libc/upstream-freebsd/android/include/freebsd-compat.h
+++ b/libc/upstream-freebsd/android/include/freebsd-compat.h
@@ -44,9 +44,6 @@
 /* Redirect internal C library calls to the public function. */
 #define _nanosleep nanosleep
 
-/* FreeBSD has this as API, but we just use it internally. */
-void* reallocarray(void*, size_t, size_t);
-
 /* FreeBSD has this, but we can't really implement it correctly on Linux. */
 #define issetugid() 0
 
diff --git a/libc/upstream-netbsd/android/include/reentrant.h b/libc/upstream-netbsd/android/include/reentrant.h
index 3ca8fd6..e27a87b 100644
--- a/libc/upstream-netbsd/android/include/reentrant.h
+++ b/libc/upstream-netbsd/android/include/reentrant.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _BIONIC_NETBSD_REENTRANT_H_included
-#define _BIONIC_NETBSD_REENTRANT_H_included
+#pragma once
 
 #define _REENTRANT
 
@@ -23,18 +22,10 @@
 #include <signal.h>
 
 //
-// Map NetBSD libc internal locking to pthread locking.
+// Map NetBSD libc internal locking onto regular pthread locking.
 //
 
 #define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
 #define mutex_t pthread_mutex_t
 #define mutex_lock(x) pthread_mutex_lock(x)
 #define mutex_unlock(x) pthread_mutex_unlock(x)
-
-#define RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
-#define rwlock_t pthread_rwlock_t
-#define rwlock_rdlock pthread_rwlock_rdlock
-#define rwlock_unlock pthread_rwlock_unlock
-#define rwlock_wrlock pthread_rwlock_wrlock
-
-#endif
diff --git a/libc/upstream-netbsd/android/include/resolv_mt.h b/libc/upstream-netbsd/android/include/resolv_mt.h
new file mode 100644
index 0000000..664ae93
--- /dev/null
+++ b/libc/upstream-netbsd/android/include/resolv_mt.h
@@ -0,0 +1,4 @@
+#pragma once
+
+// Android never enabled the per-thread code, so this was always static like glibc.
+static char inet_nsap_ntoa_tmpbuf[255*3];
diff --git a/libc/upstream-netbsd/lib/libc/include/resolv_mt.h b/libc/upstream-netbsd/lib/libc/include/resolv_mt.h
deleted file mode 100644
index 73a8dcc..0000000
--- a/libc/upstream-netbsd/lib/libc/include/resolv_mt.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*	$NetBSD: resolv_mt.h,v 1.1.1.3 2009/04/12 16:35:44 christos Exp $	*/
-
-#ifndef _RESOLV_MT_H
-#define _RESOLV_MT_H
-
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-
-/* Access functions for the libresolv private interface */
-
-int	__res_enable_mt(void);
-int	__res_disable_mt(void);
-
-/* Per-thread context */
-
-typedef struct {
-int	no_hosts_fallback_private;
-int	retry_save;
-int	retry_private;
-char	inet_nsap_ntoa_tmpbuf[255*3];
-char	sym_ntos_unname[20];
-char	sym_ntop_unname[20];
-char	p_option_nbuf[40];
-char	p_time_nbuf[40];
-char	precsize_ntoa_retbuf[sizeof "90000000.00"];
-char	loc_ntoa_tmpbuf[sizeof
-"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
-char	p_secstodate_output[15];
-} mtctxres_t;
-
-/* Thread-specific data (TSD) */
-
-mtctxres_t	*___mtctxres(void);
-#define mtctxres	(___mtctxres())
-
-/* Various static data that should be TSD */
-
-#define sym_ntos_unname		(mtctxres->sym_ntos_unname)
-#define sym_ntop_unname		(mtctxres->sym_ntop_unname)
-#define inet_nsap_ntoa_tmpbuf	(mtctxres->inet_nsap_ntoa_tmpbuf)
-#define p_option_nbuf		(mtctxres->p_option_nbuf)
-#define p_time_nbuf		(mtctxres->p_time_nbuf)
-#define precsize_ntoa_retbuf	(mtctxres->precsize_ntoa_retbuf)
-#define loc_ntoa_tmpbuf		(mtctxres->loc_ntoa_tmpbuf)
-#define p_secstodate_output	(mtctxres->p_secstodate_output)
-
-#endif /* _RESOLV_MT_H */
diff --git a/libc/upstream-netbsd/lib/libc/resolv/mtctxres.c b/libc/upstream-netbsd/lib/libc/resolv/mtctxres.c
deleted file mode 100644
index 6e3281a..0000000
--- a/libc/upstream-netbsd/lib/libc/resolv/mtctxres.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*	$NetBSD: mtctxres.c,v 1.4 2007/03/30 20:40:52 ghen Exp $	*/
-
-#include <port_before.h>
-#ifdef DO_PTHREADS
-#include <pthread.h>
-#endif
-#include <errno.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <string.h>
-#include <resolv_mt.h>
-#include <port_after.h>
-
-#ifdef DO_PTHREADS
-static pthread_key_t	key;
-static int		mt_key_initialized = 0;
-
-static int		__res_init_ctx(void);
-static void		__res_destroy_ctx(void *);
-
-#if defined(sun) && !defined(__GNUC__)
-#pragma init	(_mtctxres_init)
-#endif
-#endif
-
-static mtctxres_t	sharedctx;
-
-#ifdef DO_PTHREADS
-/*
- * Initialize the TSD key. By doing this at library load time, we're
- * implicitly running without interference from other threads, so there's
- * no need for locking.
- */
-static void
-_mtctxres_init(void) {
-	int pthread_keycreate_ret;
-
-	pthread_keycreate_ret = pthread_key_create(&key, __res_destroy_ctx);
-	if (pthread_keycreate_ret == 0)
-		mt_key_initialized = 1;
-}
-#endif
-
-/*
- * To support binaries that used the private MT-safe interface in
- * Solaris 8, we still need to provide the __res_enable_mt()
- * and __res_disable_mt() entry points. They're do-nothing routines.
- */
-int
-__res_enable_mt(void) {
-	return (-1);
-}
-
-int
-__res_disable_mt(void) {
-	return (0);
-}
-
-#ifdef DO_PTHREADS
-static int
-__res_init_ctx(void) {
-
-	mtctxres_t	*mt;
-	int		ret;
-
-
-	if (pthread_getspecific(key) != 0) {
-		/* Already exists */
-		return (0);
-	}
-
-	if ((mt = malloc(sizeof (mtctxres_t))) == 0) {
-		errno = ENOMEM;
-		return (-1);
-	}
-
-	memset(mt, 0, sizeof (mtctxres_t));
-
-	if ((ret = pthread_setspecific(key, mt)) != 0) {
-		free(mt);
-		errno = ret;
-		return (-1);
-	}
-
-	return (0);
-}
-
-static void
-__res_destroy_ctx(void *value) {
-
-	mtctxres_t	*mt = (mtctxres_t *)value;
-
-	if (mt != 0)
-		free(mt);
-}
-#endif
-
-mtctxres_t *
-___mtctxres(void) {
-#ifdef DO_PTHREADS
-	mtctxres_t	*mt;
-
-	/*
-	 * This if clause should only be executed if we are linking
-	 * statically.  When linked dynamically _mtctxres_init() should
-	 * be called at binding time due the #pragma above.
-	 */
-	if (!mt_key_initialized) {
-		static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER;
-                if (pthread_mutex_lock(&keylock) == 0) {
-			_mtctxres_init();
-			(void) pthread_mutex_unlock(&keylock);
-		}
-	}
-
-	/*
-	 * If we have already been called in this thread return the existing
-	 * context.  Otherwise recreat a new context and return it.  If
-	 * that fails return a global context.
-	 */
-	if (mt_key_initialized) {
-		if (((mt = pthread_getspecific(key)) != 0) ||
-		    (__res_init_ctx() == 0 &&
-		     (mt = pthread_getspecific(key)) != 0)) {
-			return (mt);
-		}
-	}
-#endif
-	return (&sharedctx);
-}
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index f178149..c99e2ce 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -80,9 +80,6 @@
 __LIBC_HIDDEN__ extern const char* __bionic_get_shell_path();
 #define _PATH_BSHELL __bionic_get_shell_path()
 
-/* OpenBSD has this as API, but we just use it internally. */
-__LIBC_HIDDEN__ void* reallocarray(void*, size_t, size_t);
-
 /* LP32 NDK ctype.h contained references to these. */
 __LIBC32_LEGACY_PUBLIC__ extern const short* _tolower_tab_;
 __LIBC32_LEGACY_PUBLIC__ extern const short* _toupper_tab_;
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/reallocarray.c b/libc/upstream-openbsd/lib/libc/stdlib/reallocarray.c
deleted file mode 100644
index baea252..0000000
--- a/libc/upstream-openbsd/lib/libc/stdlib/reallocarray.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*	$OpenBSD: reallocarray.c,v 1.3 2015/09/13 08:31:47 guenther Exp $	*/
-/*
- * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-/*
- * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
- * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
- */
-#define MUL_NO_OVERFLOW	((size_t)1 << (sizeof(size_t) * 4))
-
-void *
-reallocarray(void *optr, size_t nmemb, size_t size)
-{
-	if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
-	    nmemb > 0 && SIZE_MAX / nmemb < size) {
-		errno = ENOMEM;
-		return NULL;
-	}
-	return realloc(optr, size * nmemb);
-}
-DEF_WEAK(reallocarray);
diff --git a/libm/Android.bp b/libm/Android.bp
index 3b88fa3..6d55967 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -290,13 +290,9 @@
 
         arm64: {
             srcs: [
-                "arm64/ceil.S",
                 "arm64/fenv.c",
-                "arm64/floor.S",
                 "arm64/lrint.S",
-                "arm64/rint.S",
                 "arm64/sqrt.S",
-                "arm64/trunc.S",
             ],
             exclude_srcs: [
                 "upstream-freebsd/lib/msun/src/e_sqrt.c",
diff --git a/libm/arm64/floor.S b/libm/arm64/floor.S
deleted file mode 100644
index ca106bd..0000000
--- a/libm/arm64/floor.S
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2015 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 <private/bionic_asm.h>
-
-ENTRY(floor)
-  frintM d0, d0
-  ret
-END(floor)
-
-ENTRY(floorf)
-  frintM s0, s0
-  ret
-END(floorf)
diff --git a/libm/arm64/rint.S b/libm/arm64/rint.S
deleted file mode 100644
index bf49f5b..0000000
--- a/libm/arm64/rint.S
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2015 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 <private/bionic_asm.h>
-
-ENTRY(rint)
-  frintX d0, d0
-  ret
-END(rint)
-
-ENTRY(rintf)
-  frintX s0, s0
-  ret
-END(rintf)
diff --git a/libm/arm64/trunc.S b/libm/arm64/trunc.S
deleted file mode 100644
index aa0d4bd..0000000
--- a/libm/arm64/trunc.S
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2015 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 <private/bionic_asm.h>
-
-ENTRY(trunc)
-  frintZ d0, d0
-  ret
-END(trunc)
-
-ENTRY(truncf)
-  frintZ s0, s0
-  ret
-END(truncf)
diff --git a/libm/builtins.cpp b/libm/builtins.cpp
index 2ea6305..3b9228c 100644
--- a/libm/builtins.cpp
+++ b/libm/builtins.cpp
@@ -46,6 +46,12 @@
 #endif
 
 #if defined(__aarch64__)
+float ceilf(float x) { return __builtin_ceilf(x); }
+double ceil(double x) { return __builtin_ceil(x); }
+
+float floorf(float x) { return __builtin_floorf(x); }
+double floor(double x) { return __builtin_floor(x); }
+
 float fmaf(float x, float y, float z) { return __builtin_fmaf(x, y, z); }
 double fma(double x, double y, double z) { return __builtin_fma(x, y, z); }
 
@@ -55,6 +61,12 @@
 float fminf(float x, float y) { return __builtin_fminf(x, y); }
 double fmin(double x, double y) { return __builtin_fmin(x, y); }
 
+float rintf(float x) { return __builtin_rintf(x); }
+double rint(double x) { return __builtin_rint(x); }
+
 float roundf(float x) { return __builtin_roundf(x); }
 double round(double x) { return __builtin_round(x); }
+
+float truncf(float x) { return __builtin_truncf(x); }
+double trunc(double x) { return __builtin_trunc(x); }
 #endif
diff --git a/linker/Android.bp b/linker/Android.bp
index db379ba..697c260 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -66,8 +66,8 @@
     include_dirs: ["bionic/libc"],
 }
 
-cc_binary {
-    defaults: ["linux_bionic_supported"],
+filegroup {
+    name: "linker_sources",
     srcs: [
         "dlfcn.cpp",
         "linker.cpp",
@@ -89,49 +89,74 @@
         "linker_utils.cpp",
         "rt.cpp",
     ],
+}
 
+filegroup {
+    name: "linker_sources_arm",
+    srcs: [
+        "arch/arm/begin.S",
+        "linker_exidx_static.c",
+    ],
+}
+
+filegroup {
+    name: "linker_sources_arm64",
+    srcs: [
+        "arch/arm64/begin.S",
+    ],
+}
+
+filegroup {
+    name: "linker_sources_x86",
+    srcs: [
+        "arch/x86/begin.S",
+    ],
+}
+
+filegroup {
+    name: "linker_sources_x86_64",
+    srcs: [
+        "arch/x86_64/begin.S",
+    ],
+}
+
+filegroup {
+    name: "linker_sources_mips",
+    srcs: [
+        "arch/mips/begin.S",
+        "linker_mips.cpp",
+    ],
+}
+
+filegroup {
+    name: "linker_sources_mips64",
+    srcs: [
+        "arch/mips64/begin.S",
+        "linker_mips.cpp",
+    ],
+}
+
+filegroup {
+    name: "linker_version_script",
+    srcs: ["linker.generic.map"],
+}
+
+filegroup {
+    name: "linker_version_script_arm",
+    srcs: ["linker.arm.map"],
+}
+
+cc_defaults {
+    name: "linker_defaults",
     arch: {
         arm: {
-            srcs: [
-                "arch/arm/begin.S",
-                "linker_exidx_static.c",
-            ],
-
             cflags: ["-D__work_around_b_24465209__"],
-            version_script: "linker.arm.map",
-        },
-        arm64: {
-            srcs: ["arch/arm64/begin.S"],
-            version_script: "linker.generic.map",
         },
         x86: {
-            srcs: ["arch/x86/begin.S"],
             cflags: ["-D__work_around_b_24465209__"],
-            version_script: "linker.generic.map",
-        },
-        x86_64: {
-            srcs: ["arch/x86_64/begin.S"],
-            version_script: "linker.generic.map",
-        },
-        mips: {
-            srcs: [
-                "arch/mips/begin.S",
-                "linker_mips.cpp",
-            ],
-            version_script: "linker.generic.map",
-        },
-        mips64: {
-            srcs: [
-                "arch/mips64/begin.S",
-                "linker_mips.cpp",
-            ],
-            version_script: "linker.generic.map",
         },
     },
 
-    // We need to access Bionic private headers in the linker.
-    include_dirs: ["bionic/libc"],
-
     // -shared is used to overwrite the -Bstatic and -static
     // flags triggered by LOCAL_FORCE_STATIC_EXECUTABLE.
     // This dynamic linker is actually a shared object linked with static libraries.
@@ -185,6 +210,57 @@
     // just for this module
     nocrt: true,
 
+    static_executable: true,
+
+    // Leave the symbols in the shared library so that stack unwinders can produce
+    // meaningful name resolution.
+    strip: {
+        keep_symbols: true,
+    },
+
+    // Insert an extra objcopy step to add prefix to symbols. This is needed to prevent gdb
+    // looking up symbols in the linker by mistake.
+    prefix_symbols: "__dl_",
+
+    sanitize: {
+        hwaddress: false,
+    },
+}
+
+cc_binary {
+    defaults: ["linux_bionic_supported", "linker_defaults"],
+    srcs: [ ":linker_sources" ],
+
+    arch: {
+        arm: {
+            srcs: [ ":linker_sources_arm" ],
+            version_script: ":linker_version_script_arm",
+        },
+        arm64: {
+            srcs: [":linker_sources_arm64"],
+            version_script: ":linker_version_script",
+        },
+        x86: {
+            srcs: [":linker_sources_x86"],
+            version_script: ":linker_version_script",
+        },
+        x86_64: {
+            srcs: [":linker_sources_x86_64"],
+            version_script: ":linker_version_script",
+        },
+        mips: {
+            srcs: [":linker_sources_mips"],
+            version_script: ":linker_version_script",
+        },
+        mips64: {
+            srcs: [":linker_sources_mips64"],
+            version_script: ":linker_version_script",
+        },
+    },
+
+    // We need to access Bionic private headers in the linker.
+    include_dirs: ["bionic/libc"],
+
     static_libs: [
         "libc_nomalloc",
         "libm",
@@ -202,7 +278,6 @@
         // to overwrite any other malloc implementations by other static libraries.
         "liblinker_malloc",
     ],
-    static_executable: true,
 
     name: "linker",
     symlinks: ["linker_asan"],
@@ -218,20 +293,6 @@
         },
     },
     compile_multilib: "both",
-
-    // Leave the symbols in the shared library so that stack unwinders can produce
-    // meaningful name resolution.
-    strip: {
-        keep_symbols: true,
-    },
-
-    // Insert an extra objcopy step to add prefix to symbols. This is needed to prevent gdb
-    // looking up symbols in the linker by mistake.
-    prefix_symbols: "__dl_",
-
-    sanitize: {
-        hwaddress: false,
-    },
 }
 
 cc_library {
diff --git a/linker/linked_list.h b/linker/linked_list.h
index 048ea4d..7f70a2c 100644
--- a/linker/linked_list.h
+++ b/linker/linked_list.h
@@ -84,7 +84,7 @@
     clear();
   }
 
-  LinkedList(LinkedList&& that) {
+  LinkedList(LinkedList&& that) noexcept {
     this->head_ = that.head_;
     this->tail_ = that.tail_;
     that.head_ = that.tail_ = nullptr;
diff --git a/linker/linker_memory.cpp b/linker/linker_memory.cpp
index 6a54c13..f2cce01 100644
--- a/linker/linker_memory.cpp
+++ b/linker/linker_memory.cpp
@@ -80,7 +80,15 @@
   return get_allocator().realloc(p, byte_count);
 }
 
+void* reallocarray(void* p, size_t item_count, size_t item_size) {
+  size_t byte_count;
+  if (__builtin_mul_overflow(item_count, item_size, &byte_count)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return get_allocator().realloc(p, byte_count);
+}
+
 void free(void* ptr) {
   get_allocator().free(ptr);
 }
-
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 0a7ccd8..8bf4c94 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -257,8 +257,10 @@
   }
 
   if (header_.e_machine != GetTargetElfMachine()) {
-    DL_ERR("\"%s\" has unexpected e_machine: %d (%s)", name_.c_str(), header_.e_machine,
-           EM_to_string(header_.e_machine));
+    DL_ERR("\"%s\" is for %s (%d) instead of %s (%d)",
+           name_.c_str(),
+           EM_to_string(header_.e_machine), header_.e_machine,
+           EM_to_string(GetTargetElfMachine()), GetTargetElfMachine());
     return false;
   }
 
diff --git a/tests/Android.bp b/tests/Android.bp
index fa66f93..5ba6b3d 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -65,6 +65,7 @@
     defaults: ["bionic_tests_defaults"],
     srcs: [
         "alloca_test.cpp",
+        "android_get_device_api_level.cpp",
         "arpa_inet_test.cpp",
         "async_safe_test.cpp",
         "assert_test.cpp",
@@ -104,6 +105,7 @@
         "malloc_test.cpp",
         "math_test.cpp",
         "math_force_long_double_test.cpp",
+        "membarrier_test.cpp",
         "mntent_test.cpp",
         "netdb_test.cpp",
         "net_if_test.cpp",
@@ -307,33 +309,6 @@
     },
 }
 
-// -----------------------------------------------------------------------------
-// Library of bionic customized gtest main function, with simplified output format.
-// -----------------------------------------------------------------------------
-cc_test_library {
-    name: "libBionicGtestMain",
-    defaults: ["bionic_tests_defaults"],
-    srcs: [
-        "gtest_main.cpp",
-        "gtest_globals.cpp",
-    ],
-    whole_static_libs: [
-        "libbase",
-        "liblog",
-    ],
-    include_dirs: [
-        "bionic/libc",
-    ],
-    target: {
-        darwin: {
-            enabled: true,
-        },
-    },
-    shared: {
-        enabled: false,
-    },
-}
-
 cc_test_library {
     name: "libBionicLoaderTests",
     defaults: [
@@ -386,16 +361,15 @@
     name: "libBionicCtsGtestMain",
     defaults: ["bionic_tests_defaults"],
     srcs: [
-        "gtest_main.cpp",
         "gtest_globals_cts.cpp",
+        "gtest_main.cpp",
     ],
-    static_libs: [
-        "libbase",
-    ],
-    cppflags: ["-DUSING_GTEST_OUTPUT_FORMAT"],
     shared: {
         enabled: false,
     },
+    whole_static_libs: [
+        "libgtest_isolated",
+    ],
 }
 
 // -----------------------------------------------------------------------------
@@ -410,7 +384,6 @@
     whole_static_libs: [
         "libBionicTests",
         "libBionicLoaderTests",
-        "libBionicGtestMain",
     ],
 
     static_libs: [
@@ -422,6 +395,7 @@
     srcs: [
         // TODO: Include __cxa_thread_atexit_test.cpp to glibc tests once it is upgraded (glibc 2.18+)
         "__cxa_thread_atexit_test.cpp",
+        "gtest_globals.cpp",
         "thread_local_test.cpp",
     ],
 
@@ -469,11 +443,20 @@
 
 cc_test {
     name: "bionic-unit-tests",
+    gtest: false,
     defaults: [
         "bionic_unit_tests_defaults",
         "bionic_tests_defaults",
     ],
 
+    srcs: [
+        "gtest_main.cpp",
+    ],
+
+    static_libs: [
+        "libgtest_isolated",
+    ],
+
     target: {
         android: {
             shared_libs: ["libicuuc"],
@@ -617,15 +600,17 @@
 // -----------------------------------------------------------------------------
 cc_test {
     name: "bionic-unit-tests-static",
+    gtest: false,
     defaults: ["bionic_tests_defaults"],
     host_supported: false,
 
     srcs: [
         "gtest_preinit_debuggerd.cpp",
+        "gtest_globals.cpp",
+        "gtest_main.cpp",
     ],
     whole_static_libs: [
         "libBionicTests",
-        "libBionicGtestMain",
     ],
 
     static_libs: [
@@ -636,6 +621,7 @@
         "liblog",
         "libbase",
         "libdebuggerd_handler",
+        "libgtest_isolated",
     ],
 
     static_executable: true,
@@ -649,6 +635,7 @@
 
 cc_test_host {
     name: "bionic-unit-tests-glibc",
+    gtest: false,
     defaults: ["bionic_tests_defaults"],
 
     srcs: [
@@ -656,6 +643,8 @@
         "dlfcn_symlink_support.cpp",
         "dlfcn_test.cpp",
         "dl_test.cpp",
+        "gtest_globals.cpp",
+        "gtest_main.cpp",
         "pthread_dlfcn_test.cpp",
     ],
 
@@ -668,7 +657,6 @@
 
     whole_static_libs: [
         "libBionicStandardTests",
-        "libBionicGtestMain",
         "libfortify1-tests-clang",
         "libfortify2-tests-clang",
     ],
@@ -677,6 +665,7 @@
         "libbase",
         "liblog",
         "libcutils",
+        "libgtest_isolated",
     ],
 
     host_ldlibs: [
@@ -684,7 +673,9 @@
         "-lutil",
     ],
 
-    include_dirs: ["bionic/libc"],
+    include_dirs: [
+        "bionic/libc",
+    ],
 
     ldflags: [
         "-Wl,--rpath,${ORIGIN}/../bionic-loader-test-libs",
diff --git a/tests/android_get_device_api_level.cpp b/tests/android_get_device_api_level.cpp
new file mode 100644
index 0000000..5272a48
--- /dev/null
+++ b/tests/android_get_device_api_level.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 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 <gtest/gtest.h>
+
+#if __BIONIC__
+#include <android/get_device_api_level.h>
+#endif
+
+TEST(android_get_device_api_level, smoke) {
+#if __BIONIC__
+  // This will fail if you run the tests on an old device, but who does that?
+  ASSERT_GE(29, android_get_device_api_level());
+#endif
+}
diff --git a/tests/cfi_test.cpp b/tests/cfi_test.cpp
index 5e2518f..e155e1a 100644
--- a/tests/cfi_test.cpp
+++ b/tests/cfi_test.cpp
@@ -135,7 +135,7 @@
 // cfi_test_helper exports __cfi_check, which triggers CFI initialization at startup.
 TEST(cfi_test, early_init) {
 #if defined(__BIONIC__)
-  std::string helper = get_testlib_root() + "/cfi_test_helper/cfi_test_helper";
+  std::string helper = GetTestlibRoot() + "/cfi_test_helper/cfi_test_helper";
   chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
   ExecTestHelper eth;
   eth.SetArgs({ helper.c_str(), nullptr });
@@ -147,7 +147,7 @@
 // at startup.
 TEST(cfi_test, early_init2) {
 #if defined(__BIONIC__)
-  std::string helper = get_testlib_root() + "/cfi_test_helper2/cfi_test_helper2";
+  std::string helper = GetTestlibRoot() + "/cfi_test_helper2/cfi_test_helper2";
   chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
   ExecTestHelper eth;
   eth.SetArgs({ helper.c_str(), nullptr });
diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp
index 25341f4..44fab01 100644
--- a/tests/dl_test.cpp
+++ b/tests/dl_test.cpp
@@ -96,7 +96,7 @@
 
 TEST(dl, preinit_system_calls) {
 #if defined(__BIONIC__)
-  std::string helper = get_testlib_root() +
+  std::string helper = GetTestlibRoot() +
       "/preinit_syscall_test_helper/preinit_syscall_test_helper";
   chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
   ExecTestHelper eth;
@@ -107,7 +107,7 @@
 
 TEST(dl, xfail_preinit_getauxval) {
 #if defined(__BIONIC__)
-  std::string helper = get_testlib_root() +
+  std::string helper = GetTestlibRoot() +
       "/preinit_getauxval_test_helper/preinit_getauxval_test_helper";
   chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
   ExecTestHelper eth;
@@ -119,7 +119,7 @@
 
 TEST(dl, exec_without_ld_preload) {
 #if defined(__BIONIC__)
-  std::string helper = get_testlib_root() +
+  std::string helper = GetTestlibRoot() +
       "/ld_preload_test_helper/ld_preload_test_helper";
   chmod(helper.c_str(), 0755);
   ExecTestHelper eth;
@@ -130,9 +130,9 @@
 
 TEST(dl, exec_with_ld_preload) {
 #if defined(__BIONIC__)
-  std::string helper = get_testlib_root() +
+  std::string helper = GetTestlibRoot() +
       "/ld_preload_test_helper/ld_preload_test_helper";
-  std::string env = std::string("LD_PRELOAD=") + get_testlib_root() + "/ld_preload_test_helper_lib2.so";
+  std::string env = std::string("LD_PRELOAD=") + GetTestlibRoot() + "/ld_preload_test_helper_lib2.so";
   chmod(helper.c_str(), 0755);
   ExecTestHelper eth;
   eth.SetArgs({ helper.c_str(), nullptr });
@@ -157,8 +157,8 @@
 // The two libs are in ns2/ subdir.
 TEST(dl, exec_without_ld_config_file) {
 #if defined(__BIONIC__)
-  std::string error_message = "CANNOT LINK EXECUTABLE \"" + get_testlib_root() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n";
-  std::string helper = get_testlib_root() +
+  std::string error_message = "CANNOT LINK EXECUTABLE \"" + GetTestlibRoot() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n";
+  std::string helper = GetTestlibRoot() +
       "/ld_config_test_helper/ld_config_test_helper";
   chmod(helper.c_str(), 0755);
   ExecTestHelper eth;
@@ -174,13 +174,13 @@
   android_get_LD_LIBRARY_PATH(default_search_paths, sizeof(default_search_paths));
 
   std::ofstream fout(config_file, std::ios::out);
-  fout << "dir.test = " << get_testlib_root() << "/ld_config_test_helper/" << std::endl
+  fout << "dir.test = " << GetTestlibRoot() << "/ld_config_test_helper/" << std::endl
        << "[test]" << std::endl
        << "additional.namespaces = ns2" << std::endl
-       << "namespace.default.search.paths = " << get_testlib_root() << std::endl
+       << "namespace.default.search.paths = " << GetTestlibRoot() << std::endl
        << "namespace.default.links = ns2" << std::endl
        << "namespace.default.link.ns2.shared_libs = libc.so:libm.so:libdl.so:ld_config_test_helper_lib1.so" << std::endl
-       << "namespace.ns2.search.paths = " << default_search_paths << ":" << get_testlib_root() << "/ns2" << std::endl;
+       << "namespace.ns2.search.paths = " << default_search_paths << ":" << GetTestlibRoot() << "/ns2" << std::endl;
   fout.close();
 }
 #endif
@@ -199,7 +199,7 @@
     // LD_CONFIG_FILE is not supported on user build
     return;
   }
-  std::string helper = get_testlib_root() +
+  std::string helper = GetTestlibRoot() +
       "/ld_config_test_helper/ld_config_test_helper";
   TemporaryFile config_file;
   create_ld_config_file(config_file.filename);
@@ -221,12 +221,12 @@
     // LD_CONFIG_FILE is not supported on user build
     return;
   }
-  std::string helper = get_testlib_root() +
+  std::string helper = GetTestlibRoot() +
       "/ld_config_test_helper/ld_config_test_helper";
   TemporaryFile config_file;
   create_ld_config_file(config_file.filename);
   std::string env = std::string("LD_CONFIG_FILE=") + config_file.filename;
-  std::string env2 = std::string("LD_PRELOAD=") + get_testlib_root() + "/ld_config_test_helper_lib3.so";
+  std::string env2 = std::string("LD_PRELOAD=") + GetTestlibRoot() + "/ld_config_test_helper_lib3.so";
   chmod(helper.c_str(), 0755);
   ExecTestHelper eth;
   eth.SetArgs({ helper.c_str(), nullptr });
@@ -250,8 +250,8 @@
     return;
   }
 
-  std::string error_message = "CANNOT LINK EXECUTABLE \"" + get_testlib_root() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n";
-  std::string helper = get_testlib_root() +
+  std::string error_message = "CANNOT LINK EXECUTABLE \"" + GetTestlibRoot() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n";
+  std::string helper = GetTestlibRoot() +
       "/ld_config_test_helper/ld_config_test_helper";
   TemporaryFile config_file;
   create_ld_config_file(config_file.filename);
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 1e3d9c8..b33cf68 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -26,6 +26,7 @@
 #include <unistd.h>
 
 #include <android/dlext.h>
+#include <android-base/file.h>
 #include <android-base/strings.h>
 
 #include <linux/memfd.h>
@@ -104,7 +105,7 @@
 }
 
 TEST_F(DlExtTest, ExtInfoUseFd) {
-  const std::string lib_path = get_testlib_root() + "/libdlext_test_fd/libdlext_test_fd.so";
+  const std::string lib_path = GetTestlibRoot() + "/libdlext_test_fd/libdlext_test_fd.so";
 
   android_dlextinfo extinfo;
   extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD;
@@ -122,7 +123,7 @@
 }
 
 TEST_F(DlExtTest, ExtInfoUseFdWithOffset) {
-  const std::string lib_path = get_testlib_root() + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
+  const std::string lib_path = GetTestlibRoot() + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
 
   android_dlextinfo extinfo;
   extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
@@ -148,7 +149,7 @@
 }
 
 TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
-  const std::string lib_path = get_testlib_root() + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
+  const std::string lib_path = GetTestlibRoot() + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
 
   android_dlextinfo extinfo;
   extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
@@ -234,7 +235,7 @@
 
 TEST(dlfcn, dlopen_from_zip_absolute_path) {
   const std::string lib_zip_path = "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
-  const std::string lib_path = get_testlib_root() + lib_zip_path;
+  const std::string lib_path = GetTestlibRoot() + lib_zip_path;
 
   void* handle = dlopen((lib_path + "!/libdir/libatest_simple_zip.so").c_str(), RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
@@ -248,7 +249,7 @@
 
 TEST(dlfcn, dlopen_from_zip_with_dt_runpath) {
   const std::string lib_zip_path = "/libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip";
-  const std::string lib_path = get_testlib_root() + lib_zip_path;
+  const std::string lib_path = GetTestlibRoot() + lib_zip_path;
 
   void* handle = dlopen((lib_path + "!/libdir/libtest_dt_runpath_d_zip.so").c_str(), RTLD_NOW);
 
@@ -267,7 +268,7 @@
 
 TEST(dlfcn, dlopen_from_zip_ld_library_path) {
   const std::string lib_zip_path = "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
-  const std::string lib_path = get_testlib_root() + lib_zip_path + "!/libdir";
+  const std::string lib_path = GetTestlibRoot() + lib_zip_path + "!/libdir";
 
   typedef void (*fn_t)(const char*);
   fn_t android_update_LD_LIBRARY_PATH =
@@ -647,7 +648,7 @@
                " \"(anonymous)\"->\"(default)\": the list of shared libraries is empty.",
                dlerror());
 
-  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
+  const std::string lib_public_path = GetTestlibRoot() + "/public_namespace_libs/" + g_public_lib;
   void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
@@ -667,7 +668,7 @@
   android_namespace_t* ns1 =
           android_create_namespace("private",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_REGULAR,
                                    nullptr,
                                    nullptr);
@@ -677,7 +678,7 @@
   android_namespace_t* ns2 =
           android_create_namespace("private_isolated",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    nullptr,
                                    nullptr);
@@ -821,10 +822,10 @@
 }
 
 TEST(dlext, dlopen_ext_use_o_tmpfile_fd) {
-  const std::string lib_path = get_testlib_root() + "/libtest_simple.so";
+  const std::string lib_path = GetTestlibRoot() + "/libtest_simple.so";
 
   int tmpfd = TEMP_FAILURE_RETRY(
-        open(get_testlib_root().c_str(), O_TMPFILE | O_CLOEXEC | O_RDWR | O_EXCL, 0));
+        open(GetTestlibRoot().c_str(), O_TMPFILE | O_CLOEXEC | O_RDWR | O_EXCL, 0));
 
   // Ignore kernels without O_TMPFILE flag support
   if (tmpfd == -1 && (errno == EISDIR || errno == EINVAL || errno == EOPNOTSUPP)) {
@@ -836,7 +837,7 @@
   android_namespace_t* ns =
           android_create_namespace("testing-o_tmpfile",
                                    nullptr,
-                                   get_testlib_root().c_str(),
+                                   GetTestlibRoot().c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    nullptr,
                                    nullptr);
@@ -865,7 +866,7 @@
 }
 
 TEST(dlext, dlopen_ext_use_memfd) {
-  const std::string lib_path = get_testlib_root() + "/libtest_simple.so";
+  const std::string lib_path = GetTestlibRoot() + "/libtest_simple.so";
 
   // create memfd
   int memfd = syscall(__NR_memfd_create, "foobar", MFD_CLOEXEC);
@@ -883,7 +884,7 @@
   android_namespace_t* ns =
           android_create_namespace("testing-memfd",
                                    nullptr,
-                                   get_testlib_root().c_str(),
+                                   GetTestlibRoot().c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    nullptr,
                                    nullptr);
@@ -916,8 +917,8 @@
   static const char* root_lib = "libnstest_root.so";
   ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
 
-  const std::string ns_search_path = get_testlib_root() + "/public_namespace_libs:" +
-                                     get_testlib_root() + "/private_namespace_libs";
+  const std::string ns_search_path = GetTestlibRoot() + "/public_namespace_libs:" +
+                                     GetTestlibRoot() + "/private_namespace_libs";
 
   android_namespace_t* ns =
           android_create_namespace("one",
@@ -954,8 +955,8 @@
   static const char* root_lib = "libnstest_root.so";
   ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
 
-  const std::string public_ns_search_path =  get_testlib_root() + "/public_namespace_libs";
-  const std::string private_ns_search_path = get_testlib_root() + "/private_namespace_libs";
+  const std::string public_ns_search_path =  GetTestlibRoot() + "/public_namespace_libs";
+  const std::string private_ns_search_path = GetTestlibRoot() + "/private_namespace_libs";
 
   android_namespace_t* ns_public =
           android_create_namespace("public",
@@ -1005,8 +1006,8 @@
   static const char* root_lib = "libnstest_root.so";
   ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
 
-  const std::string public_ns_search_path =  get_testlib_root() + "/public_namespace_libs";
-  const std::string private_ns_search_path = get_testlib_root() + "/private_namespace_libs";
+  const std::string public_ns_search_path =  GetTestlibRoot() + "/public_namespace_libs";
+  const std::string private_ns_search_path = GetTestlibRoot() + "/private_namespace_libs";
 
   android_namespace_t* ns_public =
           android_create_namespace("public",
@@ -1054,8 +1055,8 @@
 TEST(dlext, ns_unload_between_namespaces_missing_symbol_direct) {
   ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
 
-  const std::string public_ns_search_path =  get_testlib_root() + "/public_namespace_libs";
-  const std::string private_ns_search_path = get_testlib_root() + "/private_namespace_libs";
+  const std::string public_ns_search_path =  GetTestlibRoot() + "/public_namespace_libs";
+  const std::string private_ns_search_path = GetTestlibRoot() + "/private_namespace_libs";
 
   android_namespace_t* ns_public =
           android_create_namespace("public",
@@ -1094,8 +1095,8 @@
 TEST(dlext, ns_unload_between_namespaces_missing_symbol_indirect) {
   ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
 
-  const std::string public_ns_search_path =  get_testlib_root() + "/public_namespace_libs";
-  const std::string private_ns_search_path = get_testlib_root() + "/private_namespace_libs";
+  const std::string public_ns_search_path =  GetTestlibRoot() + "/public_namespace_libs";
+  const std::string private_ns_search_path = GetTestlibRoot() + "/private_namespace_libs";
 
   android_namespace_t* ns_public =
           android_create_namespace("public",
@@ -1135,7 +1136,7 @@
 TEST(dlext, ns_greylist_enabled) {
   ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
 
-  const std::string ns_search_path = get_testlib_root() + "/private_namespace_libs";
+  const std::string ns_search_path = GetTestlibRoot() + "/private_namespace_libs";
 
   android_namespace_t* ns =
           android_create_namespace("namespace",
@@ -1173,7 +1174,7 @@
 TEST(dlext, ns_greylist_disabled_by_default) {
   ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
 
-  const std::string ns_search_path = get_testlib_root() + "/private_namespace_libs";
+  const std::string ns_search_path = GetTestlibRoot() + "/private_namespace_libs";
 
   android_namespace_t* ns =
           android_create_namespace("namespace",
@@ -1200,7 +1201,7 @@
   ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
   std::string shared_libs = g_core_shared_libs + ":libthatdoesnotexist.so";
 
-  const std::string ns_search_path =  get_testlib_root() + "/public_namespace_libs";
+  const std::string ns_search_path =  GetTestlibRoot() + "/public_namespace_libs";
 
   android_namespace_t* ns1 =
           android_create_namespace("ns1",
@@ -1238,7 +1239,7 @@
   static const char* root_lib = "libnstest_root_not_isolated.so";
   std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
 
-  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
+  const std::string lib_public_path = GetTestlibRoot() + "/public_namespace_libs/" + g_public_lib;
   void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
@@ -1249,7 +1250,7 @@
   android_namespace_t* ns_not_isolated =
           android_create_namespace("private",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_REGULAR,
                                    nullptr,
                                    nullptr);
@@ -1259,7 +1260,7 @@
   android_namespace_t* ns_isolated =
           android_create_namespace("private_isolated1",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    nullptr,
                                    nullptr);
@@ -1268,10 +1269,10 @@
 
   android_namespace_t* ns_isolated2 =
           android_create_namespace("private_isolated2",
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    nullptr,
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
-                                   get_testlib_root().c_str(),
+                                   GetTestlibRoot().c_str(),
                                    nullptr);
   ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
   ASSERT_TRUE(android_link_namespaces(ns_isolated2, nullptr, shared_libs.c_str())) << dlerror();
@@ -1280,7 +1281,7 @@
   ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
 
   std::string lib_private_external_path =
-      get_testlib_root() + "/private_namespace_libs_external/libnstest_private_external.so";
+      GetTestlibRoot() + "/private_namespace_libs_external/libnstest_private_external.so";
 
   // Load lib_private_external_path to default namespace
   // (it should remain invisible for the isolated namespaces after this)
@@ -1304,12 +1305,12 @@
   handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle2 == nullptr);
   ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" needed"
-            " or dlopened by \"" + get_executable_path() +  "\" is not accessible"
+            " or dlopened by \"" + android::base::GetExecutablePath() +  "\" is not accessible"
             " for the namespace \"private_isolated1\"", dlerror());
 
   extinfo.library_namespace = ns_isolated2;
 
-  // this should work because isolation_path for private_isolated2 includes get_testlib_root()
+  // this should work because isolation_path for private_isolated2 includes GetTestlibRoot()
   handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle2 != nullptr) << dlerror();
   dlclose(handle2);
@@ -1368,7 +1369,7 @@
   extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
   extinfo.library_namespace = ns_parent;
 
-  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
+  const std::string lib_public_path = GetTestlibRoot() + "/public_namespace_libs/" + g_public_lib;
   void* handle_public = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
@@ -1379,7 +1380,7 @@
   // preload this library to the parent namespace to check if it
   // is shared later on.
   void* handle_dlopened =
-          android_dlopen_ext((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW, &extinfo);
+          android_dlopen_ext((GetTestlibRoot() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
 
   // create two child namespaces of 'ns_parent'. One with regular, the other
@@ -1387,7 +1388,7 @@
   android_namespace_t* ns_not_isolated =
           android_create_namespace("private",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_REGULAR,
                                    nullptr,
                                    ns_parent);
@@ -1398,7 +1399,7 @@
   android_namespace_t* ns_isolated_shared =
           android_create_namespace("private_isolated_shared",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
                                    nullptr,
                                    ns_parent);
@@ -1410,7 +1411,7 @@
   ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
 
   std::string lib_private_external_path =
-      get_testlib_root() + "/private_namespace_libs_external/libnstest_private_external.so";
+      GetTestlibRoot() + "/private_namespace_libs_external/libnstest_private_external.so";
 
   // Load lib_private_external_path to the parent namespace
   // (it should remain invisible for the isolated namespaces after this)
@@ -1432,7 +1433,7 @@
   handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle2 == nullptr);
   ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" needed"
-            " or dlopened by \"" + get_executable_path() + "\" is not accessible"
+            " or dlopened by \"" + android::base::GetExecutablePath() + "\" is not accessible"
             " for the namespace \"private_isolated_shared\"", dlerror());
 
   // load libnstest_root.so to shared namespace in order to check that everything is different
@@ -1494,9 +1495,9 @@
   android_namespace_t* ns_isolated =
           android_create_namespace("private_isolated",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
-                                   (get_testlib_root() + "/public_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/public_namespace_libs").c_str(),
                                    nullptr);
   ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
   ASSERT_TRUE(android_link_namespaces(ns_isolated, nullptr, g_core_shared_libs.c_str())) << dlerror();
@@ -1530,7 +1531,7 @@
   // it has inherited permitted_when_isolated_path
   {
     void* handle = android_dlopen_ext(
-            (get_testlib_root() + "/public_namespace_libs/libnstest_public.so").c_str(),
+            (GetTestlibRoot() + "/public_namespace_libs/libnstest_public.so").c_str(),
             RTLD_NOW,
             &extinfo);
 
@@ -1545,7 +1546,7 @@
   // 3. Check that it is still isolated.
   {
     void* handle = android_dlopen_ext(
-            (get_testlib_root() + "/libtest_empty.so").c_str(),
+            (GetTestlibRoot() + "/libtest_empty.so").c_str(),
             RTLD_NOW,
             &extinfo);
 
@@ -1561,13 +1562,13 @@
   // preload this library to the default namespace to check if it
   // is shared later on.
   void* handle_dlopened =
-          dlopen((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
+          dlopen((GetTestlibRoot() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
 
   android_namespace_t* ns_isolated_shared =
           android_create_namespace("private_isolated_shared",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
                                    nullptr,
                                    nullptr);
@@ -1590,7 +1591,7 @@
   ASSERT_TRUE(handle == nullptr)
       << "Error: libnstest_dlopened.so is still accessible in shared namespace";
 
-  handle = android_dlopen_ext((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
+  handle = android_dlopen_ext((GetTestlibRoot() + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
                               RTLD_NOW | RTLD_NOLOAD, &extinfo);
   ASSERT_TRUE(handle == nullptr)
       << "Error: libnstest_dlopened.so is still accessible in shared namespace";
@@ -1599,14 +1600,14 @@
   ASSERT_TRUE(handle == nullptr)
       << "Error: libnstest_dlopened.so is still accessible in default namespace";
 
-  handle = dlopen((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
+  handle = dlopen((GetTestlibRoot() + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
                   RTLD_NOW | RTLD_NOLOAD);
   ASSERT_TRUE(handle == nullptr)
       << "Error: libnstest_dlopened.so is still accessible in default namespace";
 
   // Now lets see if the soinfo area gets reused in the wrong way:
   // load a library to default namespace.
-  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
+  const std::string lib_public_path = GetTestlibRoot() + "/public_namespace_libs/" + g_public_lib;
   void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
@@ -1620,12 +1621,12 @@
   static const char* root_lib = "libnstest_root.so";
   ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
 
-  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs";
+  const std::string lib_public_path = GetTestlibRoot() + "/public_namespace_libs";
 
   android_namespace_t* ns1 =
           android_create_namespace("isolated1",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    lib_public_path.c_str(),
                                    nullptr);
@@ -1635,7 +1636,7 @@
   android_namespace_t* ns2 =
           android_create_namespace("isolated2",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    lib_public_path.c_str(),
                                    nullptr);
@@ -1655,7 +1656,7 @@
   android_namespace_t* ns1_child =
           android_create_namespace("isolated1_child",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    nullptr,
                                    ns1);
@@ -1702,7 +1703,7 @@
   android_namespace_t* ns_a =
           android_create_namespace("ns_a",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    nullptr,
                                    nullptr);
@@ -1712,7 +1713,7 @@
   android_namespace_t* ns_b =
           android_create_namespace("ns_b",
                                    nullptr,
-                                   get_testlib_root().c_str(),
+                                   GetTestlibRoot().c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    nullptr,
                                    nullptr);
@@ -1725,7 +1726,7 @@
   extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
   extinfo.library_namespace = ns_a;
 
-  std::string library_path = get_testlib_root() + "/inaccessible_libs/libtestshared.so";
+  std::string library_path = GetTestlibRoot() + "/inaccessible_libs/libtestshared.so";
 
   void* handle = android_dlopen_ext(library_path.c_str(), RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle == nullptr);
@@ -1733,7 +1734,7 @@
       android::base::StringPrintf("dlopen failed: library \"%s\" needed or dlopened by \"%s\""
                                   " is not accessible for the namespace \"ns_a\"",
                                   library_path.c_str(),
-                                  get_executable_path().c_str());
+                                  android::base::GetExecutablePath().c_str());
   ASSERT_EQ(expected_dlerror, dlerror());
 }
 
@@ -1746,7 +1747,7 @@
   android_namespace_t* ns =
           android_create_namespace("private",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_REGULAR,
                                    nullptr,
                                    nullptr);
@@ -1787,7 +1788,7 @@
   android_namespace_t* ns_a =
           android_create_namespace("ns_a",
                                    nullptr,
-                                   (get_testlib_root() + "/ns_a").c_str(),
+                                   (GetTestlibRoot() + "/ns_a").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    nullptr,
                                    nullptr);
@@ -1797,7 +1798,7 @@
   android_namespace_t* ns_b =
           android_create_namespace("ns_b",
                                    nullptr,
-                                   (get_testlib_root() + "/ns_b").c_str(),
+                                   (GetTestlibRoot() + "/ns_b").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    nullptr,
                                    nullptr);
@@ -1861,20 +1862,20 @@
   static const char* root_lib = "libnstest_root.so";
   std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
 
-  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
+  const std::string lib_public_path = GetTestlibRoot() + "/public_namespace_libs/" + g_public_lib;
   void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
 
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
   ASSERT_TRUE(
           android_init_anonymous_namespace(shared_libs.c_str(),
-                                           (get_testlib_root() + "/private_namespace_libs").c_str())
+                                           (GetTestlibRoot() + "/private_namespace_libs").c_str())
       ) << dlerror();
 
   android_namespace_t* ns =
           android_create_namespace("private",
                                    nullptr,
-                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   (GetTestlibRoot() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_REGULAR,
                                    nullptr,
                                    nullptr);
@@ -1882,7 +1883,7 @@
   ASSERT_TRUE(ns != nullptr) << dlerror();
   ASSERT_TRUE(android_link_namespaces(ns, nullptr, shared_libs.c_str())) << dlerror();
 
-  std::string private_library_absolute_path = get_testlib_root() + "/private_namespace_libs/" + root_lib;
+  std::string private_library_absolute_path = GetTestlibRoot() + "/private_namespace_libs/" + root_lib;
 
   android_dlextinfo extinfo;
   extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 9017754..5f48e67 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -29,9 +29,11 @@
 #include <string>
 #include <thread>
 
+#include <android-base/file.h>
 #include <android-base/scopeguard.h>
 
 #include "gtest_globals.h"
+#include "gtest_utils.h"
 #include "dlfcn_symlink_support.h"
 #include "utils.h"
 
@@ -72,9 +74,9 @@
 
 TEST(dlfcn, ctor_function_call) {
   ASSERT_EQ(17, g_ctor_function_called);
-  ASSERT_TRUE(g_ctor_argc = get_argc());
-  ASSERT_TRUE(g_ctor_argv = get_argv());
-  ASSERT_TRUE(g_ctor_envp = get_envp());
+  ASSERT_TRUE(g_ctor_argc = GetArgc());
+  ASSERT_TRUE(g_ctor_argv = GetArgv());
+  ASSERT_TRUE(g_ctor_envp = GetEnvp());
 }
 
 TEST(dlfcn, dlsym_in_executable) {
@@ -928,7 +930,7 @@
   ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
 
   // Get the name of this executable.
-  const std::string& executable_path = get_executable_path();
+  const std::string executable_path = android::base::GetExecutablePath();
 
   // The filename should be that of this executable.
   char dli_realpath[PATH_MAX];
@@ -962,7 +964,7 @@
   void* handle1 = dlopen(nullptr, RTLD_NOW);
   ASSERT_TRUE(handle1 != nullptr) << dlerror();
 
-  void* handle2 = dlopen(get_executable_path().c_str(), RTLD_NOW);
+  void* handle2 = dlopen(android::base::GetExecutablePath().c_str(), RTLD_NOW);
   ASSERT_TRUE(handle2 != nullptr) << dlerror();
 
 #if defined(__BIONIC__)
@@ -1315,7 +1317,7 @@
 }
 
 TEST(dlfcn, dt_runpath_absolute_path) {
-  std::string libpath = get_testlib_root() + "/libtest_dt_runpath_d.so";
+  std::string libpath = GetTestlibRoot() + "/libtest_dt_runpath_d.so";
   void* handle = dlopen(libpath.c_str(), RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
 
@@ -1635,7 +1637,7 @@
 #endif //  defined(__arm__)
 
 TEST(dlfcn, dlopen_invalid_rw_load_segment) {
-  const std::string libpath = get_testlib_root() +
+  const std::string libpath = GetTestlibRoot() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-rw_load_segment.so";
   void* handle = dlopen(libpath.c_str(), RTLD_NOW);
@@ -1645,7 +1647,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_unaligned_shdr_offset) {
-  const std::string libpath = get_testlib_root() +
+  const std::string libpath = GetTestlibRoot() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-unaligned_shdr_offset.so";
 
@@ -1656,7 +1658,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_zero_shentsize) {
-  const std::string libpath = get_testlib_root() +
+  const std::string libpath = GetTestlibRoot() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-zero_shentsize.so";
 
@@ -1667,7 +1669,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_zero_shstrndx) {
-  const std::string libpath = get_testlib_root() +
+  const std::string libpath = GetTestlibRoot() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-zero_shstrndx.so";
 
@@ -1678,7 +1680,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_empty_shdr_table) {
-  const std::string libpath = get_testlib_root() +
+  const std::string libpath = GetTestlibRoot() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-empty_shdr_table.so";
 
@@ -1689,7 +1691,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_zero_shdr_table_offset) {
-  const std::string libpath = get_testlib_root() +
+  const std::string libpath = GetTestlibRoot() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-zero_shdr_table_offset.so";
 
@@ -1700,7 +1702,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_zero_shdr_table_content) {
-  const std::string libpath = get_testlib_root() +
+  const std::string libpath = GetTestlibRoot() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-zero_shdr_table_content.so";
 
@@ -1711,7 +1713,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_textrels) {
-  const std::string libpath = get_testlib_root() +
+  const std::string libpath = GetTestlibRoot() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-textrels.so";
 
@@ -1722,7 +1724,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_textrels2) {
-  const std::string libpath = get_testlib_root() +
+  const std::string libpath = GetTestlibRoot() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-textrels2.so";
 
diff --git a/tests/float_test.cpp b/tests/float_test.cpp
index a75214e..3ef4593 100644
--- a/tests/float_test.cpp
+++ b/tests/float_test.cpp
@@ -112,16 +112,13 @@
 #if !defined(FLT_EVAL_METHOD)
 #error FLT_EVAL_METHOD
 #endif
-// TODO: FLT_HAS_SUBNORM currently missing from clang. Negate this test when fixed.
-#if defined(FLT_HAS_SUBNORM)
+#if !defined(FLT_HAS_SUBNORM)
 #error FLT_HAS_SUBNORM
 #endif
-// TODO: DBL_HAS_SUBNORM currently missing from clang. Negate this test when fixed.
-#if defined(DBL_HAS_SUBNORM)
+#if !defined(DBL_HAS_SUBNORM)
 #error DBL_HAS_SUBNORM
 #endif
-// TODO: LDBL_HAS_SUBNORM currently missing from clang. Negate this test when fixed.
-#if defined(LDBL_HAS_SUBNORM)
+#if !defined(LDBL_HAS_SUBNORM)
 #error LDBL_HAS_SUBNORM
 #endif
 }
diff --git a/tests/fortify_filecheck_diagnostics_test.cpp b/tests/fortify_filecheck_diagnostics_test.cpp
index a69b967..e79a9a6 100644
--- a/tests/fortify_filecheck_diagnostics_test.cpp
+++ b/tests/fortify_filecheck_diagnostics_test.cpp
@@ -291,7 +291,10 @@
   char from[4] = {0};
   // NOLINTNEXTLINE(whitespace/line_length)
   // CLANG: 'memset' will set 0 bytes; maybe the arguments got flipped?
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmemset-transposed-args"
   memset(from, sizeof(from), 0);
+#pragma clang diagnostic pop
 }
 
 void test_sendto() {
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index 68897ed..24a8648 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -42,8 +42,9 @@
 using android::base::StartsWith;
 
 enum uid_type_t {
+  TYPE_APP,
   TYPE_SYSTEM,
-  TYPE_APP
+  TYPE_VENDOR,
 };
 
 #if defined(__BIONIC__)
@@ -61,12 +62,17 @@
   EXPECT_EQ(nullptr, pwd->pw_gecos);
 #endif
 
-  if (uid_type == TYPE_SYSTEM) {
-    EXPECT_STREQ("/", pwd->pw_dir);
-  } else {
+  if (uid_type == TYPE_APP) {
     EXPECT_STREQ("/data", pwd->pw_dir);
+  } else {
+    EXPECT_STREQ("/", pwd->pw_dir);
   }
-  EXPECT_STREQ("/system/bin/sh", pwd->pw_shell);
+
+  if (uid_type == TYPE_VENDOR) {
+    EXPECT_STREQ("/vendor/bin/sh", pwd->pw_shell);
+  } else {
+    EXPECT_STREQ("/system/bin/sh", pwd->pw_shell);
+  }
 }
 
 static void check_getpwuid(const char* username, uid_t uid, uid_type_t uid_type,
@@ -155,19 +161,19 @@
 }
 
 TEST(pwd, getpwnam_oem_id_5000) {
-  check_get_passwd("oem_5000", 5000, TYPE_SYSTEM, false);
+  check_get_passwd("oem_5000", 5000, TYPE_VENDOR, false);
 }
 
 TEST(pwd, getpwnam_oem_id_5999) {
-  check_get_passwd("oem_5999", 5999, TYPE_SYSTEM, false);
+  check_get_passwd("oem_5999", 5999, TYPE_VENDOR, false);
 }
 
 TEST(pwd, getpwnam_oem_id_2900) {
-  check_get_passwd("oem_2900", 2900, TYPE_SYSTEM, false);
+  check_get_passwd("oem_2900", 2900, TYPE_VENDOR, false);
 }
 
 TEST(pwd, getpwnam_oem_id_2999) {
-  check_get_passwd("oem_2999", 2999, TYPE_SYSTEM, false);
+  check_get_passwd("oem_2999", 2999, TYPE_VENDOR, false);
 }
 
 TEST(pwd, getpwnam_app_id_nobody) {
diff --git a/tests/gtest_globals.cpp b/tests/gtest_globals.cpp
index 538a534..607544a 100644
--- a/tests/gtest_globals.cpp
+++ b/tests/gtest_globals.cpp
@@ -23,12 +23,9 @@
 
 #include <string>
 
-static std::string init_testlib_root() {
+std::string GetTestlibRoot() {
   // Calculate ANDROID_DATA assuming the binary is in "$ANDROID_DATA/somedir/binary-dir/binary"
-  std::string path = get_executable_path();
-
-  path = android::base::Dirname(path);
-  path += "/..";
+  std::string path = android::base::Dirname(android::base::GetExecutablePath()) + "/..";
 
   std::string out_path;
   if (!android::base::Realpath(path.c_str(), &out_path)) {
@@ -46,9 +43,3 @@
 
   return real_path;
 }
-
-const std::string& get_testlib_root() {
-  static const std::string testlib_root = init_testlib_root();
-  return testlib_root;
-}
-
diff --git a/tests/gtest_globals.h b/tests/gtest_globals.h
index 019849d..b3c7b10 100644
--- a/tests/gtest_globals.h
+++ b/tests/gtest_globals.h
@@ -21,6 +21,6 @@
 
 constexpr const char* kPrebuiltElfDir = "prebuilt-elf-files";
 
-const std::string& get_testlib_root();
+std::string GetTestlibRoot();
 
 #endif  // _BIONIC_TESTS_GTEST_GLOBALS_H
diff --git a/tests/gtest_globals_cts.cpp b/tests/gtest_globals_cts.cpp
index 2532ef1..8e67f29 100644
--- a/tests/gtest_globals_cts.cpp
+++ b/tests/gtest_globals_cts.cpp
@@ -17,9 +17,16 @@
 #include "gtest_globals.h"
 
 #include <string>
+#include <vector>
 
-static const std::string g_testlib_root = "/data/local/tmp/lib/bionic-loader-test-libs";
+// Use the normal gtest format so that cts can parse the results.
+extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
+  static const char* initial_args[] = {"--gtest_format"};
+  *args = initial_args;
+  *num_args = 1;
+  return true;
+}
 
-const std::string& get_testlib_root() {
-  return g_testlib_root;
+std::string GetTestlibRoot() {
+  return "/data/local/tmp/lib/bionic-loader-test-libs";
 }
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index ba29825..718db70 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -15,1294 +15,30 @@
  */
 
 #include <gtest/gtest.h>
+#include <gtest_extras/IsolateMain.h>
 
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <libgen.h>
-#include <limits.h>
-#include <signal.h>
-#include <spawn.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/wait.h>
-#include <unistd.h>
+#include "gtest_utils.h"
 
-#include <chrono>
-#include <string>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-
-#ifndef TEMP_FAILURE_RETRY
-
-/* Used to retry syscalls that can return EINTR. */
-#define TEMP_FAILURE_RETRY(exp) ({         \
-    __typeof__(exp) _rc;                   \
-    do {                                   \
-        _rc = (exp);                       \
-    } while (_rc == -1 && errno == EINTR); \
-    _rc; })
-
-#endif
-
-static std::string g_executable_path;
 static int g_argc;
 static char** g_argv;
 static char** g_envp;
 
-const std::string& get_executable_path() {
-  return g_executable_path;
-}
-
-int get_argc() {
+int GetArgc() {
   return g_argc;
 }
 
-char** get_argv() {
+char** GetArgv() {
   return g_argv;
 }
 
-char** get_envp() {
+char** GetEnvp() {
   return g_envp;
 }
 
-static constexpr const char* COLOR_RESET  = "\033[m";
-static constexpr const char* COLOR_RED    = "\033[0;31m";
-static constexpr const char* COLOR_GREEN  = "\033[0;32m";
-static constexpr const char* COLOR_YELLOW = "\033[0;33m";
-
-static bool ShouldUseColor() {
-  const auto& gtest_color = ::testing::GTEST_FLAG(color);
-  if (gtest_color == "yes" || gtest_color == "true" || gtest_color == "t") {
-    return true;
-  }
-  if (gtest_color != "auto") {
-    return false;
-  }
-
-  bool stdout_is_tty = isatty(STDOUT_FILENO) != 0;
-  if (!stdout_is_tty) {
-    return false;
-  }
-
-  const char* const term = getenv("COLORTERM");
-  return term != nullptr && term[0] != 0;
-}
-
-static void ColoredPrintf(const char* const color, const char* fmt, ...) {
-  static const bool use_color = ShouldUseColor();
-
-  va_list args;
-  va_start(args, fmt);
-
-  if (!use_color) {
-    vprintf(fmt, args);
-  } else {
-    printf("%s", color);
-    vprintf(fmt, args);
-    printf("%s", COLOR_RESET);
-  }
-
-  va_end(args);
-}
-
-constexpr int DEFAULT_GLOBAL_TEST_RUN_DEADLINE_MS = 90000;
-constexpr int DEFAULT_GLOBAL_TEST_RUN_SLOW_THRESHOLD_MS = 2000;
-
-// The time each test can run before killed for the reason of timeout.
-// It takes effect only with --isolate option.
-static int global_test_run_deadline_ms = DEFAULT_GLOBAL_TEST_RUN_DEADLINE_MS;
-
-// The time each test can run before be warned for too much running time.
-// It takes effect only with --isolate option.
-static int global_test_run_slow_threshold_ms = DEFAULT_GLOBAL_TEST_RUN_SLOW_THRESHOLD_MS;
-
-// Return timeout duration for a test, in ms.
-static int GetTimeoutMs(const std::string& /*test_name*/) {
-  return global_test_run_deadline_ms;
-}
-
-// Return threshold for calling a test slow, in ms.
-static int GetSlowThresholdMs(const std::string& /*test_name*/) {
-  return global_test_run_slow_threshold_ms;
-}
-
-static void PrintHelpInfo() {
-  printf("Bionic Unit Test Options:\n"
-         "  -j [JOB_COUNT] or -j[JOB_COUNT]\n"
-         "      Run up to JOB_COUNT tests in parallel.\n"
-         "      Use isolation mode, Run each test in a separate process.\n"
-         "      If JOB_COUNT is not given, it is set to the count of available processors.\n"
-         "  --no-isolate\n"
-         "      Don't use isolation mode, run all tests in a single process.\n"
-         "  --deadline=[TIME_IN_MS]\n"
-         "      Run each test in no longer than [TIME_IN_MS] time.\n"
-         "      Only valid in isolation mode. Default deadline is 90000 ms.\n"
-         "  --slow-threshold=[TIME_IN_MS]\n"
-         "      Test running longer than [TIME_IN_MS] will be called slow.\n"
-         "      Only valid in isolation mode. Default slow threshold is 2000 ms.\n"
-         "  --gtest-filter=POSITIVE_PATTERNS[-NEGATIVE_PATTERNS]\n"
-         "      Used as a synonym for --gtest_filter option in gtest.\n"
-         "Default bionic unit test option is -j.\n"
-         "In isolation mode, you can send SIGQUIT to the parent process to show current\n"
-         "running tests, or send SIGINT to the parent process to stop testing and\n"
-         "clean up current running tests.\n"
-         "\n");
-}
-
-enum TestResult {
-  TEST_SUCCESS = 0,
-  TEST_FAILED,
-  TEST_TIMEOUT
-};
-
-class Test {
- public:
-  Test() {} // For std::vector<Test>.
-  explicit Test(const char* name) : name_(name) {}
-
-  const std::string& GetName() const { return name_; }
-
-  void SetResult(TestResult result) {
-    // Native xfails are inherently likely to actually be relying on undefined
-    // behavior/uninitialized memory, and thus likely to pass from time to time
-    // on CTS. Avoid that unpleasantness by just rewriting all xfail failures
-    // as successes. You'll still see the actual failure details.
-    if (GetName().find("xfail") == 0) result = TEST_SUCCESS;
-    result_ = result;
-  }
-
-  TestResult GetResult() const { return result_; }
-
-  void SetTestTime(int64_t elapsed_time_ns) { elapsed_time_ns_ = elapsed_time_ns; }
-
-  int64_t GetTestTime() const { return elapsed_time_ns_; }
-
-  void AppendTestOutput(const std::string& s) { output_ += s; }
-
-  const std::string& GetTestOutput() const { return output_; }
-
- private:
-  const std::string name_;
-  TestResult result_;
-  int64_t elapsed_time_ns_;
-  std::string output_;
-};
-
-class TestCase {
- public:
-  TestCase() {} // For std::vector<TestCase>.
-  explicit TestCase(const char* name) : name_(name) {}
-
-  const std::string& GetName() const { return name_; }
-
-  void AppendTest(const char* test_name) {
-    test_list_.push_back(Test(test_name));
-  }
-
-  size_t TestCount() const { return test_list_.size(); }
-
-  std::string GetTestName(size_t test_id) const {
-    VerifyTestId(test_id);
-    return name_ + "." + test_list_[test_id].GetName();
-  }
-
-  Test& GetTest(size_t test_id) {
-    VerifyTestId(test_id);
-    return test_list_[test_id];
-  }
-
-  const Test& GetTest(size_t test_id) const {
-    VerifyTestId(test_id);
-    return test_list_[test_id];
-  }
-
-  void SetTestResult(size_t test_id, TestResult result) {
-    VerifyTestId(test_id);
-    test_list_[test_id].SetResult(result);
-  }
-
-  TestResult GetTestResult(size_t test_id) const {
-    VerifyTestId(test_id);
-    return test_list_[test_id].GetResult();
-  }
-
-  bool GetTestSuccess(size_t test_id) const {
-    return GetTestResult(test_id) == TEST_SUCCESS;
-  }
-
-  void SetTestTime(size_t test_id, int64_t elapsed_time_ns) {
-    VerifyTestId(test_id);
-    test_list_[test_id].SetTestTime(elapsed_time_ns);
-  }
-
-  int64_t GetTestTime(size_t test_id) const {
-    VerifyTestId(test_id);
-    return test_list_[test_id].GetTestTime();
-  }
-
- private:
-  void VerifyTestId(size_t test_id) const {
-    if(test_id >= test_list_.size()) {
-      fprintf(stderr, "test_id %zu out of range [0, %zu)\n", test_id, test_list_.size());
-      exit(1);
-    }
-  }
-
- private:
-  const std::string name_;
-  std::vector<Test> test_list_;
-};
-
-class TestResultPrinter : public testing::EmptyTestEventListener {
- public:
-  TestResultPrinter() : pinfo_(nullptr) {}
-  virtual void OnTestStart(const testing::TestInfo& test_info) {
-    pinfo_ = &test_info; // Record test_info for use in OnTestPartResult.
-  }
-  virtual void OnTestPartResult(const testing::TestPartResult& result);
-
- private:
-  const testing::TestInfo* pinfo_;
-};
-
-// Called after an assertion failure.
-void TestResultPrinter::OnTestPartResult(const testing::TestPartResult& result) {
-  // If the test part succeeded, we don't need to do anything.
-  if (result.type() == testing::TestPartResult::kSuccess)
-    return;
-
-  // Print failure message from the assertion (e.g. expected this and got that).
-  printf("%s:(%d) Failure in test %s.%s\n%s\n", result.file_name(), result.line_number(),
-         pinfo_->test_case_name(), pinfo_->name(), result.message());
-  fflush(stdout);
-}
-
-static int64_t NanoTime() {
-  std::chrono::nanoseconds duration(std::chrono::steady_clock::now().time_since_epoch());
-  return static_cast<int64_t>(duration.count());
-}
-
-static bool EnumerateTests(int argc, char** argv, std::vector<TestCase>& testcase_list) {
-  std::vector<const char*> args(argv, argv + argc);
-  args.push_back("--gtest_list_tests");
-  args.push_back(nullptr);
-
-  // We use posix_spawn(3) rather than the simpler popen(3) because we don't want an intervening
-  // surprise shell invocation making quoting interesting for --gtest_filter (http://b/68949647).
-
-  android::base::unique_fd read_fd;
-  android::base::unique_fd write_fd;
-  if (!android::base::Pipe(&read_fd, &write_fd)) {
-    perror("pipe");
-    return false;
-  }
-
-  posix_spawn_file_actions_t fa;
-  posix_spawn_file_actions_init(&fa);
-  posix_spawn_file_actions_addclose(&fa, read_fd);
-  posix_spawn_file_actions_adddup2(&fa, write_fd, 1);
-  posix_spawn_file_actions_adddup2(&fa, write_fd, 2);
-  posix_spawn_file_actions_addclose(&fa, write_fd);
-
-  pid_t pid;
-  int result = posix_spawnp(&pid, argv[0], &fa, nullptr, const_cast<char**>(args.data()), nullptr);
-  posix_spawn_file_actions_destroy(&fa);
-  if (result == -1) {
-    perror("posix_spawn");
-    return false;
-  }
-  write_fd.reset();
-
-  std::string content;
-  if (!android::base::ReadFdToString(read_fd, &content)) {
-    perror("ReadFdToString");
-    return false;
-  }
-
-  for (auto& line : android::base::Split(content, "\n")) {
-    line = android::base::Split(line, "#")[0];
-    line = android::base::Trim(line);
-    if (line.empty()) continue;
-    if (android::base::EndsWith(line, ".")) {
-      line.pop_back();
-      testcase_list.push_back(TestCase(line.c_str()));
-    } else {
-      if (testcase_list.empty()) {
-        // Invalid response from gtest - likely it has been upset by an invalid --gtest_* flag.
-        // Relay the message to user.
-        fprintf(stderr, "%s", content.c_str());
-        return false;
-      }
-      testcase_list.back().AppendTest(line.c_str());
-    }
-  }
-
-  int status;
-  if (TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)) != pid) {
-    perror("waitpid");
-    return false;
-  }
-  return (WIFEXITED(status) && WEXITSTATUS(status) == 0);
-}
-
-// Part of the following *Print functions are copied from external/gtest/src/gtest.cc:
-// PrettyUnitTestResultPrinter. The reason for copy is that PrettyUnitTestResultPrinter
-// is defined and used in gtest.cc, which is hard to reuse.
-static void OnTestIterationStartPrint(const std::vector<TestCase>& testcase_list, size_t iteration,
-                                      int iteration_count, size_t job_count) {
-  if (iteration_count != 1) {
-    printf("\nRepeating all tests (iteration %zu) . . .\n\n", iteration);
-  }
-  ColoredPrintf(COLOR_GREEN,  "[==========] ");
-
-  size_t testcase_count = testcase_list.size();
-  size_t test_count = 0;
-  for (const auto& testcase : testcase_list) {
-    test_count += testcase.TestCount();
-  }
-
-  printf("Running %zu %s from %zu %s (%zu %s).\n",
-         test_count, (test_count == 1) ? "test" : "tests",
-         testcase_count, (testcase_count == 1) ? "test case" : "test cases",
-         job_count, (job_count == 1) ? "job" : "jobs");
-  fflush(stdout);
-}
-
-// bionic cts test needs gtest output format.
-#if defined(USING_GTEST_OUTPUT_FORMAT)
-
-static void OnTestEndPrint(const TestCase& testcase, size_t test_id) {
-  ColoredPrintf(COLOR_GREEN, "[ RUN      ] ");
-  printf("%s\n", testcase.GetTestName(test_id).c_str());
-
-  const std::string& test_output = testcase.GetTest(test_id).GetTestOutput();
-  printf("%s", test_output.c_str());
-
-  TestResult result = testcase.GetTestResult(test_id);
-  if (result == TEST_SUCCESS) {
-    ColoredPrintf(COLOR_GREEN, "[       OK ] ");
-  } else {
-    ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
-  }
-  printf("%s", testcase.GetTestName(test_id).c_str());
-  if (testing::GTEST_FLAG(print_time)) {
-    printf(" (%" PRId64 " ms)", testcase.GetTestTime(test_id) / 1000000);
-  }
-  printf("\n");
-  fflush(stdout);
-}
-
-#else  // !defined(USING_GTEST_OUTPUT_FORMAT)
-
-static void OnTestEndPrint(const TestCase& testcase, size_t test_id) {
-  TestResult result = testcase.GetTestResult(test_id);
-  if (result == TEST_SUCCESS) {
-    ColoredPrintf(COLOR_GREEN, "[    OK    ] ");
-  } else if (result == TEST_FAILED) {
-    ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
-  } else if (result == TEST_TIMEOUT) {
-    ColoredPrintf(COLOR_RED, "[ TIMEOUT  ] ");
-  }
-
-  printf("%s", testcase.GetTestName(test_id).c_str());
-  if (testing::GTEST_FLAG(print_time)) {
-    printf(" (%" PRId64 " ms)", testcase.GetTestTime(test_id) / 1000000);
-  }
-  printf("\n");
-
-  const std::string& test_output = testcase.GetTest(test_id).GetTestOutput();
-  printf("%s", test_output.c_str());
-  fflush(stdout);
-}
-
-#endif  // !defined(USING_GTEST_OUTPUT_FORMAT)
-
-static void OnTestIterationEndPrint(const std::vector<TestCase>& testcase_list, size_t /*iteration*/,
-                                    int64_t elapsed_time_ns) {
-
-  std::vector<std::string> fail_test_name_list;
-  std::vector<std::pair<std::string, int64_t>> timeout_test_list;
-
-  // For tests that were slow but didn't time out.
-  std::vector<std::tuple<std::string, int64_t, int>> slow_test_list;
-  size_t testcase_count = testcase_list.size();
-  size_t test_count = 0;
-  size_t success_test_count = 0;
-  size_t expected_failure_count = 0;
-
-  for (const auto& testcase : testcase_list) {
-    test_count += testcase.TestCount();
-    for (size_t i = 0; i < testcase.TestCount(); ++i) {
-      TestResult result = testcase.GetTestResult(i);
-      if (result == TEST_TIMEOUT) {
-        timeout_test_list.push_back(
-            std::make_pair(testcase.GetTestName(i), testcase.GetTestTime(i)));
-      } else if (result == TEST_SUCCESS) {
-        ++success_test_count;
-        if (testcase.GetTestName(i).find(".xfail_") != std::string::npos) ++expected_failure_count;
-      } else if (result == TEST_FAILED) {
-          fail_test_name_list.push_back(testcase.GetTestName(i));
-      }
-      if (result != TEST_TIMEOUT &&
-          testcase.GetTestTime(i) / 1000000 >= GetSlowThresholdMs(testcase.GetTestName(i))) {
-        slow_test_list.push_back(std::make_tuple(testcase.GetTestName(i),
-                                                 testcase.GetTestTime(i),
-                                                 GetSlowThresholdMs(testcase.GetTestName(i))));
-      }
-    }
-  }
-
-  ColoredPrintf(COLOR_GREEN,  "[==========] ");
-  printf("%zu %s from %zu %s ran.", test_count, (test_count == 1) ? "test" : "tests",
-                                    testcase_count, (testcase_count == 1) ? "test case" : "test cases");
-  if (testing::GTEST_FLAG(print_time)) {
-    printf(" (%" PRId64 " ms total)", elapsed_time_ns / 1000000);
-  }
-  printf("\n");
-  ColoredPrintf(COLOR_GREEN,  "[   PASS   ] ");
-  printf("%zu %s.", success_test_count, (success_test_count == 1) ? "test" : "tests");
-  if (expected_failure_count > 0) {
-    printf(" (%zu expected failure%s.)", expected_failure_count,
-           (expected_failure_count == 1) ? "" : "s");
-  }
-  printf("\n");
-
-  // Print tests that timed out.
-  size_t timeout_test_count = timeout_test_list.size();
-  if (timeout_test_count > 0) {
-    ColoredPrintf(COLOR_RED, "[ TIMEOUT  ] ");
-    printf("%zu %s, listed below:\n", timeout_test_count, (timeout_test_count == 1) ? "test" : "tests");
-    for (const auto& timeout_pair : timeout_test_list) {
-      ColoredPrintf(COLOR_RED, "[ TIMEOUT  ] ");
-      printf("%s (stopped at %" PRId64 " ms)\n", timeout_pair.first.c_str(),
-                                                 timeout_pair.second / 1000000);
-    }
-  }
-
-  // Print tests that were slow.
-  size_t slow_test_count = slow_test_list.size();
-  if (slow_test_count > 0) {
-    ColoredPrintf(COLOR_YELLOW, "[   SLOW   ] ");
-    printf("%zu %s, listed below:\n", slow_test_count, (slow_test_count == 1) ? "test" : "tests");
-    for (const auto& slow_tuple : slow_test_list) {
-      ColoredPrintf(COLOR_YELLOW, "[   SLOW   ] ");
-      printf("%s (%" PRId64 " ms, exceeded %d ms)\n", std::get<0>(slow_tuple).c_str(),
-             std::get<1>(slow_tuple) / 1000000, std::get<2>(slow_tuple));
-    }
-  }
-
-  // Print tests that failed.
-  size_t fail_test_count = fail_test_name_list.size();
-  if (fail_test_count > 0) {
-    ColoredPrintf(COLOR_RED,  "[   FAIL   ] ");
-    printf("%zu %s, listed below:\n", fail_test_count, (fail_test_count == 1) ? "test" : "tests");
-    for (const auto& name : fail_test_name_list) {
-      ColoredPrintf(COLOR_RED, "[   FAIL   ] ");
-      printf("%s\n", name.c_str());
-    }
-  }
-
-  if (timeout_test_count > 0 || slow_test_count > 0 || fail_test_count > 0) {
-    printf("\n");
-  }
-
-  if (timeout_test_count > 0) {
-    printf("%2zu TIMEOUT %s\n", timeout_test_count, (timeout_test_count == 1) ? "TEST" : "TESTS");
-  }
-  if (slow_test_count > 0) {
-    printf("%2zu SLOW %s\n", slow_test_count, (slow_test_count == 1) ? "TEST" : "TESTS");
-  }
-  if (fail_test_count > 0) {
-    printf("%2zu FAILED %s\n", fail_test_count, (fail_test_count == 1) ? "TEST" : "TESTS");
-  }
-
-  fflush(stdout);
-}
-
-std::string XmlEscape(const std::string& xml) {
-  std::string escaped;
-  escaped.reserve(xml.size());
-
-  for (auto c : xml) {
-    switch (c) {
-    case '<':
-      escaped.append("&lt;");
-      break;
-    case '>':
-      escaped.append("&gt;");
-      break;
-    case '&':
-      escaped.append("&amp;");
-      break;
-    case '\'':
-      escaped.append("&apos;");
-      break;
-    case '"':
-      escaped.append("&quot;");
-      break;
-    default:
-      escaped.append(1, c);
-      break;
-    }
-  }
-
-  return escaped;
-}
-
-// Output xml file when --gtest_output is used, write this function as we can't reuse
-// gtest.cc:XmlUnitTestResultPrinter. The reason is XmlUnitTestResultPrinter is totally
-// defined in gtest.cc and not expose to outside. What's more, as we don't run gtest in
-// the parent process, we don't have gtest classes which are needed by XmlUnitTestResultPrinter.
-void OnTestIterationEndXmlPrint(const std::string& xml_output_filename,
-                                const std::vector<TestCase>& testcase_list,
-                                time_t epoch_iteration_start_time,
-                                int64_t elapsed_time_ns) {
-  FILE* fp = fopen(xml_output_filename.c_str(), "we");
-  if (fp == nullptr) {
-    fprintf(stderr, "failed to open '%s': %s\n", xml_output_filename.c_str(), strerror(errno));
-    exit(1);
-  }
-
-  size_t total_test_count = 0;
-  size_t total_failed_count = 0;
-  std::vector<size_t> failed_count_list(testcase_list.size(), 0);
-  std::vector<int64_t> elapsed_time_list(testcase_list.size(), 0);
-  for (size_t i = 0; i < testcase_list.size(); ++i) {
-    auto& testcase = testcase_list[i];
-    total_test_count += testcase.TestCount();
-    for (size_t j = 0; j < testcase.TestCount(); ++j) {
-      if (!testcase.GetTestSuccess(j)) {
-        ++failed_count_list[i];
-      }
-      elapsed_time_list[i] += testcase.GetTestTime(j);
-    }
-    total_failed_count += failed_count_list[i];
-  }
-
-  const tm* time_struct = localtime(&epoch_iteration_start_time);
-  char timestamp[40];
-  snprintf(timestamp, sizeof(timestamp), "%4d-%02d-%02dT%02d:%02d:%02d",
-           time_struct->tm_year + 1900, time_struct->tm_mon + 1, time_struct->tm_mday,
-           time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
-
-  fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", fp);
-  fprintf(fp, "<testsuites tests=\"%zu\" failures=\"%zu\" disabled=\"0\" errors=\"0\"",
-          total_test_count, total_failed_count);
-  fprintf(fp, " timestamp=\"%s\" time=\"%.3lf\" name=\"AllTests\">\n", timestamp, elapsed_time_ns / 1e9);
-  for (size_t i = 0; i < testcase_list.size(); ++i) {
-    auto& testcase = testcase_list[i];
-    fprintf(fp, "  <testsuite name=\"%s\" tests=\"%zu\" failures=\"%zu\" disabled=\"0\" errors=\"0\"",
-            testcase.GetName().c_str(), testcase.TestCount(), failed_count_list[i]);
-    fprintf(fp, " time=\"%.3lf\">\n", elapsed_time_list[i] / 1e9);
-
-    for (size_t j = 0; j < testcase.TestCount(); ++j) {
-      fprintf(fp, "    <testcase name=\"%s\" status=\"run\" time=\"%.3lf\" classname=\"%s\"",
-              testcase.GetTest(j).GetName().c_str(), testcase.GetTestTime(j) / 1e9,
-              testcase.GetName().c_str());
-      if (!testcase.GetTestSuccess(j)) {
-        fputs(" />\n", fp);
-      } else {
-        fputs(">\n", fp);
-        const std::string& test_output = testcase.GetTest(j).GetTestOutput();
-        const std::string escaped_test_output = XmlEscape(test_output);
-        fprintf(fp, "      <failure message=\"%s\" type=\"\">\n", escaped_test_output.c_str());
-        fputs("      </failure>\n", fp);
-        fputs("    </testcase>\n", fp);
-      }
-    }
-
-    fputs("  </testsuite>\n", fp);
-  }
-  fputs("</testsuites>\n", fp);
-  fclose(fp);
-}
-
-static bool sigint_flag;
-static bool sigquit_flag;
-
-static void signal_handler(int sig) {
-  if (sig == SIGINT) {
-    sigint_flag = true;
-  } else if (sig == SIGQUIT) {
-    sigquit_flag = true;
-  }
-}
-
-static bool RegisterSignalHandler() {
-  sigint_flag = false;
-  sigquit_flag = false;
-  sig_t ret = signal(SIGINT, signal_handler);
-  if (ret != SIG_ERR) {
-    ret = signal(SIGQUIT, signal_handler);
-  }
-  if (ret == SIG_ERR) {
-    perror("RegisterSignalHandler");
-    return false;
-  }
-  return true;
-}
-
-static bool UnregisterSignalHandler() {
-  sig_t ret = signal(SIGINT, SIG_DFL);
-  if (ret != SIG_ERR) {
-    ret = signal(SIGQUIT, SIG_DFL);
-  }
-  if (ret == SIG_ERR) {
-    perror("UnregisterSignalHandler");
-    return false;
-  }
-  return true;
-}
-
-struct ChildProcInfo {
-  pid_t pid;
-  int64_t start_time_ns;
-  int64_t end_time_ns;
-  int64_t deadline_end_time_ns; // The time when the test is thought of as timeout.
-  size_t testcase_id, test_id;
-  bool finished;
-  bool timed_out;
-  int exit_status;
-  int child_read_fd; // File descriptor to read child test failure info.
-};
-
-// Forked Child process, run the single test.
-static void ChildProcessFn(int argc, char** argv, const std::string& test_name) {
-  char** new_argv = new char*[argc + 2];
-  memcpy(new_argv, argv, sizeof(char*) * argc);
-
-  char* filter_arg = new char [test_name.size() + 20];
-  strcpy(filter_arg, "--gtest_filter=");
-  strcat(filter_arg, test_name.c_str());
-  new_argv[argc] = filter_arg;
-  new_argv[argc + 1] = nullptr;
-
-  int new_argc = argc + 1;
-  testing::InitGoogleTest(&new_argc, new_argv);
-  int result = RUN_ALL_TESTS();
-  exit(result);
-}
-
-static ChildProcInfo RunChildProcess(const std::string& test_name, int testcase_id, int test_id,
-                                     int argc, char** argv) {
-  int pipefd[2];
-  if (pipe(pipefd) == -1) {
-    perror("pipe in RunTestInSeparateProc");
-    exit(1);
-  }
-  if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) == -1) {
-    perror("fcntl in RunTestInSeparateProc");
-    exit(1);
-  }
-  pid_t pid = fork();
-  if (pid == -1) {
-    perror("fork in RunTestInSeparateProc");
-    exit(1);
-  } else if (pid == 0) {
-    // In child process, run a single test.
-    close(pipefd[0]);
-    close(STDOUT_FILENO);
-    close(STDERR_FILENO);
-    dup2(pipefd[1], STDOUT_FILENO);
-    dup2(pipefd[1], STDERR_FILENO);
-
-    if (!UnregisterSignalHandler()) {
-      exit(1);
-    }
-    ChildProcessFn(argc, argv, test_name);
-    // Unreachable.
-  }
-  // In parent process, initialize child process info.
-  close(pipefd[1]);
-  ChildProcInfo child_proc;
-  child_proc.child_read_fd = pipefd[0];
-  child_proc.pid = pid;
-  child_proc.start_time_ns = NanoTime();
-  child_proc.deadline_end_time_ns = child_proc.start_time_ns + GetTimeoutMs(test_name) * 1000000LL;
-  child_proc.testcase_id = testcase_id;
-  child_proc.test_id = test_id;
-  child_proc.finished = false;
-  return child_proc;
-}
-
-static void HandleSignals(std::vector<TestCase>& testcase_list,
-                            std::vector<ChildProcInfo>& child_proc_list) {
-  if (sigquit_flag) {
-    sigquit_flag = false;
-    // Print current running tests.
-    printf("List of current running tests:\n");
-    for (const auto& child_proc : child_proc_list) {
-      if (child_proc.pid != 0) {
-        std::string test_name = testcase_list[child_proc.testcase_id].GetTestName(child_proc.test_id);
-        int64_t current_time_ns = NanoTime();
-        int64_t run_time_ms = (current_time_ns - child_proc.start_time_ns) / 1000000;
-        printf("  %s (%" PRId64 " ms)\n", test_name.c_str(), run_time_ms);
-      }
-    }
-  } else if (sigint_flag) {
-    sigint_flag = false;
-    // Kill current running tests.
-    for (const auto& child_proc : child_proc_list) {
-      if (child_proc.pid != 0) {
-        // Send SIGKILL to ensure the child process can be killed unconditionally.
-        kill(child_proc.pid, SIGKILL);
-      }
-    }
-    // SIGINT kills the parent process as well.
-    exit(1);
-  }
-}
-
-static bool CheckChildProcExit(pid_t exit_pid, int exit_status,
-                               std::vector<ChildProcInfo>& child_proc_list) {
-  for (size_t i = 0; i < child_proc_list.size(); ++i) {
-    if (child_proc_list[i].pid == exit_pid) {
-      child_proc_list[i].finished = true;
-      child_proc_list[i].timed_out = false;
-      child_proc_list[i].exit_status = exit_status;
-      child_proc_list[i].end_time_ns = NanoTime();
-      return true;
-    }
-  }
-  return false;
-}
-
-static size_t CheckChildProcTimeout(std::vector<ChildProcInfo>& child_proc_list) {
-  int64_t current_time_ns = NanoTime();
-  size_t timeout_child_count = 0;
-  for (size_t i = 0; i < child_proc_list.size(); ++i) {
-    if (child_proc_list[i].deadline_end_time_ns <= current_time_ns) {
-      child_proc_list[i].finished = true;
-      child_proc_list[i].timed_out = true;
-      child_proc_list[i].end_time_ns = current_time_ns;
-      ++timeout_child_count;
-    }
-  }
-  return timeout_child_count;
-}
-
-static void ReadChildProcOutput(std::vector<TestCase>& testcase_list,
-                                std::vector<ChildProcInfo>& child_proc_list) {
-  for (const auto& child_proc : child_proc_list) {
-    TestCase& testcase = testcase_list[child_proc.testcase_id];
-    int test_id = child_proc.test_id;
-    while (true) {
-      char buf[1024];
-      ssize_t bytes_read = TEMP_FAILURE_RETRY(read(child_proc.child_read_fd, buf, sizeof(buf) - 1));
-      if (bytes_read > 0) {
-        buf[bytes_read] = '\0';
-        testcase.GetTest(test_id).AppendTestOutput(buf);
-      } else if (bytes_read == 0) {
-        break; // Read end.
-      } else {
-        if (errno == EAGAIN) {
-          break;
-        }
-        perror("failed to read child_read_fd");
-        exit(1);
-      }
-    }
-  }
-}
-
-static void WaitChildProcs(std::vector<TestCase>& testcase_list,
-                           std::vector<ChildProcInfo>& child_proc_list) {
-  size_t finished_child_count = 0;
-  while (true) {
-    int status;
-    pid_t result;
-    while ((result = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG))) > 0) {
-      if (CheckChildProcExit(result, status, child_proc_list)) {
-        ++finished_child_count;
-      }
-    }
-
-    if (result == -1) {
-      if (errno == ECHILD) {
-        // This happens when we have no running child processes.
-        return;
-      } else {
-        perror("waitpid");
-        exit(1);
-      }
-    } else if (result == 0) {
-      finished_child_count += CheckChildProcTimeout(child_proc_list);
-    }
-
-    ReadChildProcOutput(testcase_list, child_proc_list);
-    if (finished_child_count > 0) {
-      return;
-    }
-
-    HandleSignals(testcase_list, child_proc_list);
-
-    // sleep 1 ms to avoid busy looping.
-    timespec sleep_time;
-    sleep_time.tv_sec = 0;
-    sleep_time.tv_nsec = 1000000;
-    nanosleep(&sleep_time, nullptr);
-  }
-}
-
-static TestResult WaitForOneChild(pid_t pid) {
-  int exit_status;
-  pid_t result = TEMP_FAILURE_RETRY(waitpid(pid, &exit_status, 0));
-
-  TestResult test_result = TEST_SUCCESS;
-  if (result != pid || WEXITSTATUS(exit_status) != 0) {
-    test_result = TEST_FAILED;
-  }
-  return test_result;
-}
-
-static void CollectChildTestResult(const ChildProcInfo& child_proc, TestCase& testcase) {
-  int test_id = child_proc.test_id;
-  testcase.SetTestTime(test_id, child_proc.end_time_ns - child_proc.start_time_ns);
-  if (child_proc.timed_out) {
-    // The child process marked as timed_out has not exited, and we should kill it manually.
-    kill(child_proc.pid, SIGKILL);
-    WaitForOneChild(child_proc.pid);
-  }
-  close(child_proc.child_read_fd);
-
-  if (child_proc.timed_out) {
-    testcase.SetTestResult(test_id, TEST_TIMEOUT);
-    char buf[1024];
-    snprintf(buf, sizeof(buf), "%s killed because of timeout at %" PRId64 " ms.\n",
-             testcase.GetTestName(test_id).c_str(), testcase.GetTestTime(test_id) / 1000000);
-    testcase.GetTest(test_id).AppendTestOutput(buf);
-
-  } else if (WIFSIGNALED(child_proc.exit_status)) {
-    // Record signal terminated test as failed.
-    testcase.SetTestResult(test_id, TEST_FAILED);
-    char buf[1024];
-    snprintf(buf, sizeof(buf), "%s terminated by signal: %s.\n",
-             testcase.GetTestName(test_id).c_str(), strsignal(WTERMSIG(child_proc.exit_status)));
-    testcase.GetTest(test_id).AppendTestOutput(buf);
-
-  } else {
-    int exitcode = WEXITSTATUS(child_proc.exit_status);
-    testcase.SetTestResult(test_id, exitcode == 0 ? TEST_SUCCESS : TEST_FAILED);
-    if (exitcode != 0) {
-      char buf[1024];
-      snprintf(buf, sizeof(buf), "%s exited with exitcode %d.\n",
-               testcase.GetTestName(test_id).c_str(), exitcode);
-      testcase.GetTest(test_id).AppendTestOutput(buf);
-    }
-  }
-}
-
-// We choose to use multi-fork and multi-wait here instead of multi-thread, because it always
-// makes deadlock to use fork in multi-thread.
-// Returns true if all tests run successfully, otherwise return false.
-static bool RunTestInSeparateProc(int argc, char** argv, std::vector<TestCase>& testcase_list,
-                                  int iteration_count, size_t job_count,
-                                  const std::string& xml_output_filename) {
-  // Stop default result printer to avoid environment setup/teardown information for each test.
-  testing::UnitTest::GetInstance()->listeners().Release(
-                        testing::UnitTest::GetInstance()->listeners().default_result_printer());
-  testing::UnitTest::GetInstance()->listeners().Append(new TestResultPrinter);
-
-  if (!RegisterSignalHandler()) {
-    exit(1);
-  }
-
-  bool all_tests_passed = true;
-
-  for (size_t iteration = 1;
-       iteration_count < 0 || iteration <= static_cast<size_t>(iteration_count);
-       ++iteration) {
-    OnTestIterationStartPrint(testcase_list, iteration, iteration_count, job_count);
-    int64_t iteration_start_time_ns = NanoTime();
-    time_t epoch_iteration_start_time = time(nullptr);
-
-    // Run up to job_count tests in parallel, each test in a child process.
-    std::vector<ChildProcInfo> child_proc_list;
-
-    // Next test to run is [next_testcase_id:next_test_id].
-    size_t next_testcase_id = 0;
-    size_t next_test_id = 0;
-
-    // Record how many tests are finished.
-    std::vector<size_t> finished_test_count_list(testcase_list.size(), 0);
-    size_t finished_testcase_count = 0;
-
-    while (finished_testcase_count < testcase_list.size()) {
-      // run up to job_count child processes.
-      while (child_proc_list.size() < job_count && next_testcase_id < testcase_list.size()) {
-        std::string test_name = testcase_list[next_testcase_id].GetTestName(next_test_id);
-        ChildProcInfo child_proc = RunChildProcess(test_name, next_testcase_id, next_test_id,
-                                                   argc, argv);
-        child_proc_list.push_back(child_proc);
-        if (++next_test_id == testcase_list[next_testcase_id].TestCount()) {
-          next_test_id = 0;
-          ++next_testcase_id;
-        }
-      }
-
-      // Wait for any child proc finish or timeout.
-      WaitChildProcs(testcase_list, child_proc_list);
-
-      // Collect result.
-      auto it = child_proc_list.begin();
-      while (it != child_proc_list.end()) {
-        auto& child_proc = *it;
-        if (child_proc.finished == true) {
-          size_t testcase_id = child_proc.testcase_id;
-          size_t test_id = child_proc.test_id;
-          TestCase& testcase = testcase_list[testcase_id];
-
-          CollectChildTestResult(child_proc, testcase);
-          OnTestEndPrint(testcase, test_id);
-
-          if (++finished_test_count_list[testcase_id] == testcase.TestCount()) {
-            ++finished_testcase_count;
-          }
-          if (!testcase.GetTestSuccess(test_id)) {
-            all_tests_passed = false;
-          }
-
-          it = child_proc_list.erase(it);
-        } else {
-          ++it;
-        }
-      }
-    }
-
-    int64_t elapsed_time_ns = NanoTime() - iteration_start_time_ns;
-    OnTestIterationEndPrint(testcase_list, iteration, elapsed_time_ns);
-    if (!xml_output_filename.empty()) {
-      OnTestIterationEndXmlPrint(xml_output_filename, testcase_list, epoch_iteration_start_time,
-                                 elapsed_time_ns);
-    }
-  }
-
-  if (!UnregisterSignalHandler()) {
-    exit(1);
-  }
-
-  return all_tests_passed;
-}
-
-static size_t GetDefaultJobCount() {
-  return static_cast<size_t>(sysconf(_SC_NPROCESSORS_ONLN));
-}
-
-static void AddPathSeparatorInTestProgramPath(std::vector<char*>& args) {
-  // To run DeathTest in threadsafe mode, gtest requires that the user must invoke the
-  // test program via a valid path that contains at least one path separator.
-  // The reason is that gtest uses clone() + execve() to run DeathTest in threadsafe mode,
-  // and execve() doesn't read environment variable PATH, so execve() will not success
-  // until we specify the absolute path or relative path of the test program directly.
-  if (strchr(args[0], '/') == nullptr) {
-    args[0] = strdup(g_executable_path.c_str());
-  }
-}
-
-static void AddGtestFilterSynonym(std::vector<char*>& args) {
-  // Support --gtest-filter as a synonym for --gtest_filter.
-  for (size_t i = 1; i < args.size(); ++i) {
-    if (strncmp(args[i], "--gtest-filter", strlen("--gtest-filter")) == 0) {
-      args[i][7] = '_';
-    }
-  }
-}
-
-struct IsolationTestOptions {
-  bool isolate;
-  size_t job_count;
-  int test_deadline_ms;
-  int test_slow_threshold_ms;
-  std::string gtest_color;
-  bool gtest_print_time;
-  int gtest_repeat;
-  std::string gtest_output;
-};
-
-// Pick options not for gtest: There are two parts in args, one part is used in isolation test mode
-// as described in PrintHelpInfo(), the other part is handled by testing::InitGoogleTest() in
-// gtest. PickOptions() picks the first part into IsolationTestOptions structure, leaving the second
-// part in args.
-// Arguments:
-//   args is used to pass in all command arguments, and pass out only the part of options for gtest.
-//   options is used to pass out test options in isolation mode.
-// Return false if there is error in arguments.
-static bool PickOptions(std::vector<char*>& args, IsolationTestOptions& options) {
-  for (size_t i = 1; i < args.size(); ++i) {
-    if (strcmp(args[i], "--help") == 0 || strcmp(args[i], "-h") == 0) {
-      PrintHelpInfo();
-      options.isolate = false;
-      return true;
-    }
-  }
-
-  AddPathSeparatorInTestProgramPath(args);
-  AddGtestFilterSynonym(args);
-
-  // if --bionic-selftest argument is used, only enable self tests, otherwise remove self tests.
-  bool enable_selftest = false;
-  for (size_t i = 1; i < args.size(); ++i) {
-    if (strcmp(args[i], "--bionic-selftest") == 0) {
-      // This argument is to enable "bionic_selftest*" for self test, and is not shown in help info.
-      // Don't remove this option from arguments.
-      enable_selftest = true;
-    }
-  }
-  std::string gtest_filter_str;
-  for (size_t i = args.size() - 1; i >= 1; --i) {
-    if (strncmp(args[i], "--gtest_filter=", strlen("--gtest_filter=")) == 0) {
-      gtest_filter_str = args[i] + strlen("--gtest_filter=");
-      args.erase(args.begin() + i);
-      break;
-    }
-  }
-  if (enable_selftest == true) {
-    gtest_filter_str = "bionic_selftest*";
-  } else {
-    if (gtest_filter_str.empty()) {
-      gtest_filter_str = "-bionic_selftest*";
-    } else {
-      // Find if '-' for NEGATIVE_PATTERNS exists.
-      if (gtest_filter_str.find('-') != std::string::npos) {
-        gtest_filter_str += ":bionic_selftest*";
-      } else {
-        gtest_filter_str += ":-bionic_selftest*";
-      }
-    }
-  }
-  gtest_filter_str = "--gtest_filter=" + gtest_filter_str;
-  args.push_back(strdup(gtest_filter_str.c_str()));
-
-  options.isolate = true;
-  // Parse arguments that make us can't run in isolation mode.
-  for (size_t i = 1; i < args.size(); ++i) {
-    if (strcmp(args[i], "--no-isolate") == 0) {
-      options.isolate = false;
-    } else if (strcmp(args[i], "--gtest_list_tests") == 0) {
-      options.isolate = false;
-    }
-  }
-
-  // Stop parsing if we will not run in isolation mode.
-  if (options.isolate == false) {
-    return true;
-  }
-
-  // Init default isolation test options.
-  options.job_count = GetDefaultJobCount();
-  options.test_deadline_ms = DEFAULT_GLOBAL_TEST_RUN_DEADLINE_MS;
-  options.test_slow_threshold_ms = DEFAULT_GLOBAL_TEST_RUN_SLOW_THRESHOLD_MS;
-  options.gtest_color = testing::GTEST_FLAG(color);
-  options.gtest_print_time = testing::GTEST_FLAG(print_time);
-  options.gtest_repeat = testing::GTEST_FLAG(repeat);
-  options.gtest_output = testing::GTEST_FLAG(output);
-
-  // Parse arguments speficied for isolation mode.
-  for (size_t i = 1; i < args.size(); ++i) {
-    if (strncmp(args[i], "-j", strlen("-j")) == 0) {
-      char* p = args[i] + strlen("-j");
-      int count = 0;
-      if (*p != '\0') {
-        // Argument like -j5.
-        count = atoi(p);
-      } else if (args.size() > i + 1) {
-        // Arguments like -j 5.
-        count = atoi(args[i + 1]);
-        ++i;
-      }
-      if (count <= 0) {
-        fprintf(stderr, "invalid job count: %d\n", count);
-        return false;
-      }
-      options.job_count = static_cast<size_t>(count);
-    } else if (strncmp(args[i], "--deadline=", strlen("--deadline=")) == 0) {
-      int time_ms = atoi(args[i] + strlen("--deadline="));
-      if (time_ms <= 0) {
-        fprintf(stderr, "invalid deadline: %d\n", time_ms);
-        return false;
-      }
-      options.test_deadline_ms = time_ms;
-    } else if (strncmp(args[i], "--slow-threshold=", strlen("--slow-threshold=")) == 0) {
-      int time_ms = atoi(args[i] + strlen("--slow-threshold="));
-      if (time_ms <= 0) {
-        fprintf(stderr, "invalid slow test threshold: %d\n", time_ms);
-        return false;
-      }
-      options.test_slow_threshold_ms = time_ms;
-    } else if (strncmp(args[i], "--gtest_color=", strlen("--gtest_color=")) == 0) {
-      options.gtest_color = args[i] + strlen("--gtest_color=");
-    } else if (strcmp(args[i], "--gtest_print_time=0") == 0) {
-      options.gtest_print_time = false;
-    } else if (strncmp(args[i], "--gtest_repeat=", strlen("--gtest_repeat=")) == 0) {
-      // If the value of gtest_repeat is < 0, then it indicates the tests
-      // should be repeated forever.
-      options.gtest_repeat = atoi(args[i] + strlen("--gtest_repeat="));
-      // Remove --gtest_repeat=xx from arguments, so child process only run one iteration for a single test.
-      args.erase(args.begin() + i);
-      --i;
-    } else if (strncmp(args[i], "--gtest_output=", strlen("--gtest_output=")) == 0) {
-      std::string output = args[i] + strlen("--gtest_output=");
-      // generate output xml file path according to the strategy in gtest.
-      bool success = true;
-      if (strncmp(output.c_str(), "xml:", strlen("xml:")) == 0) {
-        output = output.substr(strlen("xml:"));
-        if (output.size() == 0) {
-          success = false;
-        }
-        // Make absolute path.
-        if (success && output[0] != '/') {
-          char* cwd = getcwd(nullptr, 0);
-          if (cwd != nullptr) {
-            output = std::string(cwd) + "/" + output;
-            free(cwd);
-          } else {
-            success = false;
-          }
-        }
-        // Add file name if output is a directory.
-        if (success && output.back() == '/') {
-          output += "test_details.xml";
-        }
-      }
-      if (success) {
-        options.gtest_output = output;
-      } else {
-        fprintf(stderr, "invalid gtest_output file: %s\n", args[i]);
-        return false;
-      }
-
-      // Remove --gtest_output=xxx from arguments, so child process will not write xml file.
-      args.erase(args.begin() + i);
-      --i;
-    }
-  }
-
-  // Add --no-isolate in args to prevent child process from running in isolation mode again.
-  // As DeathTest will try to call execve(), this argument should always be added.
-  args.insert(args.begin() + 1, strdup("--no-isolate"));
-  return true;
-}
-
-static std::string get_proc_self_exe() {
-  char path[PATH_MAX];
-  ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
-  if (path_len <= 0 || path_len >= static_cast<ssize_t>(sizeof(path))) {
-    perror("readlink");
-    exit(1);
-  }
-
-  return std::string(path, path_len);
-}
-
 int main(int argc, char** argv, char** envp) {
-  g_executable_path = get_proc_self_exe();
   g_argc = argc;
   g_argv = argv;
   g_envp = envp;
-  std::vector<char*> arg_list(argv, argv + argc);
 
-  IsolationTestOptions options;
-  if (PickOptions(arg_list, options) == false) {
-    return 1;
-  }
-
-  if (options.isolate == true) {
-    // Set global variables.
-    global_test_run_deadline_ms = options.test_deadline_ms;
-    global_test_run_slow_threshold_ms = options.test_slow_threshold_ms;
-    testing::GTEST_FLAG(color) = options.gtest_color.c_str();
-    testing::GTEST_FLAG(print_time) = options.gtest_print_time;
-    std::vector<TestCase> testcase_list;
-
-    argc = static_cast<int>(arg_list.size());
-    arg_list.push_back(nullptr);
-    if (EnumerateTests(argc, arg_list.data(), testcase_list) == false) {
-      return 1;
-    }
-    bool all_test_passed =  RunTestInSeparateProc(argc, arg_list.data(), testcase_list,
-                              options.gtest_repeat, options.job_count, options.gtest_output);
-    return all_test_passed ? 0 : 1;
-  } else {
-    argc = static_cast<int>(arg_list.size());
-    arg_list.push_back(nullptr);
-    testing::InitGoogleTest(&argc, arg_list.data());
-    return RUN_ALL_TESTS();
-  }
-}
-
-//################################################################################
-// Bionic Gtest self test, run this by --bionic-selftest option.
-
-TEST(bionic_selftest, test_success) {
-  ASSERT_EQ(1, 1);
-}
-
-TEST(bionic_selftest, test_fail) {
-  ASSERT_EQ(0, 1);
-}
-
-TEST(bionic_selftest, test_time_warn) {
-  sleep(4);
-}
-
-TEST(bionic_selftest, test_timeout) {
-  while (1) {}
-}
-
-TEST(bionic_selftest, test_signal_SEGV_terminated) {
-  char* p = reinterpret_cast<char*>(static_cast<intptr_t>(atoi("0")));
-  *p = 3;
-}
-
-class bionic_selftest_DeathTest : public ::testing::Test {
- protected:
-  virtual void SetUp() {
-    ::testing::FLAGS_gtest_death_test_style = "threadsafe";
-  }
-};
-
-static void deathtest_helper_success() {
-  ASSERT_EQ(1, 1);
-  exit(0);
-}
-
-TEST_F(bionic_selftest_DeathTest, success) {
-  ASSERT_EXIT(deathtest_helper_success(), ::testing::ExitedWithCode(0), "");
-}
-
-static void deathtest_helper_fail() {
-  ASSERT_EQ(1, 0);
-}
-
-TEST_F(bionic_selftest_DeathTest, fail) {
-  ASSERT_EXIT(deathtest_helper_fail(), ::testing::ExitedWithCode(0), "");
-}
-
-class BionicSelfTest : public ::testing::TestWithParam<bool> {
-};
-
-TEST_P(BionicSelfTest, test_success) {
-  ASSERT_EQ(GetParam(), GetParam());
-}
-
-INSTANTIATE_TEST_CASE_P(bionic_selftest, BionicSelfTest, ::testing::Values(true, false));
-
-template <typename T>
-class bionic_selftest_TestT : public ::testing::Test {
-};
-
-typedef ::testing::Types<char, int> MyTypes;
-
-TYPED_TEST_CASE(bionic_selftest_TestT, MyTypes);
-
-TYPED_TEST(bionic_selftest_TestT, test_success) {
-  ASSERT_EQ(true, true);
+  return IsolateMain(argc, argv, envp);
 }
diff --git a/libm/arm64/ceil.S b/tests/gtest_utils.h
similarity index 75%
rename from libm/arm64/ceil.S
rename to tests/gtest_utils.h
index 7217d57..9a0b556 100644
--- a/libm/arm64/ceil.S
+++ b/tests/gtest_utils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,14 +14,9 @@
  * limitations under the License.
  */
 
-#include <private/bionic_asm.h>
+#pragma once
 
-ENTRY(ceil)
-  frintP d0, d0
-  ret
-END(ceil)
-
-ENTRY(ceilf)
-  frintP s0, s0
-  ret
-END(ceilf)
+// Access to argc/argv/envp
+int GetArgc();
+char** GetArgv();
+char** GetEnvp();
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 4161c90..c4f13f6 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -26,6 +26,12 @@
 
 #include "private/bionic_config.h"
 
+#if defined(__BIONIC__)
+#define HAVE_REALLOCARRAY 1
+#else
+#define HAVE_REALLOCARRAY __GLIBC_PREREQ(2, 26)
+#endif
+
 TEST(malloc, malloc_std) {
   // Simple malloc test.
   void *ptr = malloc(100);
@@ -497,3 +503,31 @@
   // mallopt doesn't set errno.
   ASSERT_EQ(0, errno);
 }
+
+TEST(malloc, reallocarray_overflow) {
+#if HAVE_REALLOCARRAY
+  // Values that cause overflow to a result small enough (8 on LP64) that malloc would "succeed".
+  size_t a = static_cast<size_t>(INTPTR_MIN + 4);
+  size_t b = 2;
+
+  errno = 0;
+  ASSERT_TRUE(reallocarray(nullptr, a, b) == nullptr);
+  ASSERT_EQ(ENOMEM, errno);
+
+  errno = 0;
+  ASSERT_TRUE(reallocarray(nullptr, b, a) == nullptr);
+  ASSERT_EQ(ENOMEM, errno);
+#else
+  GTEST_LOG_(INFO) << "This test requires a C library with reallocarray.\n";
+#endif
+}
+
+TEST(malloc, reallocarray) {
+#if HAVE_REALLOCARRAY
+  void* p = reallocarray(nullptr, 2, 32);
+  ASSERT_TRUE(p != nullptr);
+  ASSERT_GE(malloc_usable_size(p), 64U);
+#else
+  GTEST_LOG_(INFO) << "This test requires a C library with reallocarray.\n";
+#endif
+}
diff --git a/tests/membarrier_test.cpp b/tests/membarrier_test.cpp
new file mode 100644
index 0000000..9e871c7
--- /dev/null
+++ b/tests/membarrier_test.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2018 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>
+
+// membarrier(2) is only supported for bionic builds (b/111199492).
+#if defined(__BIONIC__)
+
+#include <linux/membarrier.h>
+#include <sys/syscall.h>
+
+class ScopedErrnoCleaner {
+ public:
+  ScopedErrnoCleaner() { errno = 0; }
+  ~ScopedErrnoCleaner() { errno = 0; }
+};
+
+bool HasMembarrier(int membarrier_cmd) {
+  ScopedErrnoCleaner errno_cleaner;
+  int supported_cmds = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
+  return (supported_cmds > 0) && ((supported_cmds & membarrier_cmd) != 0);
+}
+
+TEST(membarrier, query) {
+  ScopedErrnoCleaner errno_cleaner;
+  int supported = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
+  if (errno == 0) {
+    ASSERT_TRUE(supported >= 0);
+  } else {
+    ASSERT_TRUE(errno == ENOSYS && supported == -1);
+  }
+}
+
+TEST(membarrier, global_barrier) {
+  if (!HasMembarrier(MEMBARRIER_CMD_GLOBAL)) {
+    GTEST_LOG_(INFO) << "MEMBARRIER_CMD_GLOBAL not supported, skipping test.";
+    return;
+  }
+  ASSERT_EQ(0, syscall(__NR_membarrier, MEMBARRIER_CMD_GLOBAL, 0));
+}
+
+static const char* MembarrierCommandToName(int membarrier_cmd) {
+  switch (membarrier_cmd) {
+  case MEMBARRIER_CMD_QUERY:
+    return "MEMBARRIER_CMD_QUERY";
+  case MEMBARRIER_CMD_GLOBAL:
+    return "MEMBARRIER_CMD_GLOBAL";
+  case MEMBARRIER_CMD_GLOBAL_EXPEDITED:
+    return "MEMBARRIER_CMD_GLOBAL_EXPEDITED";
+  case MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED:
+    return "MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED";
+  case MEMBARRIER_CMD_PRIVATE_EXPEDITED:
+    return "MEMBARRIER_CMD_PRIVATE_EXPEDITED";
+  case MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED:
+    return "MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED";
+  case MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE:
+    return "MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE";
+  case MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE:
+    return "MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE";
+  default:
+    return "MEMBARRIER_UNKNOWN";
+  }
+}
+
+static void TestRegisterAndBarrierCommands(int membarrier_cmd_register,
+                                           int membarrier_cmd_barrier) {
+  if (!HasMembarrier(membarrier_cmd_register)) {
+    GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_register)
+        << " not supported, skipping test.";
+    return;
+  }
+  if (!HasMembarrier(membarrier_cmd_barrier)) {
+    GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_barrier)
+        << " not supported, skipping test.";
+    return;
+  }
+
+  ScopedErrnoCleaner errno_cleaner;
+
+  // Check barrier use without prior registration.
+  if (membarrier_cmd_register == MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED) {
+    // Global barrier use is always okay.
+    ASSERT_EQ(0, syscall(__NR_membarrier, membarrier_cmd_barrier, 0));
+  } else {
+    // Private barrier should fail.
+    ASSERT_EQ(-1, syscall(__NR_membarrier, membarrier_cmd_barrier, 0));
+    ASSERT_EQ(EPERM, errno);
+    errno = 0;
+  }
+
+  // Check registration for barrier succeeds.
+  ASSERT_EQ(0, syscall(__NR_membarrier, membarrier_cmd_register, 0));
+
+  // Check barrier use after registration succeeds.
+  ASSERT_EQ(0, syscall(__NR_membarrier, membarrier_cmd_barrier, 0));
+}
+
+TEST(membarrier, global_expedited) {
+  TestRegisterAndBarrierCommands(MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED,
+                                 MEMBARRIER_CMD_GLOBAL_EXPEDITED);
+}
+
+TEST(membarrier, private_expedited) {
+  TestRegisterAndBarrierCommands(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED,
+                                 MEMBARRIER_CMD_PRIVATE_EXPEDITED);
+}
+
+TEST(membarrier, private_expedited_sync_core) {
+  TestRegisterAndBarrierCommands(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE,
+                                 MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE);
+}
+
+#endif  // __BIONIC__
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index d96da02..54b913a 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -2356,6 +2356,52 @@
   ASSERT_EQ(buf, "hello");
 }
 
+TEST(STDIO_TEST, printf_m) {
+  char buf[BUFSIZ];
+  errno = 0;
+  snprintf(buf, sizeof(buf), "<%m>");
+  ASSERT_STREQ("<Success>", buf);
+  errno = -1;
+  snprintf(buf, sizeof(buf), "<%m>");
+  ASSERT_STREQ("<Unknown error -1>", buf);
+  errno = EINVAL;
+  snprintf(buf, sizeof(buf), "<%m>");
+  ASSERT_STREQ("<Invalid argument>", buf);
+}
+
+TEST(STDIO_TEST, printf_m_does_not_clobber_strerror) {
+  char buf[BUFSIZ];
+  const char* m = strerror(-1);
+  ASSERT_STREQ("Unknown error -1", m);
+  errno = -2;
+  snprintf(buf, sizeof(buf), "<%m>");
+  ASSERT_STREQ("<Unknown error -2>", buf);
+  ASSERT_STREQ("Unknown error -1", m);
+}
+
+TEST(STDIO_TEST, wprintf_m) {
+  wchar_t buf[BUFSIZ];
+  errno = 0;
+  swprintf(buf, sizeof(buf), L"<%m>");
+  ASSERT_EQ(std::wstring(L"<Success>"), buf);
+  errno = -1;
+  swprintf(buf, sizeof(buf), L"<%m>");
+  ASSERT_EQ(std::wstring(L"<Unknown error -1>"), buf);
+  errno = EINVAL;
+  swprintf(buf, sizeof(buf), L"<%m>");
+  ASSERT_EQ(std::wstring(L"<Invalid argument>"), buf);
+}
+
+TEST(STDIO_TEST, wprintf_m_does_not_clobber_strerror) {
+  wchar_t buf[BUFSIZ];
+  const char* m = strerror(-1);
+  ASSERT_STREQ("Unknown error -1", m);
+  errno = -2;
+  swprintf(buf, sizeof(buf), L"<%m>");
+  ASSERT_EQ(std::wstring(L"<Unknown error -2>"), buf);
+  ASSERT_STREQ("Unknown error -1", m);
+}
+
 TEST(STDIO_TEST, fopen_append_mode_and_ftell) {
   TemporaryFile tf;
   SetFileTo(tf.filename, "0123456789");
diff --git a/tools/versioner/src/Android.bp b/tools/versioner/src/Android.bp
index 4b237a9..f138cc3 100644
--- a/tools/versioner/src/Android.bp
+++ b/tools/versioner/src/Android.bp
@@ -3,6 +3,9 @@
 
     cpp_std: "gnu++17",
 
+    // b/117120485 bugprone-exception-escape hangs with DeclarationDatabase.cpp
+    tidy_checks: ["-bugprone-exception-escape"],
+
     srcs: [
         "versioner.cpp",
         "Arch.cpp",