Add reallocarray(3).

Originally a BSD extension, now in glibc too. We've used it internally
for a while.

(cherry-pick of e4b13f7e3ca68edfcc5faedc5e7d4e13c4e8edb9.)

Bug: http://b/112163459
Test: ran tests
Change-Id: I813c3a62b13ddb91ba41e32a5a853d09207ea6bc
Merged-In: I813c3a62b13ddb91ba41e32a5a853d09207ea6bc
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
+}