summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2020-06-19 00:55:04 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-06-19 00:55:04 +0000
commit1d271ba67bc88223db592cb721f2d0cc578ac978 (patch)
treee70da4e823d0f3ad195b7a2dbc480cb1e81b31ba
parent8441e8499d4963930036d8a1ca4d9e61d87d5f92 (diff)
parent520badfbe371eabc17415b0e79c03f1f7bf957fd (diff)
downloadscudo-1d271ba67bc88223db592cb721f2d0cc578ac978.tar.gz
[scudo][standalone] Allow Primary allocations to fail up multiple times. am: b7a688e544 am: 520badfbe3
Original change: https://googleplex-android-review.googlesource.com/c/platform/external/scudo/+/11914615 Change-Id: I4198484b6aa9916feaf442c6bcbb0efe9c3b3925
-rw-r--r--standalone/combined.h18
-rw-r--r--standalone/tests/combined_test.cpp17
2 files changed, 21 insertions, 14 deletions
diff --git a/standalone/combined.h b/standalone/combined.h
index 1aa93510d22..3ed34c21aa5 100644
--- a/standalone/combined.h
+++ b/standalone/combined.h
@@ -269,16 +269,20 @@ public:
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 dealing with the largest class, fallback to the Secondary.
+ // If the allocation failed, the most likely reason with a 32-bit primary
+ // is the region being full. In that event, retry in each successively
+ // larger class until it fits. If it fails to fit in the largest class,
+ // fallback to the Secondary.
if (UNLIKELY(!Block)) {
- if (ClassId < SizeClassMap::LargestClassId)
+ while (ClassId < SizeClassMap::LargestClassId) {
Block = TSD->Cache.allocate(++ClassId);
- else
+ if (LIKELY(Block)) {
+ break;
+ }
+ }
+ if (UNLIKELY(!Block)) {
ClassId = 0;
+ }
}
if (UnlockRequired)
TSD->unlock();
diff --git a/standalone/tests/combined_test.cpp b/standalone/tests/combined_test.cpp
index a6f29a2610e..a2c06182a68 100644
--- a/standalone/tests/combined_test.cpp
+++ b/standalone/tests/combined_test.cpp
@@ -348,14 +348,14 @@ 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 = 11;
+ static const scudo::uptr MaxSizeLog = 13;
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 two sizes.
+ // Tiny allocator, its Primary only serves chunks of four sizes.
using DeathSizeClassMap = scudo::FixedSizeClassMap<DeathSizeClassConfig>;
typedef scudo::SizeClassAllocator64<DeathSizeClassMap, DeathRegionSizeLog>
Primary;
@@ -435,7 +435,10 @@ TEST(ScudoCombinedTest, FullRegion) {
ClassId <= DeathConfig::DeathSizeClassMap::LargestClassId; ClassId++) {
const scudo::uptr Size =
DeathConfig::DeathSizeClassMap::getSizeByClassId(ClassId);
- const scudo::uptr MaxNumberOfChunks = (1U << DeathRegionSizeLog) / Size;
+ // Allocate enough to fill all of the regions above this one.
+ const scudo::uptr MaxNumberOfChunks =
+ ((1U << DeathRegionSizeLog) / Size) *
+ (DeathConfig::DeathSizeClassMap::LargestClassId - ClassId + 1);
void *P;
for (scudo::uptr I = 0; I <= MaxNumberOfChunks; I++) {
P = Allocator->allocate(Size - 64U, Origin);
@@ -444,10 +447,10 @@ TEST(ScudoCombinedTest, FullRegion) {
else
V.push_back(P);
}
- }
- while (!V.empty()) {
- Allocator->deallocate(V.back(), Origin);
- V.pop_back();
+ while (!V.empty()) {
+ Allocator->deallocate(V.back(), Origin);
+ V.pop_back();
+ }
}
EXPECT_EQ(FailedAllocationsCount, 0U);
}