[scudo] Modify header corrupption error message (#126812) am: 0a5dfc4690

Original change: https://android-review.googlesource.com/c/platform/external/scudo/+/3491010

Change-Id: Ibcd2e9add789b8c50bea31b98f60fe372ddd16f9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/standalone/chunk.h b/standalone/chunk.h
index 9228df0..a1b8e72 100644
--- a/standalone/chunk.h
+++ b/standalone/chunk.h
@@ -125,7 +125,7 @@
   *NewUnpackedHeader = bit_cast<UnpackedHeader>(NewPackedHeader);
   if (UNLIKELY(NewUnpackedHeader->Checksum !=
                computeHeaderChecksum(Cookie, Ptr, NewUnpackedHeader)))
-    reportHeaderCorruption(const_cast<void *>(Ptr));
+    reportHeaderCorruption(NewUnpackedHeader, const_cast<void *>(Ptr));
 }
 
 inline bool isValid(u32 Cookie, const void *Ptr,
diff --git a/standalone/report.cpp b/standalone/report.cpp
index 9cef0ad..14a4066 100644
--- a/standalone/report.cpp
+++ b/standalone/report.cpp
@@ -9,6 +9,7 @@
 #include "report.h"
 
 #include "atomic_helpers.h"
+#include "chunk.h"
 #include "string_utils.h"
 
 #include <stdarg.h>
@@ -65,9 +66,18 @@
 
 // The checksum of a chunk header is invalid. This could be caused by an
 // {over,under}write of the header, a pointer that is not an actual chunk.
-void NORETURN reportHeaderCorruption(void *Ptr) {
+void NORETURN reportHeaderCorruption(void *Header, void *Ptr) {
   ScopedErrorReport Report;
-  Report.append("corrupted chunk header at address %p\n", Ptr);
+  Report.append("corrupted chunk header at address %p", Ptr);
+  if (*static_cast<Chunk::PackedHeader *>(Header) == 0U) {
+    // Header all zero, which could indicate that this might be a pointer that
+    // has been double freed but the memory has been released to the kernel.
+    Report.append(": chunk header is zero and might indicate memory corruption "
+                  "or a double free\n",
+                  Ptr);
+  } else {
+    Report.append(": most likely due to memory corruption\n", Ptr);
+  }
 }
 
 // The allocator was compiled with parameters that conflict with field size
diff --git a/standalone/report.h b/standalone/report.h
index a510fda..c0214b5 100644
--- a/standalone/report.h
+++ b/standalone/report.h
@@ -12,7 +12,6 @@
 #include "internal_defs.h"
 
 namespace scudo {
-
 // Reports are *fatal* unless stated otherwise.
 
 // Generic error, adds newline to end of message.
@@ -25,7 +24,7 @@
 void NORETURN reportInvalidFlag(const char *FlagType, const char *Value);
 
 // Chunk header related errors.
-void NORETURN reportHeaderCorruption(void *Ptr);
+void NORETURN reportHeaderCorruption(void *Header, void *Ptr);
 
 // Sanity checks related error.
 void NORETURN reportSanityCheckError(const char *Field);
diff --git a/standalone/tests/report_test.cpp b/standalone/tests/report_test.cpp
index 6c46243..514837d 100644
--- a/standalone/tests/report_test.cpp
+++ b/standalone/tests/report_test.cpp
@@ -8,6 +8,7 @@
 
 #include "tests/scudo_unit_test.h"
 
+#include "chunk.h"
 #include "report.h"
 
 TEST(ScudoReportDeathTest, Check) {
@@ -20,9 +21,11 @@
 TEST(ScudoReportDeathTest, Generic) {
   // Potentially unused if EXPECT_DEATH isn't defined.
   UNUSED void *P = reinterpret_cast<void *>(0x42424242U);
+  UNUSED scudo::Chunk::PackedHeader Header = {};
   EXPECT_DEATH(scudo::reportError("TEST123"), "Scudo ERROR.*TEST123");
   EXPECT_DEATH(scudo::reportInvalidFlag("ABC", "DEF"), "Scudo ERROR.*ABC.*DEF");
-  EXPECT_DEATH(scudo::reportHeaderCorruption(P), "Scudo ERROR.*42424242");
+  EXPECT_DEATH(scudo::reportHeaderCorruption(&Header, P),
+               "Scudo ERROR.*42424242");
   EXPECT_DEATH(scudo::reportSanityCheckError("XYZ"), "Scudo ERROR.*XYZ");
   EXPECT_DEATH(scudo::reportAlignmentTooBig(123, 456), "Scudo ERROR.*123.*456");
   EXPECT_DEATH(scudo::reportAllocationSizeTooBig(123, 456, 789),
@@ -54,6 +57,19 @@
                "Scudo ERROR.*123.*456");
 }
 
+TEST(ScudoReportDeathTest, HeaderCorruption) {
+  UNUSED void *P = reinterpret_cast<void *>(0x42424242U);
+  UNUSED scudo::Chunk::PackedHeader Header = {};
+  EXPECT_DEATH(scudo::reportHeaderCorruption(&Header, P),
+               "Scudo ERROR.*corrupted chunk header at address 0x.*42424242: "
+               "chunk header is zero and might indicate memory "
+               "corruption or a double free");
+  Header = 10U;
+  EXPECT_DEATH(scudo::reportHeaderCorruption(&Header, P),
+               "Scudo ERROR.*corrupted chunk header at address 0x.*42424242: "
+               "most likely due to memory corruption");
+}
+
 #if SCUDO_LINUX || SCUDO_TRUSTY || SCUDO_ANDROID
 #include "report_linux.h"