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_check.cpp b/libc/bionic/malloc_debug_check.cpp
index 0575595..faf61bf 100644
--- a/libc/bionic/malloc_debug_check.cpp
+++ b/libc/bionic/malloc_debug_check.cpp
@@ -326,14 +326,19 @@
     }
 }
 
-extern "C" void* chk_malloc(size_t size) {
+extern "C" void* chk_malloc(size_t bytes) {
 //  log_message("%s: %s\n", __FILE__, __FUNCTION__);
 
-    hdr_t* hdr = static_cast<hdr_t*>(Malloc(malloc)(sizeof(hdr_t) + size + sizeof(ftr_t)));
+    size_t size = sizeof(hdr_t) + bytes + sizeof(ftr_t);
+    if (size < bytes) { // Overflow
+        errno = ENOMEM;
+        return NULL;
+    }
+    hdr_t* hdr = static_cast<hdr_t*>(Malloc(malloc)(size));
     if (hdr) {
         hdr->base = hdr;
         hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
-        add(hdr, size);
+        add(hdr, bytes);
         return user(hdr);
     }
     return NULL;
@@ -411,15 +416,15 @@
     }
 }
 
-extern "C" void* chk_realloc(void* ptr, size_t size) {
+extern "C" void* chk_realloc(void* ptr, size_t bytes) {
 //  log_message("%s: %s\n", __FILE__, __FUNCTION__);
 
     if (!ptr) {
-        return chk_malloc(size);
+        return chk_malloc(bytes);
     }
 
 #ifdef REALLOC_ZERO_BYTES_FREE
-    if (!size) {
+    if (!bytes) {
         chk_free(ptr);
         return NULL;
     }
@@ -432,7 +437,7 @@
         int depth = get_backtrace(bt, MAX_BACKTRACE_DEPTH);
         if (hdr->tag == BACKLOG_TAG) {
             log_message("+++ REALLOCATION %p SIZE %d OF FREED MEMORY!\n",
-                       user(hdr), size, hdr->size);
+                       user(hdr), bytes, hdr->size);
             log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
                        user(hdr), hdr->size);
             log_backtrace(hdr->bt, hdr->bt_depth);
@@ -451,47 +456,54 @@
             del_from_backlog(hdr);
         } else {
             log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
-                       user(hdr), size);
+                       user(hdr), bytes);
             log_backtrace(bt, depth);
             // just get a whole new allocation and leak the old one
-            return Malloc(realloc)(0, size);
-            // return realloc(user(hdr), size); // assuming it was allocated externally
+            return Malloc(realloc)(0, bytes);
+            // return realloc(user(hdr), bytes); // assuming it was allocated externally
         }
     }
 
+    size_t size = sizeof(hdr_t) + bytes + sizeof(ftr_t);
+    if (size < bytes) { // Overflow
+        errno = ENOMEM;
+        return NULL;
+    }
     if (hdr->base != hdr) {
         // An allocation from memalign, so create another allocation and
         // copy the data out.
-        void* newMem = Malloc(malloc)(sizeof(hdr_t) + size + sizeof(ftr_t));
-        if (newMem) {
-            memcpy(newMem, hdr, sizeof(hdr_t) + hdr->size);
-            Malloc(free)(hdr->base);
-            hdr = static_cast<hdr_t*>(newMem);
-        } else {
-            Malloc(free)(hdr->base);
-            hdr = NULL;
+        void* newMem = Malloc(malloc)(size);
+        if (newMem == NULL) {
+            return NULL;
         }
+        memcpy(newMem, hdr, sizeof(hdr_t) + hdr->size);
+        Malloc(free)(hdr->base);
+        hdr = static_cast<hdr_t*>(newMem);
     } else {
-        hdr = static_cast<hdr_t*>(Malloc(realloc)(hdr, sizeof(hdr_t) + size + sizeof(ftr_t)));
+        hdr = static_cast<hdr_t*>(Malloc(realloc)(hdr, size));
     }
     if (hdr) {
         hdr->base = hdr;
         hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
-        add(hdr, size);
+        add(hdr, bytes);
         return user(hdr);
     }
-
     return NULL;
 }
 
-extern "C" void* chk_calloc(int nmemb, size_t size) {
+extern "C" void* chk_calloc(size_t nmemb, size_t bytes) {
 //  log_message("%s: %s\n", __FILE__, __FUNCTION__);
-    size_t total_size = nmemb * size;
-    hdr_t* hdr = static_cast<hdr_t*>(Malloc(calloc)(1, sizeof(hdr_t) + total_size + sizeof(ftr_t)));
+    size_t total_bytes = nmemb * bytes;
+    size_t size = sizeof(hdr_t) + total_bytes + sizeof(ftr_t);
+    if (size < total_bytes || (nmemb && SIZE_MAX / nmemb < bytes)) { // Overflow
+        errno = ENOMEM;
+        return NULL;
+    }
+    hdr_t* hdr = static_cast<hdr_t*>(Malloc(calloc)(1, size));
     if (hdr) {
         hdr->base = hdr;
         hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
-        add(hdr, total_size);
+        add(hdr, total_bytes);
         return user(hdr);
     }
     return NULL;
@@ -509,6 +521,33 @@
     return hdr->size;
 }
 
+extern "C" struct mallinfo chk_mallinfo() {
+  return Malloc(mallinfo)();
+}
+
+extern "C" int chk_posix_memalign(void** memptr, size_t alignment, size_t size) {
+  if ((alignment & (alignment - 1)) != 0) {
+    return EINVAL;
+  }
+  int saved_errno = errno;
+  *memptr = chk_memalign(alignment, size);
+  errno = saved_errno;
+  return (*memptr != NULL) ? 0 : ENOMEM;
+}
+
+extern "C" void* chk_pvalloc(size_t bytes) {
+  size_t pagesize = sysconf(_SC_PAGESIZE);
+  size_t size = (bytes + pagesize - 1) & ~(pagesize - 1);
+  if (size < bytes) { // Overflow
+    return NULL;
+  }
+  return chk_memalign(pagesize, size);
+}
+
+extern "C" void* chk_valloc(size_t size) {
+  return chk_memalign(sysconf(_SC_PAGESIZE), size);
+}
+
 static void ReportMemoryLeaks() {
   // Use /proc/self/exe link to obtain the program name for logging
   // purposes. If it's not available, we set it to "<unknown>".