Put all allocation functions into dispatch table.

Implement these new functions for all of the debug malloc types.

Fix a number of bugs in the debug malloc functions related to overflow
conditions.
Fix a bug in dlpvalloc due to an overflow condition.

Fix various other bugs in the debug malloc functions.

Add new tests for malloc functions.

Bug: 11225066

Change-Id: Idf50f389603e2157645565bc15cd9365eec2e9dd
diff --git a/libc/bionic/malloc_debug_qemu.cpp b/libc/bionic/malloc_debug_qemu.cpp
index 2dda767..4272482 100644
--- a/libc/bionic/malloc_debug_qemu.cpp
+++ b/libc/bionic/malloc_debug_qemu.cpp
@@ -573,12 +573,16 @@
 // API routines
 // =============================================================================
 
-extern "C" void* qemu_instrumented_malloc(size_t bytes);
-extern "C" void  qemu_instrumented_free(void* mem);
-extern "C" void* qemu_instrumented_calloc(size_t n_elements, size_t elem_size);
-extern "C" void* qemu_instrumented_realloc(void* mem, size_t bytes);
-extern "C" void* qemu_instrumented_memalign(size_t alignment, size_t bytes);
-extern "C" size_t qemu_instrumented_malloc_usable_size(const void* mem);
+extern "C" void* qemu_instrumented_calloc(size_t, size_t);
+extern "C" void  qemu_instrumented_free(void*);
+extern "C" struct mallinfo qemu_instrumented_mallinfo();
+extern "C" void* qemu_instrumented_malloc(size_t);
+extern "C" size_t qemu_instrumented_malloc_usable_size(const void*);
+extern "C" void* qemu_instrumented_memalign(size_t, size_t);
+extern "C" int qemu_instrumented_posix_memalign(void**, size_t, size_t);
+extern "C" void* qemu_instrumented_pvalloc(size_t);
+extern "C" void* qemu_instrumented_realloc(void*, size_t);
+extern "C" void* qemu_instrumented_valloc(size_t);
 
 /* Initializes malloc debugging instrumentation for the emulator.
  * This routine is called from malloc_init_impl routine implemented in
@@ -680,10 +684,17 @@
     desc.prefix_size = DEFAULT_PREFIX_SIZE;
     desc.requested_bytes = bytes;
     desc.suffix_size = DEFAULT_SUFFIX_SIZE;
-    desc.ptr = Malloc(malloc)(mallocdesc_alloc_size(&desc));
+    size_t size = mallocdesc_alloc_size(&desc);
+    if (size < bytes) { // Overflow
+        qemu_error_log("<libc_pid=%03u, pid=%03u> malloc: malloc(%zu) overflow caused failure.",
+                       malloc_pid, getpid(), bytes);
+        errno = ENOMEM;
+        return NULL;
+    }
+    desc.ptr = Malloc(malloc)(size);
     if (desc.ptr == NULL) {
-        qemu_error_log("<libc_pid=%03u, pid=%03u> malloc(%zd): malloc(%u) failed.",
-                  malloc_pid, getpid(), bytes, mallocdesc_alloc_size(&desc));
+        qemu_error_log("<libc_pid=%03u, pid=%03u> malloc(%zu): malloc(%u) failed.",
+                       malloc_pid, getpid(), bytes, size);
         return NULL;
     }
 
@@ -692,12 +703,13 @@
         log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: malloc: notify_malloc failed for ",
                   malloc_pid, getpid());
         Malloc(free)(desc.ptr);
+        errno = ENOMEM;
         return NULL;
     } else {
 #if TEST_ACCESS_VIOLATIONS
         test_access_violation(&desc);
 #endif  // TEST_ACCESS_VIOLATIONS
-        log_mdesc(info, &desc, "+++ <libc_pid=%03u, pid=%03u> malloc(%zd) -> ",
+        log_mdesc(info, &desc, "+++ <libc_pid=%03u, pid=%03u> malloc(%zu) -> ",
                   malloc_pid, getpid(), bytes);
         return mallocdesc_user_ptr(&desc);
     }
@@ -754,13 +766,16 @@
     if (n_elements == 0 || elem_size == 0) {
         // Just let go zero bytes allocation.
         qemu_info_log("::: <libc_pid=%03u, pid=%03u>: Zero calloc redir to malloc",
-                 malloc_pid, getpid());
+                      malloc_pid, getpid());
         return qemu_instrumented_malloc(0);
     }
 
     // Fail on overflow - just to be safe even though this code runs only
     // within the debugging C library, not the production one.
     if (n_elements && SIZE_MAX / n_elements < elem_size) {
+        qemu_error_log("<libc_pid=%03u, pid=%03u> calloc: calloc(%zu, %zu) overflow caused failure.",
+                       malloc_pid, getpid(), n_elements, elem_size);
+        errno = ENOMEM;
         return NULL;
     }
 
@@ -786,6 +801,12 @@
     }
     desc.requested_bytes = n_elements * elem_size;
     size_t total_size = desc.requested_bytes + desc.prefix_size + desc.suffix_size;
+    if (total_size < desc.requested_bytes) { // Overflow
+        qemu_error_log("<libc_pid=%03u, pid=%03u> calloc: calloc(%zu, %zu) overflow caused failure.",
+                       malloc_pid, getpid(), n_elements, elem_size);
+        errno = ENOMEM;
+        return NULL;
+    }
     size_t total_elements = total_size / elem_size;
     total_size %= elem_size;
     if (total_size != 0) {
@@ -795,22 +816,23 @@
     }
     desc.ptr = Malloc(calloc)(total_elements, elem_size);
     if (desc.ptr == NULL) {
-        error_log("<libc_pid=%03u, pid=%03u> calloc: calloc(%zd(%zd), %zd) (prx=%u, sfx=%u) failed.",
+        error_log("<libc_pid=%03u, pid=%03u> calloc: calloc(%zu(%zu), %zu) (prx=%u, sfx=%u) failed.",
                    malloc_pid, getpid(), n_elements, total_elements, elem_size,
                    desc.prefix_size, desc.suffix_size);
         return NULL;
     }
 
     if (notify_qemu_malloc(&desc)) {
-        log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: calloc(%zd(%zd), %zd): notify_malloc failed for ",
+        log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: calloc(%zu(%zu), %zu): notify_malloc failed for ",
                   malloc_pid, getpid(), n_elements, total_elements, elem_size);
         Malloc(free)(desc.ptr);
+        errno = ENOMEM;
         return NULL;
     } else {
 #if TEST_ACCESS_VIOLATIONS
         test_access_violation(&desc);
 #endif  // TEST_ACCESS_VIOLATIONS
-        log_mdesc(info, &desc, "### <libc_pid=%03u, pid=%03u> calloc(%zd(%zd), %zd) -> ",
+        log_mdesc(info, &desc, "### <libc_pid=%03u, pid=%03u> calloc(%zu(%zu), %zu) -> ",
                   malloc_pid, getpid(), n_elements, total_elements, elem_size);
         return mallocdesc_user_ptr(&desc);
     }
@@ -823,22 +845,17 @@
  * should not expect that pointer returned after shrinking will remain the same.
  */
 extern "C" void* qemu_instrumented_realloc(void* mem, size_t bytes) {
-    MallocDesc new_desc;
-    MallocDesc cur_desc;
-    size_t to_copy;
-    void* ret;
-
     if (mem == NULL) {
         // Nothing to realloc. just do regular malloc.
-        qemu_info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %zd) redir to malloc",
-                 malloc_pid, getpid(), mem, bytes);
+        qemu_info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %zu) redir to malloc",
+                      malloc_pid, getpid(), mem, bytes);
         return qemu_instrumented_malloc(bytes);
     }
 
     if (bytes == 0) {
         // This is a "free" condition.
-        qemu_info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %zd) redir to free and malloc",
-                 malloc_pid, getpid(), mem, bytes);
+        qemu_info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %zu) redir to free and malloc",
+                      malloc_pid, getpid(), mem, bytes);
         qemu_instrumented_free(mem);
 
         // This is what realloc does for a "free" realloc.
@@ -846,10 +863,12 @@
     }
 
     // Query emulator for the reallocating block information.
+    MallocDesc cur_desc;
     if (query_qemu_malloc_info(mem, &cur_desc, 2)) {
         // Note that this violation should be already caught in the emulator.
-        error_log("<libc_pid=%03u, pid=%03u>: realloc(%p, %zd) query_info failed.",
+        error_log("<libc_pid=%03u, pid=%03u>: realloc(%p, %zu) query_info failed.",
                   malloc_pid, getpid(), mem, bytes);
+        errno = ENOMEM;
         return NULL;
     }
 
@@ -861,8 +880,9 @@
      * for this memory block. Note that this violation should be already caught
      * in the emulator.*/
     if (mem != mallocdesc_user_ptr(&cur_desc)) {
-        log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zd) is invalid for ",
+        log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zu) is invalid for ",
                   malloc_pid, getpid(), mem, bytes);
+        errno = ENOMEM;
         return NULL;
     }
 
@@ -872,31 +892,38 @@
      * for this block that is stored in the emulator. */
 
     // Initialize descriptor for the new block.
+    MallocDesc new_desc;
     new_desc.prefix_size = DEFAULT_PREFIX_SIZE;
     new_desc.requested_bytes = bytes;
     new_desc.suffix_size = DEFAULT_SUFFIX_SIZE;
-    new_desc.ptr = Malloc(malloc)(mallocdesc_alloc_size(&new_desc));
-    if (new_desc.ptr == NULL) {
-        log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zd): malloc(%u) failed on ",
-                  malloc_pid, getpid(), mem, bytes,
-                  mallocdesc_alloc_size(&new_desc));
+    size_t new_size = mallocdesc_alloc_size(&new_desc);
+    if (new_size < bytes) { // Overflow
+        qemu_error_log("<libc_pid=%03u, pid=%03u>: realloc(%p, %zu): malloc(%u) failed due to overflow",
+                       malloc_pid, getpid(), mem, bytes, new_size);
+        errno = ENOMEM;
         return NULL;
     }
-    ret = mallocdesc_user_ptr(&new_desc);
+    new_desc.ptr = Malloc(malloc)(new_size);
+    if (new_desc.ptr == NULL) {
+        log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zu): malloc(%u) failed on ",
+                  malloc_pid, getpid(), mem, bytes, new_size);
+        return NULL;
+    }
+    void* new_mem = mallocdesc_user_ptr(&new_desc);
 
     // Copy user data from old block to the new one.
-    to_copy = bytes < cur_desc.requested_bytes ? bytes :
-                                                 cur_desc.requested_bytes;
+    size_t to_copy = bytes < cur_desc.requested_bytes ? bytes : cur_desc.requested_bytes;
     if (to_copy != 0) {
-        memcpy(ret, mallocdesc_user_ptr(&cur_desc), to_copy);
+        memcpy(new_mem, mallocdesc_user_ptr(&cur_desc), to_copy);
     }
 
     // Register new block with emulator.
     if (notify_qemu_malloc(&new_desc)) {
-        log_mdesc(error, &new_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zd) notify_malloc failed -> ",
+        log_mdesc(error, &new_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zu) notify_malloc failed -> ",
                   malloc_pid, getpid(), mem, bytes);
         log_mdesc(error, &cur_desc, "                                                                <- ");
         Malloc(free)(new_desc.ptr);
+        errno = ENOMEM;
         return NULL;
     }
 
@@ -906,21 +933,22 @@
 
     // Free old block.
     if (notify_qemu_free(mem)) {
-        log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zd): notify_free failed for ",
+        log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zu): notify_free failed for ",
                   malloc_pid, getpid(), mem, bytes);
         /* Since we registered new decriptor with the emulator, we need
          * to unregister it before freeing newly allocated block. */
         notify_qemu_free(mallocdesc_user_ptr(&new_desc));
         Malloc(free)(new_desc.ptr);
+        errno = ENOMEM;
         return NULL;
     }
     Malloc(free)(cur_desc.ptr);
 
-    log_mdesc(info, &new_desc, "=== <libc_pid=%03u, pid=%03u>: realloc(%p, %zd) -> ",
+    log_mdesc(info, &new_desc, "=== <libc_pid=%03u, pid=%03u>: realloc(%p, %zu) -> ",
               malloc_pid, getpid(), mem, bytes);
     log_mdesc(info, &cur_desc, "                                               <- ");
 
-    return ret;
+    return new_mem;
 }
 
 /* This routine serves as entry point for 'memalign'.
@@ -931,28 +959,38 @@
 
     if (bytes == 0) {
         // Just let go zero bytes allocation.
-        qemu_info_log("::: <libc_pid=%03u, pid=%03u>: memalign(%zx, %zd) redir to malloc",
+        qemu_info_log("::: <libc_pid=%03u, pid=%03u>: memalign(%zx, %zu) redir to malloc",
                  malloc_pid, getpid(), alignment, bytes);
         return qemu_instrumented_malloc(0);
     }
 
-    /* Prefix size for aligned allocation must be equal to the alignment used
-     * for allocation in order to ensure proper alignment of the returned
-     * pointer, in case that alignment requirement is greater than prefix
-     * size. */
-    desc.prefix_size = alignment > DEFAULT_PREFIX_SIZE ? alignment :
-                                                         DEFAULT_PREFIX_SIZE;
+    // Prefix size for aligned allocation must be equal to the alignment used
+    // for allocation in order to ensure proper alignment of the returned
+    // pointer. in case that alignment requirement is greater than prefix
+    // size.
+    if (alignment < DEFAULT_PREFIX_SIZE) {
+        alignment = DEFAULT_PREFIX_SIZE;
+    } else if (alignment & (alignment - 1)) {
+        alignment = 1L << (31 - __builtin_clz(alignment));
+    }
+    desc.prefix_size = alignment;
     desc.requested_bytes = bytes;
     desc.suffix_size = DEFAULT_SUFFIX_SIZE;
-    desc.ptr = Malloc(memalign)(desc.prefix_size, mallocdesc_alloc_size(&desc));
+    size_t size = mallocdesc_alloc_size(&desc);
+    if (size < bytes) { // Overflow
+        qemu_error_log("<libc_pid=%03u, pid=%03u> memalign(%zx, %zu): malloc(%u) failed due to overflow.",
+                       malloc_pid, getpid(), alignment, bytes, size);
+
+        return NULL;
+    }
+    desc.ptr = Malloc(memalign)(desc.prefix_size, size);
     if (desc.ptr == NULL) {
-        error_log("<libc_pid=%03u, pid=%03u> memalign(%zx, %zd): malloc(%u) failed.",
-                  malloc_pid, getpid(), alignment, bytes,
-                  mallocdesc_alloc_size(&desc));
+        error_log("<libc_pid=%03u, pid=%03u> memalign(%zx, %zu): malloc(%u) failed.",
+                  malloc_pid, getpid(), alignment, bytes, size);
         return NULL;
     }
     if (notify_qemu_malloc(&desc)) {
-        log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: memalign(%zx, %zd): notify_malloc failed for ",
+        log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: memalign(%zx, %zu): notify_malloc failed for ",
                   malloc_pid, getpid(), alignment, bytes);
         Malloc(free)(desc.ptr);
         return NULL;
@@ -962,7 +1000,7 @@
     test_access_violation(&desc);
 #endif  // TEST_ACCESS_VIOLATIONS
 
-    log_mdesc(info, &desc, "@@@ <libc_pid=%03u, pid=%03u> memalign(%zx, %zd) -> ",
+    log_mdesc(info, &desc, "@@@ <libc_pid=%03u, pid=%03u> memalign(%zx, %zu) -> ",
               malloc_pid, getpid(), alignment, bytes);
     return mallocdesc_user_ptr(&desc);
 }
@@ -990,3 +1028,34 @@
     /* during instrumentation, we can't really report anything more than requested_bytes */
     return cur_desc.requested_bytes;
 }
+
+extern "C" struct mallinfo qemu_instrumented_mallinfo() {
+  return Malloc(mallinfo)();
+}
+
+extern "C" int qemu_instrumented_posix_memalign(void** memptr, size_t alignment, size_t size) {
+  if ((alignment & (alignment - 1)) != 0) {
+    qemu_error_log("<libc_pid=%03u, pid=%03u> posix_memalign(%p, %zu, %zu): invalid alignment.",
+                   malloc_pid, getpid(), memptr, alignment, size);
+    return EINVAL;
+  }
+  int saved_errno = errno;
+  *memptr = qemu_instrumented_memalign(alignment, size);
+  errno = saved_errno;
+  return (*memptr != NULL) ? 0 : ENOMEM;
+}
+
+extern "C" void* qemu_instrumented_pvalloc(size_t bytes) {
+  size_t pagesize = sysconf(_SC_PAGESIZE);
+  size_t size = (bytes + pagesize - 1) & ~(pagesize - 1);
+  if (size < bytes) { // Overflow
+    qemu_error_log("<libc_pid=%03u, pid=%03u> pvalloc(%zu): overflow (%zu).",
+                   malloc_pid, getpid(), bytes, size);
+    return NULL;
+  }
+  return qemu_instrumented_memalign(pagesize, size);
+}
+
+extern "C" void* qemu_instrumented_valloc(size_t size) {
+  return qemu_instrumented_memalign(sysconf(_SC_PAGESIZE), size);
+}