Merge "Create a filegroup for versioner dependencies" into main
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
index f31e127..ffb5921 100644
--- a/benchmarks/Android.bp
+++ b/benchmarks/Android.bp
@@ -57,6 +57,7 @@
         "stdio_benchmark.cpp",
         "stdlib_benchmark.cpp",
         "string_benchmark.cpp",
+        "syscall_mmap_benchmark.cpp",
         "time_benchmark.cpp",
         "unistd_benchmark.cpp",
         "wctype_benchmark.cpp",
diff --git a/benchmarks/bionic_benchmarks.cpp b/benchmarks/bionic_benchmarks.cpp
index 74966c0..c0f956b 100644
--- a/benchmarks/bionic_benchmarks.cpp
+++ b/benchmarks/bionic_benchmarks.cpp
@@ -521,12 +521,22 @@
   all_sizes.insert(all_sizes.end(), kMediumSizes.begin(), kMediumSizes.end());
   all_sizes.insert(all_sizes.end(), kLargeSizes.begin(), kLargeSizes.end());
 
+  int page_sz = getpagesize();
+  std::vector<int> sub_page_sizes = {page_sz / 2, page_sz / 4, page_sz / 8};
+  std::vector<int> multi_page_sizes = {page_sz, page_sz * 2, page_sz * 3, page_sz * 10,
+                                       page_sz * 100};
+  std::vector<int> all_page_sizes(sub_page_sizes);
+  all_page_sizes.insert(all_page_sizes.end(), multi_page_sizes.begin(), multi_page_sizes.end());
+
   std::map<std::string, args_vector_t> args_shorthand {
     {"AT_COMMON_SIZES", GetArgs(kCommonSizes)},
     {"AT_SMALL_SIZES", GetArgs(kSmallSizes)},
     {"AT_MEDIUM_SIZES", GetArgs(kMediumSizes)},
     {"AT_LARGE_SIZES", GetArgs(kLargeSizes)},
     {"AT_ALL_SIZES", GetArgs(all_sizes)},
+    {"AT_SUB_PAGE_SIZES", GetArgs(sub_page_sizes)},
+    {"AT_MULTI_PAGE_SIZES", GetArgs(multi_page_sizes)},
+    {"AT_All_PAGE_SIZES", GetArgs(all_page_sizes)},
 
     {"AT_ALIGNED_ONEBUF", GetArgs(kCommonSizes, 0)},
     {"AT_ALIGNED_ONEBUF_SMALL", GetArgs(kSmallSizes, 0)},
diff --git a/benchmarks/suites/syscall.xml b/benchmarks/suites/syscall.xml
new file mode 100644
index 0000000..c253a3f
--- /dev/null
+++ b/benchmarks/suites/syscall.xml
@@ -0,0 +1,52 @@
+<!-- mmap tests -->
+<fn>
+  <name>BM_syscall_mmap_anon_rw</name>
+  <iterations>10</iterations>
+  <args>AT_All_PAGE_SIZES</args>
+</fn>
+<fn>
+  <name>BM_syscall_mmap_anon_noreserve</name>
+  <iterations>10</iterations>
+  <args>AT_All_PAGE_SIZES</args>
+</fn>
+<fn>
+  <name>BM_syscall_mmap_anon_none</name>
+  <iterations>10</iterations>
+  <args>AT_All_PAGE_SIZES</args>
+</fn>
+<fn>
+  <name>BM_syscall_mmap_anon_rw_fixed</name>
+  <iterations>10</iterations>
+  <args>AT_All_PAGE_SIZES</args>
+</fn>
+<fn>
+  <name>BM_syscall_mmap_anon_none_fixed</name>
+  <iterations>10</iterations>
+  <args>AT_All_PAGE_SIZES</args>
+</fn>
+<fn>
+  <name>BM_syscall_mmap_file_rd_priv</name>
+  <iterations>10</iterations>
+  <args>AT_All_PAGE_SIZES</args>
+</fn>
+<fn>
+  <name>BM_syscall_mmap_file_rw_shared</name>
+  <iterations>10</iterations>
+  <args>AT_All_PAGE_SIZES</args>
+</fn>
+<fn>
+  <name>BM_syscall_mmap_file_rw_priv_fixed_start</name>
+  <iterations>10</iterations>
+  <args>AT_All_PAGE_SIZES</args>
+</fn>
+<fn>
+  <name>BM_syscall_mmap_file_rw_priv_fixed_mid</name>
+  <iterations>10</iterations>
+  <args>AT_MULTI_PAGE_SIZES</args>
+</fn>
+<fn>
+  <name>BM_syscall_mmap_file_rw_priv_fixed_end</name>
+  <iterations>10</iterations>
+  <args>AT_MULTI_PAGE_SIZES</args>
+</fn>
+
diff --git a/benchmarks/syscall_mmap_benchmark.cpp b/benchmarks/syscall_mmap_benchmark.cpp
new file mode 100644
index 0000000..10bae1f
--- /dev/null
+++ b/benchmarks/syscall_mmap_benchmark.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2023 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 <string.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <benchmark/benchmark.h>
+
+#include "util.h"
+
+static size_t page_sz = getpagesize();
+
+struct MmapParams {
+  int prot;
+  int flags;
+  int64_t size;
+};
+
+// mmap syscall benchmarks
+static void MmapBenchmark(benchmark::State& state, const struct MmapParams& params, int fd,
+                          void* area = nullptr) {
+  for (auto _ : state) {
+    void* addr = mmap(area, params.size, params.prot, params.flags, fd, 0);
+    if (addr == MAP_FAILED) {
+      state.SkipWithError(android::base::StringPrintf("mmap failed: %s", strerror(errno)).c_str());
+      break;
+    }
+
+    if (params.prot & PROT_WRITE) {
+      MakeAllocationResident(addr, params.size, page_sz);
+    }
+
+    if (munmap(addr, params.size) != 0) {
+      state.SkipWithError(
+          android::base::StringPrintf("munmap failed: %s", strerror(errno)).c_str());
+      break;
+    }
+  }
+}
+
+static void MmapFixedBenchmark(benchmark::State& state, const struct MmapParams& params, int fd,
+                               size_t area_size, size_t offs) {
+  uint8_t* area = reinterpret_cast<uint8_t*>(mmap(0, area_size, params.prot, params.flags, fd, 0));
+  if (area == MAP_FAILED) {
+    state.SkipWithError(android::base::StringPrintf("mmap failed: %s", strerror(errno)).c_str());
+    return;
+  }
+
+  MmapBenchmark(state, params, fd, area + offs);
+
+  if (munmap(area, area_size) != 0) {
+    state.SkipWithError(android::base::StringPrintf("munmap failed: %s", strerror(errno)).c_str());
+    return;
+  }
+}
+
+static void MmapFileBenchmark(benchmark::State& state, const struct MmapParams& params,
+                              size_t area_size, size_t offs) {
+  TemporaryFile tf;
+
+  if (tf.fd < 0) {
+    state.SkipWithError(
+        android::base::StringPrintf("failed to create a temporary file: %s", strerror(errno))
+            .c_str());
+    return;
+  }
+
+  if (area_size > 0 && ftruncate(tf.fd, area_size)) {
+    state.SkipWithError(
+        android::base::StringPrintf("ftruncate failed: %s", strerror(errno)).c_str());
+    return;
+  }
+
+  if (params.flags & MAP_FIXED) {
+    MmapFixedBenchmark(state, params, tf.fd, area_size, offs);
+  } else {
+    MmapBenchmark(state, params, tf.fd);
+  }
+}
+
+// anon mmap
+static void BM_syscall_mmap_anon_rw(benchmark::State& state) {
+  struct MmapParams params = {
+      .prot = PROT_READ | PROT_WRITE,
+      .flags = MAP_PRIVATE | MAP_ANONYMOUS,
+      .size = state.range(0),
+  };
+
+  MmapBenchmark(state, params, 0);
+}
+BIONIC_BENCHMARK_WITH_ARG(BM_syscall_mmap_anon_rw, "AT_All_PAGE_SIZES");
+
+static void BM_syscall_mmap_anon_noreserve(benchmark::State& state) {
+  struct MmapParams params = {
+      .prot = PROT_NONE,
+      .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
+      .size = state.range(0),
+  };
+
+  MmapBenchmark(state, params, 0);
+}
+BIONIC_BENCHMARK_WITH_ARG(BM_syscall_mmap_anon_noreserve, "AT_All_PAGE_SIZES");
+
+static void BM_syscall_mmap_anon_none(benchmark::State& state) {
+  struct MmapParams params = {
+      .prot = PROT_NONE,
+      .flags = MAP_PRIVATE | MAP_ANONYMOUS,
+      .size = state.range(0),
+  };
+
+  MmapBenchmark(state, params, 0);
+}
+BIONIC_BENCHMARK_WITH_ARG(BM_syscall_mmap_anon_none, "AT_All_PAGE_SIZES");
+
+// anon fixed mmap
+static void BM_syscall_mmap_anon_rw_fixed(benchmark::State& state) {
+  struct MmapParams params = {
+      .prot = PROT_READ | PROT_WRITE,
+      .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
+      .size = state.range(0),
+  };
+
+  MmapFixedBenchmark(state, params, 0, params.size, 0);
+}
+BIONIC_BENCHMARK_WITH_ARG(BM_syscall_mmap_anon_rw_fixed, "AT_All_PAGE_SIZES");
+
+static void BM_syscall_mmap_anon_none_fixed(benchmark::State& state) {
+  struct MmapParams params = {
+      .prot = PROT_NONE,
+      .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
+      .size = state.range(0),
+  };
+
+  MmapFixedBenchmark(state, params, 0, params.size, 0);
+}
+BIONIC_BENCHMARK_WITH_ARG(BM_syscall_mmap_anon_none_fixed, "AT_All_PAGE_SIZES");
+
+// file mmap
+static void BM_syscall_mmap_file_rd_priv(benchmark::State& state) {
+  struct MmapParams params = {
+      .prot = PROT_READ,
+      .flags = MAP_PRIVATE,
+      .size = state.range(0),
+  };
+
+  MmapFileBenchmark(state, params, params.size, 0);
+}
+BIONIC_BENCHMARK_WITH_ARG(BM_syscall_mmap_file_rd_priv, "AT_All_PAGE_SIZES");
+
+static void BM_syscall_mmap_file_rw_shared(benchmark::State& state) {
+  struct MmapParams params = {
+      .prot = PROT_READ | PROT_WRITE,
+      .flags = MAP_SHARED,
+      .size = state.range(0),
+  };
+
+  MmapFileBenchmark(state, params, params.size, 0);
+}
+BIONIC_BENCHMARK_WITH_ARG(BM_syscall_mmap_file_rw_shared, "AT_All_PAGE_SIZES");
+
+// file fixed mmap
+static void BM_syscall_mmap_file_rw_priv_fixed_start(benchmark::State& state) {
+  struct MmapParams params = {
+      .prot = PROT_READ | PROT_WRITE,
+      .flags = MAP_PRIVATE | MAP_FIXED,
+      .size = state.range(0),
+  };
+
+  // allocate 3x area and map at the start
+  MmapFileBenchmark(state, params, params.size * 3, 0);
+}
+BIONIC_BENCHMARK_WITH_ARG(BM_syscall_mmap_file_rw_priv_fixed_start, "AT_All_PAGE_SIZES");
+
+static void BM_syscall_mmap_file_rw_priv_fixed_mid(benchmark::State& state) {
+  struct MmapParams params = {
+      .prot = PROT_READ | PROT_WRITE,
+      .flags = MAP_PRIVATE | MAP_FIXED,
+      .size = state.range(0),
+  };
+
+  // allocate 3x area and map at the middle
+  MmapFileBenchmark(state, params, params.size * 3, params.size);
+}
+// mapping at sub-page size offset is not supported, so run only for AT_MULTI_PAGE_SIZES
+BIONIC_BENCHMARK_WITH_ARG(BM_syscall_mmap_file_rw_priv_fixed_mid, "AT_MULTI_PAGE_SIZES");
+
+static void BM_syscall_mmap_file_rw_priv_fixed_end(benchmark::State& state) {
+  struct MmapParams params = {
+      .prot = PROT_READ | PROT_WRITE,
+      .flags = MAP_PRIVATE | MAP_FIXED,
+      .size = state.range(0),
+  };
+
+  // allocate 3x area and map at the end
+  MmapFileBenchmark(state, params, params.size * 3, params.size * 2);
+}
+// mapping at sub-page size offset is not supported, so run only for AT_MULTI_PAGE_SIZES
+BIONIC_BENCHMARK_WITH_ARG(BM_syscall_mmap_file_rw_priv_fixed_end, "AT_MULTI_PAGE_SIZES");
diff --git a/benchmarks/tests/interface_test.cpp b/benchmarks/tests/interface_test.cpp
index 1d620d1..b56866e 100644
--- a/benchmarks/tests/interface_test.cpp
+++ b/benchmarks/tests/interface_test.cpp
@@ -160,8 +160,10 @@
     "Google benchmark flags:\n"
     "benchmark [--benchmark_list_tests={true|false}]\n"
     "          [--benchmark_filter=<regex>]\n"
-    "          [--benchmark_min_time=<min_time>]\n"
+    "          [--benchmark_min_time=`<integer>x` OR `<float>s` ]\n"
+    "          [--benchmark_min_warmup_time=<min_warmup_time>]\n"
     "          [--benchmark_repetitions=<num_repetitions>]\n"
+    "          [--benchmark_enable_random_interleaving={true|false}]\n"
     "          [--benchmark_report_aggregates_only={true|false}]\n"
     "          [--benchmark_display_aggregates_only={true|false}]\n"
     "          [--benchmark_format=<console|json|csv>]\n"
@@ -169,6 +171,8 @@
     "          [--benchmark_out_format=<json|console|csv>]\n"
     "          [--benchmark_color={auto|true|false}]\n"
     "          [--benchmark_counters_tabular={true|false}]\n"
+    "          [--benchmark_context=<key>=<value>,...]\n"
+    "          [--benchmark_time_unit={ns|us|ms|s}]\n"
     "          [--v=<verbosity>]\n";
   Verify(expected, 0, std::vector<const char*>{"--help"}, false);
 }
diff --git a/libc/Android.bp b/libc/Android.bp
index 6b2e2ca..fe5f6de 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -951,6 +951,7 @@
                 "arch-riscv64/string/memcpy_vext.S",
                 "arch-riscv64/string/memmove_vext.S",
                 "arch-riscv64/string/memset_vext.S",
+                "arch-riscv64/string/stpcpy_vext.S",
                 "arch-riscv64/string/strcat_vext.S",
                 "arch-riscv64/string/strchr_vext.S",
                 "arch-riscv64/string/strcmp_vext.S",
diff --git a/libc/arch-riscv64/dynamic_function_dispatch.cpp b/libc/arch-riscv64/dynamic_function_dispatch.cpp
index 0925c5f..5866fe4 100644
--- a/libc/arch-riscv64/dynamic_function_dispatch.cpp
+++ b/libc/arch-riscv64/dynamic_function_dispatch.cpp
@@ -58,6 +58,11 @@
   RETURN_FUNC(memset_func, memset_vext);
 }
 
+typedef char* stpcpy_func(char*, const char*);
+DEFINE_IFUNC_FOR(stpcpy) {
+  RETURN_FUNC(stpcpy_func, stpcpy_vext);
+}
+
 typedef char* strcat_func(char*, const char*);
 DEFINE_IFUNC_FOR(strcat) {
   RETURN_FUNC(strcat_func, strcat_vext);
diff --git a/libc/arch-riscv64/static_function_dispatch.S b/libc/arch-riscv64/static_function_dispatch.S
index 3bf0275..f96d40e 100644
--- a/libc/arch-riscv64/static_function_dispatch.S
+++ b/libc/arch-riscv64/static_function_dispatch.S
@@ -40,6 +40,7 @@
 FUNCTION_DELEGATE(memcpy, memcpy_vext)
 FUNCTION_DELEGATE(memmove, memmove_vext)
 FUNCTION_DELEGATE(memset, memset_vext)
+FUNCTION_DELEGATE(stpcpy, stpcpy_vext)
 FUNCTION_DELEGATE(strcat, strcat_vext)
 FUNCTION_DELEGATE(strchr, strchr_vext)
 FUNCTION_DELEGATE(strcmp, strcmp_vext)
diff --git a/libc/arch-riscv64/string/stpcpy_vext.S b/libc/arch-riscv64/string/stpcpy_vext.S
new file mode 100644
index 0000000..3096e76
--- /dev/null
+++ b/libc/arch-riscv64/string/stpcpy_vext.S
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+/*
+ * Copyright (c) 2023 SiFive, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the company may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SIFIVE INC ``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 SIFIVE INC 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.
+ */
+
+#if defined(__riscv_v)
+
+#include <private/bionic_asm.h>
+
+#define pDstPtr a0
+#define pSrc a1
+
+#define iVL a3
+#define iCurrentVL a4
+#define iActiveElemPos a5
+
+#define ELEM_LMUL_SETTING m1
+#define vMask1 v0
+#define vMask2 v1
+#define vStr1 v8
+#define vStr2 v16
+
+ENTRY(stpcpy_vext)
+L(stpcpy_loop):
+    vsetvli iVL, zero, e8, ELEM_LMUL_SETTING, ta, ma
+    vle8ff.v vStr1, (pSrc)
+    vmseq.vx vMask2, vStr1, zero
+    csrr iCurrentVL, vl
+    vfirst.m iActiveElemPos, vMask2
+    vmsif.m vMask1, vMask2
+    add pSrc, pSrc, iCurrentVL
+    vse8.v vStr1, (pDstPtr), vMask1.t
+    add pDstPtr, pDstPtr, iCurrentVL
+    bltz iActiveElemPos, L(stpcpy_loop)
+
+    // stpcpy() returns a pointer to the '\0', not the byte after it.
+    addi pDstPtr, pDstPtr, -1
+    ret
+END(stpcpy_vext)
+
+#endif
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 287e757..3e7506c 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -211,11 +211,8 @@
       soinfo_do_lookup_impl<false>(name, vi, si_found_in, lookup_list);
 }
 
-soinfo::soinfo(android_namespace_t* ns, const char* realpath,
-               const struct stat* file_stat, off64_t file_offset,
-               int rtld_flags) {
-  memset(this, 0, sizeof(*this));
-
+soinfo::soinfo(android_namespace_t* ns, const char* realpath, const struct stat* file_stat,
+               off64_t file_offset, int rtld_flags) {
   if (realpath != nullptr) {
     realpath_ = realpath;
   }
diff --git a/tests/android_get_device_api_level.cpp b/tests/android_get_device_api_level.cpp
index 9bd6b3a..2e51022 100644
--- a/tests/android_get_device_api_level.cpp
+++ b/tests/android_get_device_api_level.cpp
@@ -28,12 +28,12 @@
 
 #include <gtest/gtest.h>
 
-#if __BIONIC__
+#if __has_include(<android/api-level.h>)
 #include <android/api-level.h>
 #endif
 
 TEST(android_get_device_api_level, smoke) {
-#if __BIONIC__
+#if defined(__BIONIC__)
   // This will fail if you run the tests on an old device, but who does that?
   ASSERT_GE(android_get_device_api_level(), 29);
 #endif
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index f8f559b..b3be18e 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -320,7 +320,7 @@
 }
 
 TEST(fcntl, open_O_TMPFILE_mode) {
-#if __BIONIC__ // Our glibc is too old for O_TMPFILE.
+#if defined(__BIONIC__)  // Our glibc is too old for O_TMPFILE.
   TemporaryDir dir;
   // Without O_EXCL, we're allowed to give this a name later.
   // (This is unrelated to the O_CREAT interaction with O_EXCL.)
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index cc3080d..12ea21b 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -29,7 +29,7 @@
 
 #include <android-base/silent_death_test.h>
 
-#if __BIONIC__
+#if defined(__BIONIC__)
 #define ASSERT_FORTIFY(expr) ASSERT_EXIT(expr, testing::KilledBySignal(SIGABRT), "FORTIFY")
 #else
 #define ASSERT_FORTIFY(expr) ASSERT_EXIT(expr, testing::KilledBySignal(SIGABRT), "")
@@ -412,9 +412,6 @@
   ASSERT_FORTIFY(sprintf(buf, "%s", source_buf));
 }
 
-#if !__has_attribute(alloc_size)
-// TODO: remove this after Clang prebuilt rebase.
-#else
 TEST_F(DEATHTEST, sprintf_malloc_fortified) {
   char* buf = (char *) malloc(10);
   char source_buf[11];
@@ -422,7 +419,6 @@
   ASSERT_FORTIFY(sprintf(buf, "%s", source_buf));
   free(buf);
 }
-#endif
 
 TEST_F(DEATHTEST, sprintf2_fortified) {
   char buf[5];
@@ -1014,7 +1010,7 @@
 }
 
 TEST_F(DEATHTEST, ppoll64_fortified) {
-#if __BIONIC__ // glibc doesn't have ppoll64.
+#if defined(__BIONIC__)        // glibc doesn't have ppoll64.
   nfds_t fd_count = atoi("2"); // suppress compiler optimizations
   pollfd buf[1] = {{0, POLLIN, 0}};
   // Set timeout to zero to prevent waiting in ppoll when fortify test fails.
@@ -1030,7 +1026,7 @@
 }
 
 TEST_F(DEATHTEST, open_O_TMPFILE_without_mode_fortified) {
-#if __BIONIC__ // Our glibc is too old for O_TMPFILE.
+#if defined(__BIONIC__)  // Our glibc is too old for O_TMPFILE.
   int flags = O_TMPFILE; // Fool the compiler.
   ASSERT_FORTIFY(open("", flags));
 #endif
diff --git a/tests/poll_test.cpp b/tests/poll_test.cpp
index 33143f8..5799fea 100644
--- a/tests/poll_test.cpp
+++ b/tests/poll_test.cpp
@@ -49,7 +49,7 @@
 }
 
 TEST(poll, ppoll64_null_fds) {
-#if __BIONIC__
+#if defined(__BIONIC__)
   // Because nanosleep(2) is relatively new to POSIX, code sometimes abuses poll.
   errno = 0;
   timespec ts = { .tv_nsec = 100 };
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 5e97c63..ca8e260 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -1269,7 +1269,7 @@
 }
 
 TEST(time, timespec_get) {
-#if __BIONIC__
+#if defined(__BIONIC__)
   timespec ts = {};
   ASSERT_EQ(TIME_UTC, timespec_get(&ts, TIME_UTC));
   ASSERT_EQ(TIME_MONOTONIC, timespec_get(&ts, TIME_MONOTONIC));
@@ -1281,7 +1281,7 @@
 }
 
 TEST(time, timespec_get_invalid) {
-#if __BIONIC__
+#if defined(__BIONIC__)
   timespec ts = {};
   ASSERT_EQ(0, timespec_get(&ts, 123));
 #else
@@ -1290,7 +1290,7 @@
 }
 
 TEST(time, timespec_getres) {
-#if __BIONIC__
+#if defined(__BIONIC__)
   timespec ts = {};
   ASSERT_EQ(TIME_UTC, timespec_getres(&ts, TIME_UTC));
   ASSERT_EQ(1, ts.tv_nsec);
@@ -1301,7 +1301,7 @@
 }
 
 TEST(time, timespec_getres_invalid) {
-#if __BIONIC__
+#if defined(__BIONIC__)
   timespec ts = {};
   ASSERT_EQ(0, timespec_getres(&ts, 123));
 #else
@@ -1315,7 +1315,7 @@
 }
 
 TEST(time, tzfree_null) {
-#if __BIONIC__
+#if defined(__BIONIC__)
   tzfree(nullptr);
 #else
   GTEST_SKIP() << "glibc doesn't have timezone_t";
@@ -1323,7 +1323,7 @@
 }
 
 TEST(time, localtime_rz) {
-#if __BIONIC__
+#if defined(__BIONIC__)
   setenv("TZ", "America/Los_Angeles", 1);
   tzset();
 
@@ -1377,7 +1377,7 @@
 }
 
 TEST(time, mktime_z) {
-#if __BIONIC__
+#if defined(__BIONIC__)
   setenv("TZ", "America/Los_Angeles", 1);
   tzset();
 
@@ -1417,7 +1417,7 @@
 }
 
 TEST(time, tzalloc_nullptr) {
-#if __BIONIC__
+#if defined(__BIONIC__)
   // tzalloc(nullptr) returns the system timezone.
   timezone_t default_tz = tzalloc(nullptr);
   ASSERT_NE(nullptr, default_tz);
@@ -1453,7 +1453,7 @@
 }
 
 TEST(time, tzalloc_unique_ptr) {
-#if __BIONIC__
+#if defined(__BIONIC__)
   std::unique_ptr<std::remove_pointer_t<timezone_t>, decltype(&tzfree)> tz{tzalloc("Asia/Seoul"),
                                                                            tzfree};
 #else
diff --git a/tests/utils.cpp b/tests/utils.cpp
index e470724..0c7c552 100644
--- a/tests/utils.cpp
+++ b/tests/utils.cpp
@@ -28,7 +28,9 @@
 
 #include "utils.h"
 
+#include <string.h>
 #include <syscall.h>
+
 #include <string>
 
 #include <android-base/properties.h>
@@ -72,8 +74,19 @@
 #endif
 
 void PrintTo(const Errno& e, std::ostream* os) {
-  // TODO: strerrorname_np() might be more useful here, but we'd need to implement it first!
-  *os << strerror(e.errno_);
+  // Prefer EINVAL or whatever, but fall back to strerror() to print
+  // "Unknown error 666" for bogus values. Not that I've ever seen one,
+  // but we shouldn't be looking at an assertion failure unless something
+  // weird has happened!
+#if defined(__BIONIC__)
+  const char* errno_name = strerrorname_np(e.errno_);
+  if (errno_name != nullptr) {
+    *os << errno_name;
+  } else
+#endif
+  {
+    *os << strerror(e.errno_);
+  }
 }
 
 bool operator==(const Errno& lhs, const Errno& rhs) {