Index: lib/scudo/standalone/chunk.h =================================================================== --- lib/scudo/standalone/chunk.h +++ lib/scudo/standalone/chunk.h @@ -97,12 +97,6 @@ reinterpret_cast(Ptr) - getHeaderSize()); } -INLINE void *getBlockBegin(const void *Ptr, UnpackedHeader *Header) { - return reinterpret_cast(reinterpret_cast(Ptr) - - getHeaderSize() - - (Header->Offset << SCUDO_MIN_ALIGNMENT_LOG)); -} - // We do not need a cryptographically strong hash for the checksum, but a CRC // type function that can alert us in the event a header is invalid or // corrupted. Ideally slightly better than a simple xor of all fields. Index: lib/scudo/standalone/combined.h =================================================================== --- lib/scudo/standalone/combined.h +++ lib/scudo/standalone/combined.h @@ -45,7 +45,7 @@ NewHeader.State = Chunk::State::Available; Chunk::compareExchangeHeader(Allocator.Cookie, Ptr, &NewHeader, &Header); - void *BlockBegin = Chunk::getBlockBegin(Ptr, &Header); + void *BlockBegin = Allocator::getBlockBegin(Ptr, &NewHeader); const uptr ClassId = Header.ClassId; if (ClassId) Cache.deallocate(ClassId, BlockBegin); @@ -482,12 +482,19 @@ reportSanityCheckError("class ID"); } + static INLINE void *getBlockBegin(const void *Ptr, + Chunk::UnpackedHeader *Header) { + return reinterpret_cast(reinterpret_cast(Ptr) - + Chunk::getHeaderSize() - + (Header->Offset << MinAlignmentLog)); + } + // Return the size of a chunk as requested during its allocation. INLINE uptr getSize(const void *Ptr, Chunk::UnpackedHeader *Header) { const uptr SizeOrUnusedBytes = Header->SizeOrUnusedBytes; if (Header->ClassId) return SizeOrUnusedBytes; - return SecondaryT::getBlockEnd(Chunk::getBlockBegin(Ptr, Header)) - + return SecondaryT::getBlockEnd(getBlockBegin(Ptr, Header)) - reinterpret_cast(Ptr) - SizeOrUnusedBytes; } @@ -505,7 +512,7 @@ if (BypassQuarantine) { NewHeader.State = Chunk::State::Available; Chunk::compareExchangeHeader(Cookie, Ptr, &NewHeader, Header); - void *BlockBegin = Chunk::getBlockBegin(Ptr, Header); + void *BlockBegin = getBlockBegin(Ptr, &NewHeader); const uptr ClassId = NewHeader.ClassId; if (ClassId) { bool UnlockRequired; Index: lib/scudo/standalone/local_cache.h =================================================================== --- lib/scudo/standalone/local_cache.h +++ lib/scudo/standalone/local_cache.h @@ -10,6 +10,7 @@ #define SCUDO_LOCAL_CACHE_H_ #include "internal_defs.h" +#include "report.h" #include "stats.h" namespace scudo { @@ -39,7 +40,7 @@ DCHECK_LE(I, Count); return Batch[I]; } - static u32 MaxCached(uptr Size) { + static u32 getMaxCached(uptr Size) { return Min(MaxNumCached, SizeClassMap::getMaxCachedHint(Size)); } TransferBatch *Next; @@ -140,7 +141,7 @@ for (uptr I = 0; I < NumClasses; I++) { PerClass *P = &PerClassArray[I]; const uptr Size = SizeClassAllocator::getSizeByClassId(I); - P->MaxCount = 2 * TransferBatch::MaxCached(Size); + P->MaxCount = 2 * TransferBatch::getMaxCached(Size); P->ClassSize = Size; } } @@ -166,7 +167,9 @@ const u32 Count = Min(C->MaxCount / 2, C->Count); const uptr FirstIndexToDrain = C->Count - Count; TransferBatch *B = createBatch(ClassId, C->Chunks[FirstIndexToDrain]); - CHECK(B); + if (UNLIKELY(!B)) + reportOutOfMemory( + SizeClassAllocator::getSizeByClassId(SizeClassMap::BatchClassId)); B->setFromArray(&C->Chunks[FirstIndexToDrain], Count); C->Count -= Count; Allocator->pushBatch(ClassId, B); Index: lib/scudo/standalone/primary32.h =================================================================== --- lib/scudo/standalone/primary32.h +++ lib/scudo/standalone/primary32.h @@ -162,7 +162,9 @@ } void releaseToOS() { - for (uptr I = 1; I < NumClasses; I++) { + for (uptr I = 0; I < NumClasses; I++) { + if (I == SizeClassMap::BatchClassId) + continue; SizeClassInfo *Sci = getSizeClassInfo(I); ScopedLock L(Sci->Mutex); releaseToOSMaybe(Sci, I, /*Force=*/true); @@ -291,7 +293,7 @@ return nullptr; C->getStats().add(StatMapped, RegionSize); const uptr Size = getSizeByClassId(ClassId); - const u32 MaxCount = TransferBatch::MaxCached(Size); + const u32 MaxCount = TransferBatch::getMaxCached(Size); DCHECK_GT(MaxCount, 0); const uptr NumberOfBlocks = RegionSize / Size; DCHECK_GT(NumberOfBlocks, 0); Index: lib/scudo/standalone/primary64.h =================================================================== --- lib/scudo/standalone/primary64.h +++ lib/scudo/standalone/primary64.h @@ -166,7 +166,9 @@ } void releaseToOS() { - for (uptr I = 1; I < NumClasses; I++) { + for (uptr I = 0; I < NumClasses; I++) { + if (I == SizeClassMap::BatchClassId) + continue; RegionInfo *Region = getRegionInfo(I); ScopedLock L(Region->Mutex); releaseToOSMaybe(Region, I, /*Force=*/true); @@ -249,7 +251,7 @@ NOINLINE TransferBatch *populateFreeList(CacheT *C, uptr ClassId, RegionInfo *Region) { const uptr Size = getSizeByClassId(ClassId); - const u32 MaxCount = TransferBatch::MaxCached(Size); + const u32 MaxCount = TransferBatch::getMaxCached(Size); const uptr RegionBeg = Region->RegionBeg; const uptr MappedUser = Region->MappedUser; Index: lib/scudo/standalone/report.cc =================================================================== --- lib/scudo/standalone/report.cc +++ lib/scudo/standalone/report.cc @@ -52,7 +52,7 @@ // Generic string fatal error message. void NORETURN reportError(const char *Message) { ScopedErrorReport Report; - Report.append("%s", Message); + Report.append("%s\n", Message); } void NORETURN reportInvalidFlag(const char *FlagType, const char *Value) { Index: lib/scudo/standalone/tests/chunk_test.cc =================================================================== --- lib/scudo/standalone/tests/chunk_test.cc +++ lib/scudo/standalone/tests/chunk_test.cc @@ -30,7 +30,6 @@ HeaderSize); scudo::Chunk::storeHeader(Cookie, P, &Header); memset(P, 'A', Size); - EXPECT_EQ(scudo::Chunk::getBlockBegin(P, &Header), Block); scudo::Chunk::loadHeader(Cookie, P, &Header); EXPECT_TRUE(scudo::Chunk::isValid(Cookie, P, &Header)); EXPECT_FALSE(scudo::Chunk::isValid(InvalidCookie, P, &Header)); @@ -70,7 +69,6 @@ HeaderSize); scudo::Chunk::storeHeader(Cookie, P, &Header); memset(P, 'A', Size); - EXPECT_EQ(scudo::Chunk::getBlockBegin(P, &Header), Block); scudo::Chunk::loadHeader(Cookie, P, &Header); // Simulate a couple of corrupted bits per byte of header data. for (scudo::uptr I = 0; I < sizeof(scudo::Chunk::PackedHeader); I++) {