|
24 | 24 | #include <set> |
25 | 25 | #include <stdlib.h> |
26 | 26 | #include <thread> |
| 27 | +#include <unordered_map> |
27 | 28 | #include <vector> |
28 | 29 |
|
29 | 30 | static constexpr scudo::Chunk::Origin Origin = scudo::Chunk::Origin::Malloc; |
@@ -150,14 +151,8 @@ void TestAllocator<Config>::operator delete(void *ptr) { |
150 | 151 | } |
151 | 152 |
|
152 | 153 | template <class TypeParam> struct ScudoCombinedTest : public Test { |
153 | | - ScudoCombinedTest() { |
154 | | - UseQuarantine = std::is_same<TypeParam, scudo::AndroidConfig>::value; |
155 | | - Allocator = std::make_unique<AllocatorT>(); |
156 | | - } |
157 | | - ~ScudoCombinedTest() { |
158 | | - Allocator->releaseToOS(scudo::ReleaseToOS::Force); |
159 | | - UseQuarantine = true; |
160 | | - } |
| 154 | + ScudoCombinedTest() { Allocator = std::make_unique<AllocatorT>(); } |
| 155 | + ~ScudoCombinedTest() { Allocator->releaseToOS(scudo::ReleaseToOS::Force); } |
161 | 156 |
|
162 | 157 | void RunTest(); |
163 | 158 |
|
@@ -525,30 +520,25 @@ SCUDO_TYPED_TEST(ScudoCombinedTest, IterateOverChunks) { |
525 | 520 | auto *Allocator = this->Allocator.get(); |
526 | 521 | // Allocates a bunch of chunks, then iterate over all the chunks, ensuring |
527 | 522 | // they are the ones we allocated. This requires the allocator to not have any |
528 | | - // other allocated chunk at this point (eg: won't work with the Quarantine). |
529 | | - // FIXME: Make it work with UseQuarantine and tagging enabled. Internals of |
530 | | - // iterateOverChunks reads header by tagged and non-tagger pointers so one of |
531 | | - // them will fail. |
532 | | - if (!UseQuarantine) { |
533 | | - std::vector<void *> V; |
534 | | - for (scudo::uptr I = 0; I < 64U; I++) |
535 | | - V.push_back(Allocator->allocate( |
536 | | - static_cast<scudo::uptr>(std::rand()) % |
537 | | - (TypeParam::Primary::SizeClassMap::MaxSize / 2U), |
538 | | - Origin)); |
539 | | - Allocator->disable(); |
540 | | - Allocator->iterateOverChunks( |
541 | | - 0U, static_cast<scudo::uptr>(SCUDO_MMAP_RANGE_SIZE - 1), |
542 | | - [](uintptr_t Base, UNUSED size_t Size, void *Arg) { |
543 | | - std::vector<void *> *V = reinterpret_cast<std::vector<void *> *>(Arg); |
544 | | - void *P = reinterpret_cast<void *>(Base); |
545 | | - EXPECT_NE(std::find(V->begin(), V->end(), P), V->end()); |
546 | | - }, |
547 | | - reinterpret_cast<void *>(&V)); |
548 | | - Allocator->enable(); |
549 | | - for (auto P : V) |
550 | | - Allocator->deallocate(P, Origin); |
551 | | - } |
| 523 | + // other allocated chunk at this point. |
| 524 | + std::vector<void *> V; |
| 525 | + for (scudo::uptr I = 0; I < 64U; I++) |
| 526 | + V.push_back(Allocator->allocate( |
| 527 | + static_cast<scudo::uptr>(std::rand()) % |
| 528 | + (TypeParam::Primary::SizeClassMap::MaxSize / 2U), |
| 529 | + Origin)); |
| 530 | + Allocator->disable(); |
| 531 | + Allocator->iterateOverChunks( |
| 532 | + 0U, static_cast<scudo::uptr>(SCUDO_MMAP_RANGE_SIZE - 1), |
| 533 | + [](uintptr_t Base, UNUSED size_t Size, void *Arg) { |
| 534 | + std::vector<void *> *V = reinterpret_cast<std::vector<void *> *>(Arg); |
| 535 | + void *P = reinterpret_cast<void *>(Base); |
| 536 | + EXPECT_NE(std::find(V->begin(), V->end(), P), V->end()); |
| 537 | + }, |
| 538 | + reinterpret_cast<void *>(&V)); |
| 539 | + Allocator->enable(); |
| 540 | + for (auto P : V) |
| 541 | + Allocator->deallocate(P, Origin); |
552 | 542 | } |
553 | 543 |
|
554 | 544 | SCUDO_TYPED_TEST(ScudoCombinedDeathTest, UseAfterFree) { |
@@ -1161,3 +1151,34 @@ TEST(ScudoCombinedTest, QuarantineDisabled) { |
1161 | 1151 | // No quarantine stats should not be present. |
1162 | 1152 | EXPECT_EQ(Stats.find("Stats: Quarantine"), std::string::npos); |
1163 | 1153 | } |
| 1154 | + |
| 1155 | +// Verify that no special quarantine blocks appear in iterateOverChunks. |
| 1156 | +TEST(ScudoCombinedTest, QuarantineIterateOverChunks) { |
| 1157 | + using AllocatorT = scudo::Allocator<TestQuarantineConfig>; |
| 1158 | + auto Allocator = std::unique_ptr<AllocatorT>(new AllocatorT()); |
| 1159 | + |
| 1160 | + // Do a bunch of allocations and deallocations. At the end there should |
| 1161 | + // be no special quarantine blocks in our callbacks, and no blocks at all. |
| 1162 | + std::vector<scudo::uptr> Sizes = {128, 128, 256, 256}; |
| 1163 | + for (auto const Size : Sizes) { |
| 1164 | + void *Ptr = Allocator->allocate(Size, Origin); |
| 1165 | + EXPECT_NE(Ptr, nullptr); |
| 1166 | + Allocator->deallocate(Ptr, Origin); |
| 1167 | + } |
| 1168 | + std::unordered_map<uintptr_t, size_t> Pointers; |
| 1169 | + Allocator->disable(); |
| 1170 | + Allocator->iterateOverChunks( |
| 1171 | + 0, static_cast<scudo::uptr>(SCUDO_MMAP_RANGE_SIZE - 1), |
| 1172 | + [](uintptr_t Base, size_t Size, void *Arg) { |
| 1173 | + std::unordered_map<uintptr_t, size_t> *Pointers = |
| 1174 | + reinterpret_cast<std::unordered_map<uintptr_t, size_t> *>(Arg); |
| 1175 | + (*Pointers)[Base] = Size; |
| 1176 | + }, |
| 1177 | + reinterpret_cast<void *>(&Pointers)); |
| 1178 | + Allocator->enable(); |
| 1179 | + |
| 1180 | + for (const auto [Base, Size] : Pointers) { |
| 1181 | + EXPECT_TRUE(false) << "Unexpected pointer found in iterateOverChunks " |
| 1182 | + << std::hex << Base << " Size " << std::dec << Size; |
| 1183 | + } |
| 1184 | +} |
0 commit comments