@@ -315,12 +315,13 @@ template <class SizeClassMap> void testPageMapMarkRange() {
315
315
const scudo::uptr RoundedRegionSize = scudo::roundUp (RegionSize, PageSize);
316
316
317
317
std::vector<scudo::uptr> Pages (RoundedRegionSize / PageSize, 0 );
318
- for (scudo::uptr Block = 0 ; Block + BlockSize <= RoundedRegionSize;
319
- Block += BlockSize) {
320
- for (scudo::uptr page = Block / PageSize;
321
- page <= (Block + BlockSize - 1 ) / PageSize; ++page) {
322
- ASSERT_LT (page, Pages.size ());
323
- ++Pages[page];
318
+ for (scudo::uptr Block = 0 ; Block < RoundedRegionSize; Block += BlockSize) {
319
+ for (scudo::uptr Page = Block / PageSize;
320
+ Page <= (Block + BlockSize - 1 ) / PageSize &&
321
+ Page < RoundedRegionSize / PageSize;
322
+ ++Page) {
323
+ ASSERT_LT (Page, Pages.size ());
324
+ ++Pages[Page];
324
325
}
325
326
}
326
327
@@ -410,17 +411,18 @@ template <class SizeClassMap> void testPageMapMarkRange() {
410
411
template <class SizeClassMap > void testReleasePartialRegion () {
411
412
typedef FreeBatch<SizeClassMap> Batch;
412
413
const scudo::uptr PageSize = scudo::getPageSizeCached ();
413
- const scudo::uptr ReleaseBase = PageSize;
414
- const scudo::uptr BasePageOffset = ReleaseBase / PageSize;
415
414
416
415
for (scudo::uptr I = 1 ; I <= SizeClassMap::LargestClassId; I++) {
417
416
// In the following, we want to ensure the region includes at least 2 pages
418
417
// and we will release all the pages except the first one. The handling of
419
418
// the last block is tricky, so we always test the case that includes the
420
419
// last block.
421
420
const scudo::uptr BlockSize = SizeClassMap::getSizeByClassId (I);
421
+ const scudo::uptr ReleaseBase = scudo::roundUp (BlockSize, PageSize);
422
+ const scudo::uptr BasePageOffset = ReleaseBase / PageSize;
422
423
const scudo::uptr RegionSize =
423
- scudo::roundUpSlow (scudo::roundUp (BlockSize, PageSize) * 2 , BlockSize) +
424
+ scudo::roundUpSlow (scudo::roundUp (BlockSize, PageSize) + ReleaseBase,
425
+ BlockSize) +
424
426
BlockSize;
425
427
const scudo::uptr RoundedRegionSize = scudo::roundUp (RegionSize, PageSize);
426
428
@@ -429,7 +431,7 @@ template <class SizeClassMap> void testReleasePartialRegion() {
429
431
430
432
// Skip the blocks in the first page and add the remaining.
431
433
std::vector<scudo::uptr> Pages (RoundedRegionSize / PageSize, 0 );
432
- for (scudo::uptr Block = scudo::roundUpSlow (PageSize , BlockSize);
434
+ for (scudo::uptr Block = scudo::roundUpSlow (ReleaseBase , BlockSize);
433
435
Block + BlockSize <= RoundedRegionSize; Block += BlockSize) {
434
436
for (scudo::uptr Page = Block / PageSize;
435
437
Page <= (Block + BlockSize - 1 ) / PageSize; ++Page) {
@@ -444,7 +446,7 @@ template <class SizeClassMap> void testReleasePartialRegion() {
444
446
++Pages.back ();
445
447
446
448
Batch *CurrentBatch = nullptr ;
447
- for (scudo::uptr Block = scudo::roundUpSlow (PageSize , BlockSize);
449
+ for (scudo::uptr Block = scudo::roundUpSlow (ReleaseBase , BlockSize);
448
450
Block < RegionSize; Block += BlockSize) {
449
451
if (CurrentBatch == nullptr ||
450
452
CurrentBatch->getCount () == Batch::MaxCount) {
@@ -459,7 +461,7 @@ template <class SizeClassMap> void testReleasePartialRegion() {
459
461
auto SkipRegion = [](UNUSED scudo::uptr RegionIndex) { return false ; };
460
462
ReleasedPagesRecorder Recorder (ReleaseBase);
461
463
releaseFreeMemoryToOS (Context, Recorder, SkipRegion);
462
- const scudo::uptr FirstBlock = scudo::roundUpSlow (PageSize , BlockSize);
464
+ const scudo::uptr FirstBlock = scudo::roundUpSlow (ReleaseBase , BlockSize);
463
465
464
466
for (scudo::uptr P = 0 ; P < RoundedRegionSize; P += PageSize) {
465
467
if (P < FirstBlock) {
@@ -563,6 +565,69 @@ TEST(ScudoReleaseTest, ReleasePartialRegion) {
563
565
testReleasePartialRegion<scudo::SvelteSizeClassMap>();
564
566
}
565
567
568
+ template <class SizeClassMap > void testReleaseRangeWithSingleBlock () {
569
+ const scudo::uptr PageSize = scudo::getPageSizeCached ();
570
+
571
+ // We want to test if a memory group only contains single block that will be
572
+ // handled properly. The case is like:
573
+ //
574
+ // From To
575
+ // +----------------------+
576
+ // +------------+------------+
577
+ // | | |
578
+ // +------------+------------+
579
+ // ^
580
+ // RegionSize
581
+ //
582
+ // Note that `From` will be page aligned.
583
+ //
584
+ // If the second from the last block is aligned at `From`, then we expect all
585
+ // the pages after `From` will be marked as can-be-released. Otherwise, the
586
+ // pages only touched by the last blocks will be marked as can-be-released.
587
+ for (scudo::uptr I = 1 ; I <= SizeClassMap::LargestClassId; I++) {
588
+ const scudo::uptr BlockSize = SizeClassMap::getSizeByClassId (I);
589
+ const scudo::uptr From = scudo::roundUp (BlockSize, PageSize);
590
+ const scudo::uptr To =
591
+ From % BlockSize == 0
592
+ ? From + BlockSize
593
+ : scudo::roundDownSlow (From + BlockSize, BlockSize) + BlockSize;
594
+ const scudo::uptr RoundedRegionSize = scudo::roundUp (To, PageSize);
595
+
596
+ std::vector<scudo::uptr> Pages (RoundedRegionSize / PageSize, 0 );
597
+ for (scudo::uptr Block = (To - BlockSize); Block < RoundedRegionSize;
598
+ Block += BlockSize) {
599
+ for (scudo::uptr Page = Block / PageSize;
600
+ Page <= (Block + BlockSize - 1 ) / PageSize &&
601
+ Page < RoundedRegionSize / PageSize;
602
+ ++Page) {
603
+ ASSERT_LT (Page, Pages.size ());
604
+ ++Pages[Page];
605
+ }
606
+ }
607
+
608
+ scudo::PageReleaseContext Context (BlockSize, /* NumberOfRegions=*/ 1U ,
609
+ /* ReleaseSize=*/ To,
610
+ /* ReleaseBase=*/ 0U );
611
+ Context.markRangeAsAllCounted (From, To, /* Base=*/ 0U , /* RegionIndex=*/ 0 ,
612
+ /* RegionSize=*/ To);
613
+
614
+ for (scudo::uptr Page = 0 ; Page < RoundedRegionSize; Page += PageSize) {
615
+ if (Context.PageMap .get (/* Region=*/ 0U , Page / PageSize) !=
616
+ Pages[Page / PageSize]) {
617
+ EXPECT_TRUE (
618
+ Context.PageMap .isAllCounted (/* Region=*/ 0U , Page / PageSize));
619
+ }
620
+ }
621
+ } // for each size class
622
+ }
623
+
624
+ TEST (ScudoReleaseTest, RangeReleaseRegionWithSingleBlock) {
625
+ testReleaseRangeWithSingleBlock<scudo::DefaultSizeClassMap>();
626
+ testReleaseRangeWithSingleBlock<scudo::AndroidSizeClassMap>();
627
+ testReleaseRangeWithSingleBlock<scudo::FuchsiaSizeClassMap>();
628
+ testReleaseRangeWithSingleBlock<scudo::SvelteSizeClassMap>();
629
+ }
630
+
566
631
TEST (ScudoReleaseTest, BufferPool) {
567
632
constexpr scudo::uptr StaticBufferCount = SCUDO_WORDSIZE - 1 ;
568
633
constexpr scudo::uptr StaticBufferSize = 512U ;
0 commit comments