Merge "tests: explain how to debug FileCheck failures"
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
index 93f62cf..6cda463 100644
--- a/benchmarks/Android.bp
+++ b/benchmarks/Android.bp
@@ -96,6 +96,9 @@
         "tests/benchmark_test.cpp",
         "tests/interface_test.cpp",
     ],
-    static_libs: ["libBionicBenchmarksUtils"],
+    static_libs: [
+        "libbase",
+        "libBionicBenchmarksUtils",
+    ],
     data: ["suites/test_*.xml"],
 }
diff --git a/benchmarks/stdio_benchmark.cpp b/benchmarks/stdio_benchmark.cpp
index 3f5e0f1..0e7f668 100644
--- a/benchmarks/stdio_benchmark.cpp
+++ b/benchmarks/stdio_benchmark.cpp
@@ -19,9 +19,20 @@
 #include <stdio_ext.h>
 #include <stdlib.h>
 
+#include <android-base/test_utils.h>
 #include <benchmark/benchmark.h>
 #include "util.h"
 
+static void FillFile(TemporaryFile& tf) {
+  char line[256];
+  memset(line, 'x', sizeof(line));
+  line[sizeof(line) - 1] = '\0';
+
+  FILE* fp = fopen(tf.path, "w");
+  for (size_t i = 0; i < 4096; ++i) fputs(line, fp);
+  fclose(fp);
+}
+
 template <typename Fn>
 void ReadWriteTest(benchmark::State& state, Fn f, bool buffered) {
   size_t chunk_size = state.range(0);
@@ -65,14 +76,39 @@
 }
 BIONIC_BENCHMARK(BM_stdio_fwrite_unbuffered);
 
-static void FopenFgetsFclose(benchmark::State& state, bool no_locking) {
-  size_t nbytes = state.range(0);
-  char buf[nbytes];
+#if !defined(__GLIBC__)
+static void FopenFgetlnFclose(benchmark::State& state, bool no_locking) {
+  TemporaryFile tf;
+  FillFile(tf);
   while (state.KeepRunning()) {
-    FILE* fp = fopen("/dev/zero", "re");
+    FILE* fp = fopen(tf.path, "re");
     if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER);
-    if (fgets(buf, sizeof(buf), fp) == nullptr) {
-      errx(1, "ERROR: fgets of %zu bytes failed.", nbytes);
+    size_t length;
+    while (fgetln(fp, &length) != nullptr) {
+    }
+    fclose(fp);
+  }
+}
+
+static void BM_stdio_fopen_fgetln_fclose_locking(benchmark::State& state) {
+  FopenFgetlnFclose(state, false);
+}
+BIONIC_BENCHMARK(BM_stdio_fopen_fgetln_fclose_locking);
+
+void BM_stdio_fopen_fgetln_fclose_no_locking(benchmark::State& state) {
+  FopenFgetlnFclose(state, true);
+}
+BIONIC_BENCHMARK(BM_stdio_fopen_fgetln_fclose_no_locking);
+#endif
+
+static void FopenFgetsFclose(benchmark::State& state, bool no_locking) {
+  TemporaryFile tf;
+  FillFile(tf);
+  char buf[BUFSIZ];
+  while (state.KeepRunning()) {
+    FILE* fp = fopen(tf.path, "re");
+    if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER);
+    while (fgets(buf, sizeof(buf), fp) != nullptr) {
     }
     fclose(fp);
   }
@@ -88,6 +124,31 @@
 }
 BIONIC_BENCHMARK(BM_stdio_fopen_fgets_fclose_no_locking);
 
+static void FopenGetlineFclose(benchmark::State& state, bool no_locking) {
+  TemporaryFile tf;
+  FillFile(tf);
+  while (state.KeepRunning()) {
+    FILE* fp = fopen(tf.path, "re");
+    if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER);
+    char* line = nullptr;
+    size_t n = 0;
+    while (getline(&line, &n, fp) != -1) {
+    }
+    free(line);
+    fclose(fp);
+  }
+}
+
+static void BM_stdio_fopen_getline_fclose_locking(benchmark::State& state) {
+  FopenGetlineFclose(state, false);
+}
+BIONIC_BENCHMARK(BM_stdio_fopen_getline_fclose_locking);
+
+void BM_stdio_fopen_getline_fclose_no_locking(benchmark::State& state) {
+  FopenGetlineFclose(state, true);
+}
+BIONIC_BENCHMARK(BM_stdio_fopen_getline_fclose_no_locking);
+
 static void FopenFgetcFclose(benchmark::State& state, bool no_locking) {
   size_t nbytes = state.range(0);
   while (state.KeepRunning()) {
diff --git a/benchmarks/suites/full.xml b/benchmarks/suites/full.xml
index 8c9aef6..fc58914 100644
--- a/benchmarks/suites/full.xml
+++ b/benchmarks/suites/full.xml
@@ -179,12 +179,16 @@
   <args>AT_COMMON_SIZES</args>
 </fn>
 <fn>
+  <name>BM_stdio_fopen_fgetln_fclose_locking</name>
+</fn>
+<fn>
+  <name>BM_stdio_fopen_fgetln_fclose_no_locking</name>
+</fn>
+<fn>
   <name>BM_stdio_fopen_fgets_fclose_locking</name>
-  <args>1024</args>
 </fn>
 <fn>
   <name>BM_stdio_fopen_fgets_fclose_no_locking</name>
-  <args>1024</args>
 </fn>
 <fn>
   <name>BM_stdio_fopen_fgetc_fclose_locking</name>
@@ -195,6 +199,12 @@
   <args>1024</args>
 </fn>
 <fn>
+  <name>BM_stdio_fopen_getline_fclose_locking</name>
+</fn>
+<fn>
+  <name>BM_stdio_fopen_getline_fclose_no_locking</name>
+</fn>
+<fn>
   <name>BM_string_memcmp</name>
   <args>AT_ALIGNED_TWOBUF</args>
 </fn>
diff --git a/benchmarks/tests/interface_test.cpp b/benchmarks/tests/interface_test.cpp
index 9283e6b..601dcc5 100644
--- a/benchmarks/tests/interface_test.cpp
+++ b/benchmarks/tests/interface_test.cpp
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 
+#include <android-base/file.h>
 #include <gtest/gtest.h>
 
 class SystemTests : public ::testing::Test {
@@ -49,6 +50,10 @@
   int fd_;
 };
 
+static std::string GetBionicXmlArg(const char* xml_file) {
+  return "--bionic_xml=" + android::base::GetExecutableDirectory() + "/suites/" + xml_file;
+}
+
 void SystemTests::SanitizeOutput() {
   // Cut off anything after the arguments, since that varies with time.
   sanitized_output_ = std::regex_replace(raw_output_, std::regex(".+(BM_\\S+) +.+"), "$1");
@@ -377,16 +382,17 @@
     "BM_stdlib_malloc_free/65536/0/iterations:1\n"
     "BM_stdlib_mbstowcs/0/0/iterations:1\n"
     "BM_stdlib_mbrtowc/0/iterations:1\n";
-  Verify(expected, 0, std::vector<const char *>{"--bionic_xml=suites/test_full.xml",
+  Verify(expected, 0, std::vector<const char *>{GetBionicXmlArg("test_full.xml").c_str(),
                                                 "--bionic_iterations=1"});
 }
 
 TEST_F(SystemTests, small) {
   std::string expected =
-    "BM_string_memcmp/8/8/8\n"
-    "BM_math_sqrt\n"
-    "BM_property_get/1\n";
-  Verify(expected, 0, std::vector<const char *>{"--bionic_xml=suites/test_small.xml"});
+    "BM_string_memcmp/8/8/8/iterations:1\n"
+    "BM_math_sqrt/iterations:1\n"
+    "BM_property_get/1/iterations:1\n";
+  Verify(expected, 0, std::vector<const char *>{GetBionicXmlArg("test_small.xml").c_str(),
+                                                "--bionic_iterations=1"});
 }
 
 TEST_F(SystemTests, medium) {
@@ -402,7 +408,7 @@
     "BM_math_sqrt/iterations:1\n"
     "BM_string_memcpy/512/4/4/iterations:25\n"
     "BM_property_get/1/iterations:1\n";
-  Verify(expected, 0, std::vector<const char *>{"--bionic_xml=suites/test_medium.xml",
+  Verify(expected, 0, std::vector<const char *>{GetBionicXmlArg("test_medium.xml").c_str(),
                                                 "--bionic_iterations=1"});
 }
 
@@ -417,7 +423,7 @@
     "BM_string_memcpy/512/4/4/iterations:1\n"
     "BM_time_clock_gettime/iterations:1\n"
     "BM_unistd_getpid/iterations:1\n";
-  Verify(expected, 0, std::vector<const char *>{"--bionic_xml=suites/test_from_each.xml",
+  Verify(expected, 0, std::vector<const char *>{GetBionicXmlArg("test_from_each.xml").c_str(),
                                                 "--bionic_iterations=1"});
 }
 
@@ -462,8 +468,8 @@
     "BM_math_log10/iterations:1\n";
   Verify(expected, 0, std::vector<const char *>{"--bionic_extra=BM_string_memcpy AT_ALIGNED_TWOBUF",
                                                 "--bionic_extra=BM_math_log10",
-                                                "--bionic_cpu -1",
-                                                "--bionic_xml=suites/test_medium.xml",
+                                                "--bionic_cpu=0",
+                                                GetBionicXmlArg("test_medium.xml").c_str(),
                                                 "--bionic_iterations=1"});
 }
 
@@ -549,6 +555,6 @@
     "BM_string_strlen/16384/2048/iterations:1\n"
     "BM_string_strlen/32768/2048/iterations:1\n"
     "BM_string_strlen/65536/2048/iterations:1\n";
-  Verify(expected, 0, std::vector<const char *>{"--bionic_xml=suites/test_alignment.xml",
-                                                "--bionic_iterations=100"});
+  Verify(expected, 0, std::vector<const char *>{GetBionicXmlArg("test_alignment.xml").c_str(),
+                                                "--bionic_iterations=1"});
 }
diff --git a/libc/bionic/assert.cpp b/libc/bionic/assert.cpp
index 41831cb..0f4ee97 100644
--- a/libc/bionic/assert.cpp
+++ b/libc/bionic/assert.cpp
@@ -39,7 +39,3 @@
 void __assert2(const char* file, int line, const char* function, const char* failed_expression) {
   async_safe_fatal("%s:%d: %s: assertion \"%s\" failed", file, line, function, failed_expression);
 }
-
-extern "C" __LIBC_HIDDEN__ void longjmperror() {
-  async_safe_fatal("longjmp botch");
-}
diff --git a/libc/bionic/fortify.cpp b/libc/bionic/fortify.cpp
index cbcc976..4b7b776 100644
--- a/libc/bionic/fortify.cpp
+++ b/libc/bionic/fortify.cpp
@@ -147,7 +147,7 @@
 
 void* __memrchr_chk(const void* s, int c, size_t n, size_t actual_size) {
   __check_buffer_access("memrchr", "read from", n, actual_size);
-  return memrchr(s, c, n);
+  return memrchr(const_cast<void *>(s), c, n);
 }
 
 // memset is performance-critical enough that we have assembler __memset_chk implementations.
diff --git a/libc/include/bits/fortify/string.h b/libc/include/bits/fortify/string.h
index 667e21d..f994e3e 100644
--- a/libc/include/bits/fortify/string.h
+++ b/libc/include/bits/fortify/string.h
@@ -38,6 +38,8 @@
 size_t __strlcat_chk(char*, const char*, size_t, size_t) __INTRODUCED_IN(17);
 
 #if defined(__BIONIC_FORTIFY)
+extern void* __memrchr_real(const void*, int, size_t) __RENAME(memrchr);
+
 // These can share their implementation between gcc and clang with minimal
 // trickery...
 #if __ANDROID_API__ >= __ANDROID_API_J_MR1__
@@ -116,11 +118,11 @@
 }
 
 __BIONIC_FORTIFY_INLINE
-void* memrchr(const void* const s __pass_object_size, int c, size_t n) __overloadable {
+void* __memrchr_fortify(const void* const __pass_object_size s, int c, size_t n) __overloadable {
     size_t bos = __bos(s);
 
     if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
-        return __call_bypassing_fortify(memrchr)(s, c, n);
+        return __memrchr_real(s, c, n);
     }
 
     return __memrchr_chk(s, c, n, bos);
@@ -231,7 +233,6 @@
 
 #else // defined(__clang__)
 extern char* __strncpy_real(char*, const char*, size_t) __RENAME(strncpy);
-extern void* __memrchr_real(const void*, int, size_t) __RENAME(memrchr);
 extern size_t __strlcpy_real(char*, const char*, size_t)
     __RENAME(strlcpy);
 extern size_t __strlcat_real(char*, const char*, size_t)
@@ -261,7 +262,7 @@
 }
 
 __BIONIC_FORTIFY_INLINE
-void* memrchr(const void* s, int c, size_t n) {
+void* __memrchr_fortify(const void* s, int c, size_t n) {
     size_t bos = __bos(s);
 
     if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
@@ -415,4 +416,26 @@
 }
 #endif /* __ANDROID_API__ >= __ANDROID_API_J_MR2__ */
 #endif /* defined(__clang__) */
+
+#if __ANDROID_API__ >= __ANDROID_API_M__
+#if defined(__cplusplus)
+extern "C++" {
+__BIONIC_FORTIFY_INLINE
+void* memrchr(void* const __pass_object_size s, int c, size_t n) {
+    return __memrchr_fortify(s, c, n);
+}
+
+__BIONIC_FORTIFY_INLINE
+const void* memrchr(const void* const __pass_object_size s, int c, size_t n) {
+    return __memrchr_fortify(s, c, n);
+}
+}
+#else
+__BIONIC_FORTIFY_INLINE
+void* memrchr(const void* const __pass_object_size s, int c, size_t n) __overloadable {
+    return __memrchr_fortify(s, c, n);
+}
+#endif
+#endif /* __ANDROID_API__ >= __ANDROID_API_M__ */
+
 #endif /* defined(__BIONIC_FORTIFY) */
diff --git a/libc/include/string.h b/libc/include/string.h
index 33ef468..d409ba8 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -43,7 +43,12 @@
 
 void* memccpy(void* __dst, const void* __src, int __stop_char, size_t __n);
 void* memchr(const void* __s, int __ch, size_t __n) __attribute_pure__ __overloadable __RENAME_CLANG(memchr);
+#if defined(__cplusplus)
+extern "C++" void* memrchr(void* __s, int __ch, size_t __n) __RENAME(memrchr) __attribute_pure__;
+extern "C++" const void* memrchr(const void* __s, int __ch, size_t __n) __RENAME(memrchr) __attribute_pure__;
+#else
 void* memrchr(const void* __s, int __ch, size_t __n) __attribute_pure__ __overloadable __RENAME_CLANG(memrchr);
+#endif
 int memcmp(const void* __lhs, const void* __rhs, size_t __n) __attribute_pure__;
 void* memcpy(void*, const void*, size_t)
         __overloadable __RENAME_CLANG(memcpy);
@@ -81,7 +86,12 @@
 char* strdup(const char* __s);
 
 char* strstr(const char* __haystack, const char* __needle) __attribute_pure__;
+#if defined(__cplusplus)
+extern "C++" char* strcasestr(char*, const char*) __RENAME(strcasestr) __attribute_pure__;
+extern "C++" const char* strcasestr(const char*, const char*) __RENAME(strcasestr) __attribute_pure__;
+#else
 char* strcasestr(const char* __haystack, const char* __needle) __attribute_pure__;
+#endif
 char* strtok(char* __s, const char* __delimiter);
 char* strtok_r(char* __s, const char* __delimiter, char** __pos_ptr);
 
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 8aadd14..59e4bac 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -66,6 +66,7 @@
 #include "linker_reloc_iterators.h"
 #include "linker_utils.h"
 
+#include "android-base/macros.h"
 #include "android-base/strings.h"
 #include "android-base/stringprintf.h"
 #include "ziparchive/zip_archive.h"
@@ -83,6 +84,8 @@
 static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
 static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
 
+static const char* const kLdConfigArchFilePath = "/system/etc/ld.config." ABI_STRING ".txt";
+
 static const char* const kLdConfigFilePath = "/system/etc/ld.config.txt";
 
 #if defined(__LP64__)
@@ -3467,7 +3470,7 @@
 
   std::string error_msg;
 
-  const char* config_file = kLdConfigFilePath;
+  const char* config_file = file_exists(kLdConfigArchFilePath) ? kLdConfigArchFilePath : kLdConfigFilePath;
 #ifdef USE_LD_CONFIG_FILE
   // This is a debugging/testing only feature. Must not be available on
   // production builds.