[GWP-ASan] Fix bugs in realloc().

Two edge cases were found in aosp/2038947:
 1. realloc(p, 0) == free() and returns nullptr. Previously, we just
    returned a new pointer.
 2. If the malloc() part of realloc() fails (e.g. when the size of the
    allocation is 1 << 56), then the old memory shouldn't be destroyed.

Bug: N/A
Test: Covered using atest bionic-unit-tests using aosp/2038947.
Change-Id: Ibafc752787129922a1e0323ffa14221d6a14f108
diff --git a/libc/bionic/gwp_asan_wrappers.cpp b/libc/bionic/gwp_asan_wrappers.cpp
index 8c51347..79b4b69 100644
--- a/libc/bionic/gwp_asan_wrappers.cpp
+++ b/libc/bionic/gwp_asan_wrappers.cpp
@@ -144,10 +144,21 @@
 }
 
 void* gwp_asan_realloc(void* old_mem, size_t bytes) {
+  // GPA::pointerIsMine(p) always returns false where `p == nullptr` (and thus
+  // malloc(bytes) is requested). We always fall back to the backing allocator,
+  // technically missing some coverage, but reducing an extra conditional
+  // branch.
   if (__predict_false(GuardedAlloc.pointerIsMine(old_mem))) {
-    size_t old_size = GuardedAlloc.getSize(old_mem);
+    if (__predict_false(bytes == 0)) {
+      GuardedAlloc.deallocate(old_mem);
+      return nullptr;
+    }
     void* new_ptr = gwp_asan_malloc(bytes);
-    if (new_ptr) memcpy(new_ptr, old_mem, (bytes < old_size) ? bytes : old_size);
+    // If malloc() fails, then don't destroy the old memory.
+    if (__predict_false(new_ptr == nullptr)) return nullptr;
+
+    size_t old_size = GuardedAlloc.getSize(old_mem);
+    memcpy(new_ptr, old_mem, (bytes < old_size) ? bytes : old_size);
     GuardedAlloc.deallocate(old_mem);
     return new_ptr;
   }