diff options
Diffstat (limited to 'compiler-rt')
| -rw-r--r-- | compiler-rt/lib/asan/asan_interceptors.cpp | 4 | ||||
| -rw-r--r-- | compiler-rt/lib/scudo/standalone/secondary.h | 69 | ||||
| -rw-r--r-- | compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp | 85 |
3 files changed, 129 insertions, 29 deletions
diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index c43332c..8643271 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -58,7 +58,7 @@ namespace __asan { static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { #if SANITIZER_INTERCEPT_STRNLEN - if (REAL(strnlen) != nullptr) + if (static_cast<bool>(REAL(strnlen))) return REAL(strnlen)(s, maxlen); # endif return internal_strnlen(s, maxlen); @@ -66,7 +66,7 @@ static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { static inline uptr MaybeRealWcsnlen(const wchar_t* s, uptr maxlen) { # if SANITIZER_INTERCEPT_WCSNLEN - if (REAL(wcsnlen) != nullptr) + if (static_cast<bool>(REAL(wcsnlen))) return REAL(wcsnlen)(s, maxlen); # endif return internal_wcsnlen(s, maxlen); diff --git a/compiler-rt/lib/scudo/standalone/secondary.h b/compiler-rt/lib/scudo/standalone/secondary.h index f0b7bce..2509db2 100644 --- a/compiler-rt/lib/scudo/standalone/secondary.h +++ b/compiler-rt/lib/scudo/standalone/secondary.h @@ -249,6 +249,7 @@ public: LRUEntries.clear(); LRUEntries.init(Entries, sizeof(Entries)); + OldestPresentEntry = nullptr; AvailEntries.clear(); AvailEntries.init(Entries, sizeof(Entries)); @@ -322,8 +323,6 @@ public: } CachedBlock PrevEntry = Quarantine[QuarantinePos]; Quarantine[QuarantinePos] = Entry; - if (OldestTime == 0) - OldestTime = Entry.Time; Entry = PrevEntry; } @@ -339,9 +338,6 @@ public: } insert(Entry); - - if (OldestTime == 0) - OldestTime = Entry.Time; } while (0); for (MemMapT &EvictMemMap : EvictionMemMaps) @@ -355,7 +351,6 @@ public: SCUDO_SCOPED_TRACE( GetSecondaryReleaseToOSTraceName(ReleaseToOS::Normal)); - // TODO: Add ReleaseToOS logic to LRU algorithm releaseOlderThan(Time - static_cast<u64>(Interval) * 1000000); Mutex.unlock(); } else @@ -535,6 +530,11 @@ public: void unmapTestOnly() { empty(); } + void releaseOlderThanTestOnly(u64 ReleaseTime) { + ScopedLock L(Mutex); + releaseOlderThan(ReleaseTime); + } + private: void insert(const CachedBlock &Entry) REQUIRES(Mutex) { CachedBlock *AvailEntry = AvailEntries.front(); @@ -542,10 +542,16 @@ private: *AvailEntry = Entry; LRUEntries.push_front(AvailEntry); + if (OldestPresentEntry == nullptr && AvailEntry->Time != 0) + OldestPresentEntry = AvailEntry; } void remove(CachedBlock *Entry) REQUIRES(Mutex) { DCHECK(Entry->isValid()); + if (OldestPresentEntry == Entry) { + OldestPresentEntry = LRUEntries.getPrev(Entry); + DCHECK(OldestPresentEntry == nullptr || OldestPresentEntry->Time != 0); + } LRUEntries.remove(Entry); Entry->invalidate(); AvailEntries.push_front(Entry); @@ -560,6 +566,7 @@ private: for (CachedBlock &Entry : LRUEntries) MapInfo[N++] = Entry.MemMap; LRUEntries.clear(); + OldestPresentEntry = nullptr; } for (uptr I = 0; I < N; I++) { MemMapT &MemMap = MapInfo[I]; @@ -567,36 +574,42 @@ private: } } - void releaseIfOlderThan(CachedBlock &Entry, u64 Time) REQUIRES(Mutex) { - if (!Entry.isValid() || !Entry.Time) - return; - if (Entry.Time > Time) { - if (OldestTime == 0 || Entry.Time < OldestTime) - OldestTime = Entry.Time; - return; + void releaseOlderThan(u64 ReleaseTime) REQUIRES(Mutex) { + SCUDO_SCOPED_TRACE(GetSecondaryReleaseOlderThanTraceName()); + + if (!Config::getQuarantineDisabled()) { + for (uptr I = 0; I < Config::getQuarantineSize(); I++) { + auto &Entry = Quarantine[I]; + if (!Entry.isValid() || Entry.Time == 0 || Entry.Time > ReleaseTime) + continue; + Entry.MemMap.releaseAndZeroPagesToOS(Entry.CommitBase, + Entry.CommitSize); + Entry.Time = 0; + } } - Entry.MemMap.releaseAndZeroPagesToOS(Entry.CommitBase, Entry.CommitSize); - Entry.Time = 0; - } - void releaseOlderThan(u64 Time) REQUIRES(Mutex) { - SCUDO_SCOPED_TRACE(GetSecondaryReleaseOlderThanTraceName()); + for (CachedBlock *Entry = OldestPresentEntry; Entry != nullptr; + Entry = LRUEntries.getPrev(Entry)) { + DCHECK(Entry->isValid()); + DCHECK(Entry->Time != 0); + + if (Entry->Time > ReleaseTime) { + // All entries are newer than this, so no need to keep scanning. + OldestPresentEntry = Entry; + return; + } - if (!LRUEntries.size() || OldestTime == 0 || OldestTime > Time) - return; - OldestTime = 0; - if (!Config::getQuarantineDisabled()) - for (uptr I = 0; I < Config::getQuarantineSize(); I++) - releaseIfOlderThan(Quarantine[I], Time); - for (uptr I = 0; I < Config::getEntriesArraySize(); I++) - releaseIfOlderThan(Entries[I], Time); + Entry->MemMap.releaseAndZeroPagesToOS(Entry->CommitBase, + Entry->CommitSize); + Entry->Time = 0; + } + OldestPresentEntry = nullptr; } HybridMutex Mutex; u32 QuarantinePos GUARDED_BY(Mutex) = 0; atomic_u32 MaxEntriesCount = {}; atomic_uptr MaxEntrySize = {}; - u64 OldestTime GUARDED_BY(Mutex) = 0; atomic_s32 ReleaseToOsIntervalMs = {}; u32 CallsToRetrieve GUARDED_BY(Mutex) = 0; u32 SuccessfulRetrieves GUARDED_BY(Mutex) = 0; @@ -606,6 +619,8 @@ private: NonZeroLengthArray<CachedBlock, Config::getQuarantineSize()> Quarantine GUARDED_BY(Mutex) = {}; + // The oldest entry in the LRUEntries that has Time non-zero. + CachedBlock *OldestPresentEntry GUARDED_BY(Mutex) = nullptr; // Cached blocks stored in LRU order DoublyLinkedList<CachedBlock> LRUEntries GUARDED_BY(Mutex); // The unused Entries diff --git a/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp b/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp index d8a7f6b..855a3e6 100644 --- a/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp @@ -403,6 +403,11 @@ template <class Config> struct CacheInfoType { MemMap.getBase(), MemMap); } } + + void storeMemMap(scudo::MemMapT &MemMap) { + Cache->store(Options, MemMap.getBase(), MemMap.getCapacity(), + MemMap.getBase(), MemMap); + } }; TEST(ScudoSecondaryTest, AllocatorCacheEntryOrder) { @@ -503,3 +508,83 @@ TEST(ScudoSecondaryTest, AllocatorCacheOptions) { Info.Cache->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 20)); EXPECT_TRUE(Info.Cache->canCache(1UL << 16)); } + +TEST(ScudoSecondaryTest, ReleaseOlderThanAllEntries) { + CacheInfoType<TestCacheConfig> Info; + using CacheConfig = CacheInfoType<TestCacheConfig>::CacheConfig; + + Info.Cache->releaseOlderThanTestOnly(UINT64_MAX); + + Info.fillCacheWithSameSizeBlocks(CacheConfig::getDefaultMaxEntriesCount(), + 1024); + for (size_t I = 0; I < Info.MemMaps.size(); I++) { + // Set the first u32 value to a non-zero value. + *reinterpret_cast<scudo::u32 *>(Info.MemMaps[I].getBase()) = 10; + } + + Info.Cache->releaseOlderThanTestOnly(UINT64_MAX); + + EXPECT_EQ(Info.MemMaps.size(), CacheConfig::getDefaultMaxEntriesCount()); + for (size_t I = 0; I < Info.MemMaps.size(); I++) { + // All released maps will now be zero. + EXPECT_EQ(*reinterpret_cast<scudo::u32 *>(Info.MemMaps[I].getBase()), 0U); + } +} + +// This test assumes that the timestamp comes from getMonotonicFast. +TEST(ScudoSecondaryTest, ReleaseOlderThanGroups) { + CacheInfoType<TestCacheConfig> Info; + + // Disable the release interval so we can do tests the releaseOlderThan + // function. + Info.Cache->setOption(scudo::Option::ReleaseInterval, -1); + + // Create all of the maps we are going to use. + for (size_t I = 0; I < 6; I++) { + Info.MemMaps.emplace_back(Info.allocate(1024)); + // Set the first u32 value to a non-zero value. + *reinterpret_cast<scudo::u32 *>(Info.MemMaps[I].getBase()) = 10; + } + + // Create three groups of entries at three different intervals. + Info.storeMemMap(Info.MemMaps[0]); + Info.storeMemMap(Info.MemMaps[1]); + scudo::u64 FirstTime = scudo::getMonotonicTimeFast(); + + // Need to make sure the next set of entries are stamped with a newer time. + while (scudo::getMonotonicTimeFast() <= FirstTime) + ; + + Info.storeMemMap(Info.MemMaps[2]); + Info.storeMemMap(Info.MemMaps[3]); + scudo::u64 SecondTime = scudo::getMonotonicTimeFast(); + + // Need to make sure the next set of entries are stamped with a newer time. + while (scudo::getMonotonicTimeFast() <= SecondTime) + ; + + Info.storeMemMap(Info.MemMaps[4]); + Info.storeMemMap(Info.MemMaps[5]); + scudo::u64 ThirdTime = scudo::getMonotonicTimeFast(); + + Info.Cache->releaseOlderThanTestOnly(FirstTime); + for (size_t I = 0; I < 2; I++) { + EXPECT_EQ(*reinterpret_cast<scudo::u32 *>(Info.MemMaps[I].getBase()), 0U); + } + for (size_t I = 2; I < 6; I++) { + EXPECT_EQ(*reinterpret_cast<scudo::u32 *>(Info.MemMaps[I].getBase()), 10U); + } + + Info.Cache->releaseOlderThanTestOnly(SecondTime); + for (size_t I = 0; I < 4; I++) { + EXPECT_EQ(*reinterpret_cast<scudo::u32 *>(Info.MemMaps[I].getBase()), 0U); + } + for (size_t I = 4; I < 6; I++) { + EXPECT_EQ(*reinterpret_cast<scudo::u32 *>(Info.MemMaps[I].getBase()), 10U); + } + + Info.Cache->releaseOlderThanTestOnly(ThirdTime); + for (size_t I = 0; I < 6; I++) { + EXPECT_EQ(*reinterpret_cast<scudo::u32 *>(Info.MemMaps[I].getBase()), 0U); + } +} |
