[PATCH] D74567: [scudo][standalone] Workaround for full regions on Android
Kostya Kortchinsky via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 13 11:29:03 PST 2020
cryptoad updated this revision to Diff 244485.
cryptoad added a comment.
Adding the test here rather than later.
This made me realize that since the `SizeClassAllocator64` is used on 32-bit
(region size permitting), the `SCUDO_CAN_USE_PRIMARY64` check can't be applied.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D74567/new/
https://reviews.llvm.org/D74567
Files:
compiler-rt/lib/scudo/standalone/combined.h
compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
Index: compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
===================================================================
--- compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
+++ compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
@@ -344,7 +344,6 @@
#endif
}
-
struct DeathSizeClassConfig {
static const scudo::uptr NumBits = 1;
static const scudo::uptr MinSizeLog = 10;
@@ -354,10 +353,12 @@
static const scudo::uptr MaxBytesCachedLog = 10;
};
+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 @@
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);
+}
Index: compiler-rt/lib/scudo/standalone/combined.h
===================================================================
--- compiler-rt/lib/scudo/standalone/combined.h
+++ compiler-rt/lib/scudo/standalone/combined.h
@@ -267,6 +267,17 @@
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 {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D74567.244485.patch
Type: text/x-patch
Size: 3235 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20200213/6ec9c8b6/attachment.bin>
More information about the llvm-commits
mailing list