reinterpret_cast<uptr>(Ptr) - getHeaderSize());
}
-INLINE void *getBlockBegin(const void *Ptr, UnpackedHeader *Header) {
- return reinterpret_cast<void *>(reinterpret_cast<uptr>(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.
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);
reportSanityCheckError("class ID");
}
+ static INLINE void *getBlockBegin(const void *Ptr,
+ Chunk::UnpackedHeader *Header) {
+ return reinterpret_cast<void *>(reinterpret_cast<uptr>(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<uptr>(Ptr) - SizeOrUnusedBytes;
}
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;
#define SCUDO_LOCAL_CACHE_H_
#include "internal_defs.h"
+#include "report.h"
#include "stats.h"
namespace scudo {
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;
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;
}
}
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);
}
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);
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);
}
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);
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;
// 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) {
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));
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++) {