Merge "bionic-unit-tests should depend on libandroidicu instead"
diff --git a/docs/status.md b/docs/status.md
index 54385a4..85f9b60 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -48,8 +48,10 @@
   * Whole printf family now supports the GNU `%m` extension, rather than a special-case hack in `syslog`
   * `popen` now always uses `O_CLOEXEC`, not just with the `e` extension
   * Bug fixes to handling of UTF-8 U+fffe/U+ffff and code points above U+10ffff
+  * `aligned_alloc` correctly verifies that `size` is a multiple of `alignment`
 
 New libc functions in P (API level 28):
+  * `aligned_alloc`
   * `__freading`/`__fwriting` (completing <stdio_ext.h>)
   * `endhostent`/`endnetent`/`endprotoent`/`getnetent`/`getprotoent`/`sethostent`/`setnetent`/`setprotoent` (completing <netdb.h>)
   * `fexecve`
diff --git a/libc/bionic/jemalloc.h b/libc/bionic/jemalloc.h
index 79a4f72..3fd36e4 100644
--- a/libc/bionic/jemalloc.h
+++ b/libc/bionic/jemalloc.h
@@ -22,14 +22,19 @@
 // Need to wrap memalign since je_memalign fails on non-power of 2 alignments.
 #define je_memalign je_memalign_round_up_boundary
 
+// Need to wrap aligned_alloc since je_aligned_alloc does not enforce
+// that size is a multiple of alignment.
+#define je_aligned_alloc je_aligned_alloc_wrapper
+
 __BEGIN_DECLS
 
-struct mallinfo je_mallinfo();
-int je_mallopt(int, int);
+void* je_aligned_alloc_wrapper(size_t, size_t);
 int je_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*);
+int je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
+struct mallinfo je_mallinfo();
 void je_malloc_disable();
 void je_malloc_enable();
-int je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
+int je_mallopt(int, int);
 void* je_memalign_round_up_boundary(size_t, size_t);
 void* je_pvalloc(size_t);
 
diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp
index ef0d384..c513246 100644
--- a/libc/bionic/jemalloc_wrapper.cpp
+++ b/libc/bionic/jemalloc_wrapper.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <errno.h>
 #include <malloc.h>
 #include <sys/param.h>
 #include <unistd.h>
@@ -48,6 +49,20 @@
   return je_memalign(boundary, size);
 }
 
+#ifdef je_aligned_alloc
+#undef je_aligned_alloc
+#endif
+
+// The aligned_alloc function requires that size is a multiple of alignment.
+// jemalloc doesn't enforce this, so add enforcement here.
+void* je_aligned_alloc_wrapper(size_t alignment, size_t size) {
+  if ((size % alignment) != 0) {
+    errno = EINVAL;
+    return nullptr;
+  }
+  return je_aligned_alloc(alignment, size);
+}
+
 int je_mallopt(int param, int value) {
   // The only parameter we currently understand is M_DECAY_TIME.
   if (param == M_DECAY_TIME) {
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index f1fbfa9..b229cda 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -298,11 +298,26 @@
   unsigned long is_AT_SECURE = getauxval(AT_SECURE);
   if (errno != 0) __early_abort(__LINE__);
 
-  if (is_AT_SECURE) {
-    // If this is a setuid/setgid program, close the security hole described in
-    // https://www.freebsd.org/security/advisories/FreeBSD-SA-02:23.stdio.asc
+  // Always ensure that STDIN/STDOUT/STDERR exist. This prevents file
+  // descriptor confusion bugs where a parent process closes
+  // STD*, the exec()d process calls open() for an unrelated reason,
+  // the newly created file descriptor is assigned
+  // 0<=FD<=2, and unrelated code attempts to read / write to the STD*
+  // FDs.
+  // In particular, this can be a security bug for setuid/setgid programs.
+  // For example:
+  // https://www.freebsd.org/security/advisories/FreeBSD-SA-02:23.stdio.asc
+  // However, for robustness reasons, we don't limit these protections to
+  // just security critical executables.
+  //
+  // Init is excluded from these protections unless AT_SECURE is set, as
+  // /dev/null and/or /sys/fs/selinux/null will not be available at
+  // early boot.
+  if ((getpid() != 1) || is_AT_SECURE) {
     __nullify_closed_stdio();
+  }
 
+  if (is_AT_SECURE) {
     __sanitize_environment_variables(env);
   }
 
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 80e82f7..bb8ec59 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -69,7 +69,11 @@
   if (__predict_false(dispatch_table != nullptr)) {
     return dispatch_table->calloc(n_elements, elem_size);
   }
-  return Malloc(calloc)(n_elements, elem_size);
+  void* result = Malloc(calloc)(n_elements, elem_size);
+  if (__predict_false(result == nullptr)) {
+    warning_log("calloc(%zu, %zu) failed: returning null pointer", n_elements, elem_size);
+  }
+  return result;
 }
 
 extern "C" void free(void* mem) {
@@ -102,7 +106,11 @@
   if (__predict_false(dispatch_table != nullptr)) {
     return dispatch_table->malloc(bytes);
   }
-  return Malloc(malloc)(bytes);
+  void* result = Malloc(malloc)(bytes);
+  if (__predict_false(result == nullptr)) {
+    warning_log("malloc(%zu) failed: returning null pointer", bytes);
+  }
+  return result;
 }
 
 extern "C" size_t malloc_usable_size(const void* mem) {
@@ -118,7 +126,11 @@
   if (__predict_false(dispatch_table != nullptr)) {
     return dispatch_table->memalign(alignment, bytes);
   }
-  return Malloc(memalign)(alignment, bytes);
+  void* result = Malloc(memalign)(alignment, bytes);
+  if (__predict_false(result == nullptr)) {
+    warning_log("memalign(%zu, %zu) failed: returning null pointer", alignment, bytes);
+  }
+  return result;
 }
 
 extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size) {
@@ -134,7 +146,11 @@
   if (__predict_false(dispatch_table != nullptr)) {
     return dispatch_table->aligned_alloc(alignment, size);
   }
-  return Malloc(aligned_alloc)(alignment, size);
+  void* result = Malloc(aligned_alloc)(alignment, size);
+  if (__predict_false(result == nullptr)) {
+    warning_log("aligned_alloc(%zu, %zu) failed: returning null pointer", alignment, size);
+  }
+  return result;
 }
 
 extern "C" void* realloc(void* old_mem, size_t bytes) {
@@ -142,12 +158,18 @@
   if (__predict_false(dispatch_table != nullptr)) {
     return dispatch_table->realloc(old_mem, bytes);
   }
-  return Malloc(realloc)(old_mem, bytes);
+  void* result = Malloc(realloc)(old_mem, bytes);
+  if (__predict_false(result == nullptr && bytes != 0)) {
+    warning_log("realloc(%p, %zu) failed: returning null pointer", old_mem, bytes);
+  }
+  return result;
 }
 
 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)) {
+    warning_log("reallocaray(%p, %zu, %zu) failed: returning null pointer",
+                old_mem, item_count, item_size);
     errno = ENOMEM;
     return nullptr;
   }
@@ -160,7 +182,11 @@
   if (__predict_false(dispatch_table != nullptr)) {
     return dispatch_table->pvalloc(bytes);
   }
-  return Malloc(pvalloc)(bytes);
+  void* result = Malloc(pvalloc)(bytes);
+  if (__predict_false(result == nullptr)) {
+    warning_log("pvalloc(%zu) failed: returning null pointer", bytes);
+  }
+  return result;
 }
 
 extern "C" void* valloc(size_t bytes) {
@@ -168,7 +194,11 @@
   if (__predict_false(dispatch_table != nullptr)) {
     return dispatch_table->valloc(bytes);
   }
-  return Malloc(valloc)(bytes);
+  void* result = Malloc(valloc)(bytes);
+  if (__predict_false(result == nullptr)) {
+    warning_log("valloc(%zu) failed: returning null pointer", bytes);
+  }
+  return result;
 }
 #endif
 // =============================================================================
diff --git a/libc/bionic/malloc_common.h b/libc/bionic/malloc_common.h
index a2f338a..e3326cf 100644
--- a/libc/bionic/malloc_common.h
+++ b/libc/bionic/malloc_common.h
@@ -71,4 +71,6 @@
     async_safe_format_log(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ )
 #define info_log(format, ...)  \
     async_safe_format_log(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ )
+#define warning_log(format, ...)  \
+    async_safe_format_log(ANDROID_LOG_WARN, "libc", (format), ##__VA_ARGS__ )
 // =============================================================================
diff --git a/libc/bionic/strsignal.cpp b/libc/bionic/strsignal.cpp
index 5637431..05d3498 100644
--- a/libc/bionic/strsignal.cpp
+++ b/libc/bionic/strsignal.cpp
@@ -37,7 +37,7 @@
 };
 
 const char* const sys_signame[NSIG] = {
-#define __BIONIC_SIGDEF(signal_number, unused) [ signal_number ] = #signal_number + 3,
+#define __BIONIC_SIGDEF(signal_number, unused) [ signal_number ] = &(#signal_number)[3],
 #include "private/bionic_sigdefs.h"
 };
 
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 2e6afff..f662957 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -729,7 +729,7 @@
   if (DebugCallsDisabled()) {
     return g_dispatch->aligned_alloc(alignment, size);
   }
-  if (!powerof2(alignment)) {
+  if (!powerof2(alignment) || (size % alignment) != 0) {
     errno = EINVAL;
     return nullptr;
   }
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 6da95ca..a72db3b 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -318,7 +318,7 @@
   ASSERT_LE(1039U, debug_malloc_usable_size(pointer));
   debug_free(pointer);
 
-  pointer = debug_aligned_alloc(128, 15);
+  pointer = debug_aligned_alloc(16, 16);
   ASSERT_TRUE(pointer != nullptr);
   ASSERT_LE(1039U, debug_malloc_usable_size(pointer));
   debug_free(pointer);
@@ -2144,9 +2144,9 @@
   debug_free(pointer);
   expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
 
-  pointer = debug_aligned_alloc(32, 50);
+  pointer = debug_aligned_alloc(32, 64);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: memalign %p 32 50\n", getpid(), pointer);
+  expected += android::base::StringPrintf("%d: memalign %p 32 64\n", getpid(), pointer);
   debug_free(pointer);
   expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
 
diff --git a/libc/malloc_hooks/malloc_hooks.cpp b/libc/malloc_hooks/malloc_hooks.cpp
index f7bdd56..715a629 100644
--- a/libc/malloc_hooks/malloc_hooks.cpp
+++ b/libc/malloc_hooks/malloc_hooks.cpp
@@ -176,7 +176,7 @@
 
 void* hooks_aligned_alloc(size_t alignment, size_t size) {
   if (__memalign_hook != nullptr && __memalign_hook != default_memalign_hook) {
-    if (!powerof2(alignment)) {
+    if (!powerof2(alignment) || (size % alignment) != 0) {
       errno = EINVAL;
       return nullptr;
     }
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index 408a9c7..ff4cb71 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -272,11 +272,11 @@
   for (size_t align = 1; align <= 2048; align <<= 1) {
     // Try all of the non power of 2 values from the last until this value.
     for (size_t fail_align = last_align + 1; fail_align < align; fail_align++) {
-      ASSERT_TRUE(aligned_alloc(fail_align, 256) == nullptr)
+      ASSERT_TRUE(aligned_alloc(fail_align, fail_align) == nullptr)
           << "Unexpected success at align " << fail_align;
       ASSERT_EQ(EINVAL, errno) << "Unexpected errno at align " << fail_align;
     }
-    void* ptr = aligned_alloc(align, 256);
+    void* ptr = aligned_alloc(align, 2 * align);
     ASSERT_TRUE(ptr != nullptr) << "Unexpected failure at align " << align;
     ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
         << "Did not return a valid aligned ptr " << ptr << " expected alignment " << align;
@@ -292,11 +292,11 @@
 
 TEST(stdlib, aligned_alloc_size_not_multiple_of_alignment) {
   SKIP_WITH_HWASAN;
-  for (size_t size = 1; size <= 2048; size++) {
-    void* ptr = aligned_alloc(2048, size);
-    ASSERT_TRUE(ptr != nullptr) << "Failed at size " << std::to_string(size);
-    free(ptr);
-  }
+
+  ASSERT_TRUE(aligned_alloc(2048, 1) == nullptr);
+  ASSERT_TRUE(aligned_alloc(4, 3) == nullptr);
+  ASSERT_TRUE(aligned_alloc(4, 7) == nullptr);
+  ASSERT_TRUE(aligned_alloc(16, 8) == nullptr);
 }
 
 TEST(stdlib, realpath__NULL_filename) {