[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;
}