|
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