Merge "Add support of architecture specific ld.configs"
diff --git a/benchmarks/stdio_benchmark.cpp b/benchmarks/stdio_benchmark.cpp
index 2ab7264..0e7f668 100644
--- a/benchmarks/stdio_benchmark.cpp
+++ b/benchmarks/stdio_benchmark.cpp
@@ -19,14 +19,25 @@
 #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);
 
-  FILE* fp = fopen("/dev/zero", "rw");
+  FILE* fp = fopen("/dev/zero", "r+e");
   __fsetlocking(fp, FSETLOCKING_BYCALLER);
   char* buf = new char[chunk_size];
 
@@ -35,7 +46,9 @@
   }
 
   while (state.KeepRunning()) {
-    f(buf, chunk_size, 1, fp);
+    if (f(buf, chunk_size, 1, fp) != 1) {
+      errx(1, "ERROR: op of %zu bytes failed.", chunk_size);
+    }
   }
 
   state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(chunk_size));
@@ -63,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);
   }
@@ -86,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()) {
@@ -108,4 +171,3 @@
   FopenFgetcFclose(state, true);
 }
 BIONIC_BENCHMARK(BM_stdio_fopen_fgetc_fclose_no_locking);
-
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/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);