diff --git a/compiler-rt/lib/scudo/standalone/local_cache.h b/compiler-rt/lib/scudo/standalone/local_cache.h --- a/compiler-rt/lib/scudo/standalone/local_cache.h +++ b/compiler-rt/lib/scudo/standalone/local_cache.h @@ -101,12 +101,22 @@ Stats.add(StatFree, ClassSize); } + bool isEmpty() const { + for (uptr I = 0; I < NumClasses; ++I) + if (PerClassArray[I].Count) + return false; + return true; + } + void drain() { - for (uptr I = 0; I < NumClasses; I++) { + // Drain BatchClassId (0) the last as createBatch cat refill it. + for (uptr I = NumClasses; I;) { + --I; PerClass *C = &PerClassArray[I]; while (C->Count > 0) drain(C, I); } + DCHECK(isEmpty()); } TransferBatch *createBatch(uptr ClassId, void *B) { diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp --- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp @@ -304,6 +304,14 @@ EXPECT_NE(Stats.find("Stats: SizeClassAllocator"), std::string::npos); EXPECT_NE(Stats.find("Stats: MapAllocator"), std::string::npos); EXPECT_NE(Stats.find("Stats: Quarantine"), std::string::npos); + + bool UnlockRequired; + auto *TSD = Allocator->getTSDRegistry()->getTSDAndLock(&UnlockRequired); + EXPECT_TRUE(!TSD->Cache.isEmpty()); + TSD->Cache.drain(); + EXPECT_TRUE(TSD->Cache.isEmpty()); + if (UnlockRequired) + TSD->unlock(); } // Test that multiple instantiations of the allocator have not messed up the