Index: lib/scudo/CMakeLists.txt =================================================================== --- lib/scudo/CMakeLists.txt +++ lib/scudo/CMakeLists.txt @@ -9,6 +9,10 @@ set(SCUDO_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) +# Use gc-sections by default to avoid unused code being pulled in. +list(APPEND SCUDO_CFLAGS -ffunction-sections -fdata-sections) +list(APPEND SCUDO_DYNAMIC_LINK_FLAGS -Wl,--gc-sections) + set(SCUDO_SOURCES scudo_allocator.cpp scudo_crc32.cpp Index: lib/scudo/scudo_allocator.cpp =================================================================== --- lib/scudo/scudo_allocator.cpp +++ lib/scudo/scudo_allocator.cpp @@ -136,7 +136,7 @@ *NewUnpackedHeader = bit_cast(NewPackedHeader); if (UNLIKELY(NewUnpackedHeader->Checksum != computeChecksum(Ptr, NewUnpackedHeader))) { - dieWithMessage("ERROR: corrupted chunk header at address %p\n", Ptr); + dieWithMessage("corrupted chunk header at address %p\n", Ptr); } } @@ -159,7 +159,7 @@ if (UNLIKELY(!atomic_compare_exchange_strong( getAtomicHeader(Ptr), &OldPackedHeader, NewPackedHeader, memory_order_relaxed))) { - dieWithMessage("ERROR: race on chunk header at address %p\n", Ptr); + dieWithMessage("race on chunk header at address %p\n", Ptr); } } } // namespace Chunk @@ -174,8 +174,7 @@ UnpackedHeader Header; Chunk::loadHeader(Ptr, &Header); if (UNLIKELY(Header.State != ChunkQuarantine)) { - dieWithMessage("ERROR: invalid chunk state when recycling address %p\n", - Ptr); + dieWithMessage("invalid chunk state when recycling address %p\n", Ptr); } Chunk::eraseHeader(Ptr); void *BackendPtr = Chunk::getBackendPtr(Ptr, &Header); @@ -236,7 +235,7 @@ explicit ScudoAllocator(LinkerInitialized) : AllocatorQuarantine(LINKER_INITIALIZED) {} - void performSanityChecks() { + NOINLINE void performSanityChecks() { // Verify that the header offset field can hold the maximum offset. In the // case of the Secondary allocator, it takes care of alignment and the // offset will always be 0. In the case of the Primary, the worst case @@ -252,8 +251,7 @@ (MaxPrimaryAlignment - Chunk::getHeaderSize()) >> MinAlignmentLog; Header.Offset = MaxOffset; if (Header.Offset != MaxOffset) { - dieWithMessage("ERROR: the maximum possible offset doesn't fit in the " - "header\n"); + dieWithMessage("maximum possible offset doesn't fit in header\n"); } // Verify that we can fit the maximum size or amount of unused bytes in the // header. Given that the Secondary fits the allocation to a page, the worst @@ -263,14 +261,13 @@ const uptr MaxSizeOrUnusedBytes = SizeClassMap::kMaxSize - 1; Header.SizeOrUnusedBytes = MaxSizeOrUnusedBytes; if (Header.SizeOrUnusedBytes != MaxSizeOrUnusedBytes) { - dieWithMessage("ERROR: the maximum possible unused bytes doesn't fit in " - "the header\n"); + dieWithMessage("maximum possible unused bytes doesn't fit in header\n"); } const uptr LargestClassId = SizeClassMap::kLargestClassID; Header.ClassId = LargestClassId; if (Header.ClassId != LargestClassId) { - dieWithMessage("ERROR: the largest class ID doesn't fit in the header\n"); + dieWithMessage("largest class ID doesn't fit in header\n"); } } @@ -332,11 +329,9 @@ // RSS from /proc/self/statm by default. We might want to // call getrusage directly, even if it's less accurate. const uptr CurrentRssMb = GetRSS() >> 20; - if (HardRssLimitMb && HardRssLimitMb < CurrentRssMb) { - Report("%s: hard RSS limit exhausted (%zdMb vs %zdMb)\n", - SanitizerToolName, HardRssLimitMb, CurrentRssMb); - DumpProcessMap(); - Die(); + if (HardRssLimitMb && UNLIKELY(HardRssLimitMb < CurrentRssMb)) { + dieWithMessage("hard RSS limit exhausted (%zdMb vs %zdMb)\n", + HardRssLimitMb, CurrentRssMb); } if (SoftRssLimitMb) { if (atomic_load_relaxed(&RssLimitExceeded)) { @@ -345,8 +340,8 @@ } else { if (CurrentRssMb > SoftRssLimitMb) { atomic_store_relaxed(&RssLimitExceeded, true); - Report("%s: soft RSS limit exhausted (%zdMb vs %zdMb)\n", - SanitizerToolName, SoftRssLimitMb, CurrentRssMb); + Printf("Scudo INFO: soft RSS limit exhausted (%zdMb vs %zdMb)\n", + SoftRssLimitMb, CurrentRssMb); } } } @@ -485,22 +480,20 @@ if (UNLIKELY(!Ptr)) return; if (UNLIKELY(!Chunk::isAligned(Ptr))) { - dieWithMessage("ERROR: attempted to deallocate a chunk not properly " - "aligned at address %p\n", Ptr); + dieWithMessage("misaligned pointer when deallocating address %p\n", Ptr); } UnpackedHeader Header; Chunk::loadHeader(Ptr, &Header); if (UNLIKELY(Header.State != ChunkAllocated)) { - dieWithMessage("ERROR: invalid chunk state when deallocating address " - "%p\n", Ptr); + dieWithMessage("invalid chunk state when deallocating address %p\n", Ptr); } if (DeallocationTypeMismatch) { // The deallocation type has to match the allocation one. if (Header.AllocType != Type) { // With the exception of memalign'd Chunks, that can be still be free'd. if (Header.AllocType != FromMemalign || Type != FromMalloc) { - dieWithMessage("ERROR: allocation type mismatch when deallocating " - "address %p\n", Ptr); + dieWithMessage("allocation type mismatch when deallocating address " + "%p\n", Ptr); } } } @@ -508,7 +501,7 @@ Chunk::getUsableSize(Ptr, &Header) - Header.SizeOrUnusedBytes; if (DeleteSizeMismatch) { if (DeleteSize && DeleteSize != Size) { - dieWithMessage("ERROR: invalid sized delete on chunk at address %p\n", + dieWithMessage("invalid sized delete when deallocating address %p\n", Ptr); } } @@ -520,19 +513,19 @@ void *reallocate(void *OldPtr, uptr NewSize) { initThreadMaybe(); if (UNLIKELY(!Chunk::isAligned(OldPtr))) { - dieWithMessage("ERROR: attempted to reallocate a chunk not properly " - "aligned at address %p\n", OldPtr); + dieWithMessage("misaligned address when reallocating address %p\n", + OldPtr); } UnpackedHeader OldHeader; Chunk::loadHeader(OldPtr, &OldHeader); if (UNLIKELY(OldHeader.State != ChunkAllocated)) { - dieWithMessage("ERROR: invalid chunk state when reallocating address " - "%p\n", OldPtr); + dieWithMessage("invalid chunk state when reallocating address %p\n", + OldPtr); } if (DeallocationTypeMismatch) { if (UNLIKELY(OldHeader.AllocType != FromMalloc)) { - dieWithMessage("ERROR: allocation type mismatch when reallocating " - "address %p\n", OldPtr); + dieWithMessage("allocation type mismatch when reallocating address " + "%p\n", OldPtr); } } const uptr UsableSize = Chunk::getUsableSize(OldPtr, &OldHeader); @@ -567,8 +560,7 @@ Chunk::loadHeader(Ptr, &Header); // Getting the usable size of a chunk only makes sense if it's allocated. if (UNLIKELY(Header.State != ChunkAllocated)) { - dieWithMessage("ERROR: invalid chunk state when sizing address %p\n", - Ptr); + dieWithMessage("invalid chunk state when sizing address %p\n", Ptr); } return Chunk::getUsableSize(Ptr, &Header); } Index: lib/scudo/scudo_termination.cpp =================================================================== --- lib/scudo/scudo_termination.cpp +++ lib/scudo/scudo_termination.cpp @@ -35,7 +35,7 @@ void NORETURN CheckFailed(const char *File, int Line, const char *Condition, u64 Value1, u64 Value2) { - __scudo::dieWithMessage("Scudo CHECK failed: %s:%d %s (%lld, %lld)\n", + __scudo::dieWithMessage("CHECK failed at %s:%d %s (%lld, %lld)\n", File, Line, Condition, Value1, Value2); } Index: lib/scudo/scudo_utils.cpp =================================================================== --- lib/scudo/scudo_utils.cpp +++ lib/scudo/scudo_utils.cpp @@ -38,11 +38,14 @@ namespace __scudo { FORMAT(1, 2) void NORETURN dieWithMessage(const char *Format, ...) { + static const char ScudoError[] = "Scudo ERROR: "; + static constexpr uptr PrefixSize = sizeof(ScudoError) - 1; // Our messages are tiny, 256 characters is more than enough. char Message[256]; va_list Args; va_start(Args, Format); - VSNPrintf(Message, sizeof(Message), Format, Args); + internal_memcpy(Message, ScudoError, PrefixSize); + VSNPrintf(Message + PrefixSize, sizeof(Message) - PrefixSize, Format, Args); va_end(Args); RawWrite(Message); Die(); Index: test/scudo/alignment.c =================================================================== --- test/scudo/alignment.c +++ test/scudo/alignment.c @@ -20,4 +20,4 @@ return 0; } -// CHECK: ERROR: attempted to deallocate a chunk not properly aligned +// CHECK: ERROR: misaligned pointer when deallocating address Index: test/scudo/sized-delete.cpp =================================================================== --- test/scudo/sized-delete.cpp +++ test/scudo/sized-delete.cpp @@ -38,4 +38,4 @@ return 0; } -// CHECK: ERROR: invalid sized delete on chunk at address +// CHECK: ERROR: invalid sized delete when deallocating address