Merge "Ignore output to stderr while enumerating tests"
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/docs/status.md b/docs/status.md
index b6439a0..0106ccd 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -39,6 +39,7 @@
 
 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)
 
diff --git a/libc/Android.bp b/libc/Android.bp
index 57173d1..cc0a2bb 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -479,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",
@@ -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/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/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/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 2891925..a22a8df 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1433,6 +1433,7 @@
     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 3e8cea2..55fd587 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1354,6 +1354,7 @@
     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 2770f21..304dbb7 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1458,6 +1458,7 @@
     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 456e35c..397ff72 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1417,6 +1417,7 @@
     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 3e8cea2..55fd587 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1354,6 +1354,7 @@
     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 4cbef13..a18657c 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1415,6 +1415,7 @@
     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 3e8cea2..55fd587 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1354,6 +1354,7 @@
     android_fdsan_set_error_level;
     android_get_device_api_level;
     pthread_sigqueue;
+    reallocarray;
     timespec_get;
 } LIBC_P;
 
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-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/ceil.S b/libm/arm64/ceil.S
deleted file mode 100644
index 7217d57..0000000
--- a/libm/arm64/ceil.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(ceil)
-  frintP d0, d0
-  ret
-END(ceil)
-
-ENTRY(ceilf)
-  frintP s0, s0
-  ret
-END(ceilf)
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 b809f76..1e14ee3 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/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/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
+}