[compiler-rt] 2169571 - [scudo][standalone] Workaround for full regions on Android
Kostya Kortchinsky via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 13 12:54:54 PST 2020
Author: Kostya Kortchinsky
Date: 2020-02-13T12:54:25-08:00
New Revision: 21695710cfa9a36256e9547155e2b9e0139f5c6a
URL: https://github.com/llvm/llvm-project/commit/21695710cfa9a36256e9547155e2b9e0139f5c6a
DIFF: https://github.com/llvm/llvm-project/commit/21695710cfa9a36256e9547155e2b9e0139f5c6a.diff
LOG: [scudo][standalone] Workaround for full regions on Android
Summary:
Due to Unity, we had to reduce our region sizes, but in some rare
situations, some programs (mostly tests AFAICT) manage to fill up
a region for a given size class.
So this adds a workaround for that attempts to allocate the block
from the immediately larger size class, wasting some memory but
allowing the application to keep going.
Reviewers: pcc, eugenis, cferris, hctim, morehouse
Subscribers: #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D74567
Added:
Modified:
compiler-rt/lib/scudo/standalone/combined.h
compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
Removed:
################################################################################
diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h
index bd78d79857ec..e8390a7b44f1 100644
--- a/compiler-rt/lib/scudo/standalone/combined.h
+++ b/compiler-rt/lib/scudo/standalone/combined.h
@@ -267,6 +267,17 @@ class Allocator {
bool UnlockRequired;
auto *TSD = TSDRegistry.getTSDAndLock(&UnlockRequired);
Block = TSD->Cache.allocate(ClassId);
+ // If the allocation failed, the most likely reason with a 64-bit primary
+ // is the region being full. In that event, retry once using the
+ // immediately larger class (except if the failing class was already the
+ // largest). This will waste some memory but will allow the application to
+ // not fail.
+ if (SCUDO_ANDROID) {
+ if (UNLIKELY(!Block)) {
+ if (ClassId < SizeClassMap::LargestClassId)
+ Block = TSD->Cache.allocate(++ClassId);
+ }
+ }
if (UnlockRequired)
TSD->unlock();
} else {
diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
index 488dca91a359..ce1b2824788d 100644
--- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
@@ -344,20 +344,21 @@ TEST(ScudoCombinedTest, ThreadedCombined) {
#endif
}
-
struct DeathSizeClassConfig {
static const scudo::uptr NumBits = 1;
static const scudo::uptr MinSizeLog = 10;
static const scudo::uptr MidSizeLog = 10;
- static const scudo::uptr MaxSizeLog = 10;
- static const scudo::u32 MaxNumCachedHint = 1;
- static const scudo::uptr MaxBytesCachedLog = 10;
+ static const scudo::uptr MaxSizeLog = 11;
+ static const scudo::u32 MaxNumCachedHint = 4;
+ static const scudo::uptr MaxBytesCachedLog = 12;
};
+static const scudo::uptr DeathRegionSizeLog = 20U;
struct DeathConfig {
- // Tiny allocator, its Primary only serves chunks of 1024 bytes.
+ // Tiny allocator, its Primary only serves chunks of two sizes.
using DeathSizeClassMap = scudo::FixedSizeClassMap<DeathSizeClassConfig>;
- typedef scudo::SizeClassAllocator64<DeathSizeClassMap, 20U> Primary;
+ typedef scudo::SizeClassAllocator64<DeathSizeClassMap, DeathRegionSizeLog>
+ Primary;
typedef scudo::MapAllocator<scudo::MapAllocatorNoCache> Secondary;
template <class A> using TSDRegistryT = scudo::TSDRegistrySharedT<A, 1U>;
};
@@ -415,3 +416,39 @@ TEST(ScudoCombinedTest, ReleaseToOS) {
Allocator->releaseToOS();
}
+
+// Verify that when a region gets full, Android will still manage to
+// fulfill the allocation through a larger size class.
+TEST(ScudoCombinedTest, FullRegion) {
+ using AllocatorT = scudo::Allocator<DeathConfig>;
+ auto Deleter = [](AllocatorT *A) {
+ A->unmapTestOnly();
+ delete A;
+ };
+ std::unique_ptr<AllocatorT, decltype(Deleter)> Allocator(new AllocatorT,
+ Deleter);
+ Allocator->reset();
+
+ const scudo::uptr Size = 1000U;
+ const scudo::uptr MaxNumberOfChunks =
+ (1U << DeathRegionSizeLog) /
+ DeathConfig::DeathSizeClassMap::getSizeByClassId(1U);
+ void *P;
+ std::vector<void *> V;
+ scudo::uptr FailedAllocationsCount = 0;
+ for (scudo::uptr I = 0; I <= MaxNumberOfChunks; I++) {
+ P = Allocator->allocate(Size, Origin);
+ if (!P)
+ FailedAllocationsCount++;
+ else
+ V.push_back(P);
+ }
+ while (!V.empty()) {
+ Allocator->deallocate(V.back(), Origin);
+ V.pop_back();
+ }
+ if (SCUDO_ANDROID)
+ EXPECT_EQ(FailedAllocationsCount, 0U);
+ else
+ EXPECT_GT(FailedAllocationsCount, 0U);
+}
More information about the llvm-commits
mailing list