diff --git a/compiler-rt/lib/scudo/standalone/chunk.h b/compiler-rt/lib/scudo/standalone/chunk.h index 9228df0471890..a1b8e723d4cb5 100644 --- a/compiler-rt/lib/scudo/standalone/chunk.h +++ b/compiler-rt/lib/scudo/standalone/chunk.h @@ -125,7 +125,7 @@ inline void loadHeader(u32 Cookie, const void *Ptr, *NewUnpackedHeader = bit_cast(NewPackedHeader); if (UNLIKELY(NewUnpackedHeader->Checksum != computeHeaderChecksum(Cookie, Ptr, NewUnpackedHeader))) - reportHeaderCorruption(const_cast(Ptr)); + reportHeaderCorruption(NewUnpackedHeader, const_cast(Ptr)); } inline bool isValid(u32 Cookie, const void *Ptr, diff --git a/compiler-rt/lib/scudo/standalone/report.cpp b/compiler-rt/lib/scudo/standalone/report.cpp index 9cef0adc0bb31..14a4066d37200 100644 --- a/compiler-rt/lib/scudo/standalone/report.cpp +++ b/compiler-rt/lib/scudo/standalone/report.cpp @@ -9,6 +9,7 @@ #include "report.h" #include "atomic_helpers.h" +#include "chunk.h" #include "string_utils.h" #include @@ -65,9 +66,18 @@ void NORETURN reportInvalidFlag(const char *FlagType, const char *Value) { // 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) { - ScopedErrorReport Report; - Report.append("corrupted chunk header at address %p\n", Ptr); +void NORETURN reportHeaderCorruption(void *Header, void *Ptr) { + ScopedErrorReport Report; + Report.append("corrupted chunk header at address %p", Ptr); + if (*static_cast(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/compiler-rt/lib/scudo/standalone/report.h b/compiler-rt/lib/scudo/standalone/report.h index a510fdaebb6de..c0214b51560e9 100644 --- a/compiler-rt/lib/scudo/standalone/report.h +++ b/compiler-rt/lib/scudo/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 reportRawError(const char *Message); 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/compiler-rt/lib/scudo/standalone/tests/report_test.cpp b/compiler-rt/lib/scudo/standalone/tests/report_test.cpp index 6c46243053d9e..514837df1a43a 100644 --- a/compiler-rt/lib/scudo/standalone/tests/report_test.cpp +++ b/compiler-rt/lib/scudo/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, Check) { TEST(ScudoReportDeathTest, Generic) { // Potentially unused if EXPECT_DEATH isn't defined. UNUSED void *P = reinterpret_cast(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 @@ TEST(ScudoReportDeathTest, CSpecific) { "Scudo ERROR.*123.*456"); } +TEST(ScudoReportDeathTest, HeaderCorruption) { + UNUSED void *P = reinterpret_cast(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"