Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(283)

Unified Diff: runtime/vm/freelist_test.cc

Issue 150563007: Fix crash bug in free list when allocating write protected memory. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: addressed commment Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/freelist.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/freelist_test.cc
diff --git a/runtime/vm/freelist_test.cc b/runtime/vm/freelist_test.cc
index fc506d76d1c2220637e965b49d7421f8151fb5ab..b7cfbca18cfb4a0f91cf53671dd316d267d58eb7 100644
--- a/runtime/vm/freelist_test.cc
+++ b/runtime/vm/freelist_test.cc
@@ -8,47 +8,189 @@
namespace dart {
-TEST_CASE(FreeList) {
- FreeList* free_list = new FreeList();
- intptr_t kBlobSize = 1 * MB;
- intptr_t kSmallObjectSize = 4 * kWordSize;
- intptr_t kMediumObjectSize = 16 * kWordSize;
- intptr_t kLargeObjectSize = 8 * KB;
- uword blob = reinterpret_cast<uword>(malloc(kBlobSize));
+static uword Allocate(FreeList* free_list, intptr_t size, bool is_protected) {
+ uword result = free_list->TryAllocate(size, is_protected);
+ if (result && is_protected) {
+ bool status = VirtualMemory::Protect(reinterpret_cast<void*>(result),
+ size,
+ VirtualMemory::kReadExecute);
+ ASSERT(status);
+ }
+ return result;
+}
+
+
+static void Free(FreeList* free_list,
+ uword address,
+ intptr_t size,
+ bool is_protected) {
+ if (is_protected) {
+ bool status = VirtualMemory::Protect(reinterpret_cast<void*>(address),
+ size,
+ VirtualMemory::kReadWrite);
+ ASSERT(status);
+ }
+ free_list->Free(address, size);
+ if (is_protected) {
+ bool status = VirtualMemory::Protect(reinterpret_cast<void*>(address),
+ size,
+ VirtualMemory::kReadExecute);
+ ASSERT(status);
+ }
+}
+
+
+static void TestFreeList(VirtualMemory* region,
+ FreeList* free_list,
+ bool is_protected) {
+ const intptr_t kSmallObjectSize = 4 * kWordSize;
+ const intptr_t kMediumObjectSize = 16 * kWordSize;
+ const intptr_t kLargeObjectSize = 8 * KB;
+ uword blob = region->start();
// Enqueue the large blob as one free block.
- free_list->Free(blob, kBlobSize);
+ free_list->Free(blob, region->size());
+
+ if (is_protected) {
+ // Write protect the whole region.
+ region->Protect(VirtualMemory::kReadExecute);
+ }
+
// Allocate a small object. Expect it to be positioned as the first element.
- uword small_object = free_list->TryAllocate(kSmallObjectSize, false);
+ uword small_object = Allocate(free_list, kSmallObjectSize, is_protected);
EXPECT_EQ(blob, small_object);
// Freeing and allocating should give us the same memory back.
- free_list->Free(small_object, kSmallObjectSize);
- small_object = free_list->TryAllocate(kSmallObjectSize, false);
+ Free(free_list, small_object, kSmallObjectSize, is_protected);
+ small_object = Allocate(free_list, kSmallObjectSize, is_protected);
EXPECT_EQ(blob, small_object);
// Splitting the remainder further with small and medium objects.
- uword small_object2 = free_list->TryAllocate(kSmallObjectSize, false);
+ uword small_object2 = Allocate(free_list, kSmallObjectSize, is_protected);
EXPECT_EQ(blob + kSmallObjectSize, small_object2);
- uword med_object = free_list->TryAllocate(kMediumObjectSize, false);
+ uword med_object = Allocate(free_list, kMediumObjectSize, is_protected);
EXPECT_EQ(small_object2 + kSmallObjectSize, med_object);
// Allocate a large object.
- uword large_object = free_list->TryAllocate(kLargeObjectSize, false);
+ uword large_object = Allocate(free_list, kLargeObjectSize, is_protected);
EXPECT_EQ(med_object + kMediumObjectSize, large_object);
// Make sure that small objects can still split the remainder.
- uword small_object3 = free_list->TryAllocate(kSmallObjectSize, false);
+ uword small_object3 = Allocate(free_list, kSmallObjectSize, is_protected);
EXPECT_EQ(large_object + kLargeObjectSize, small_object3);
// Split the large object.
- free_list->Free(large_object, kLargeObjectSize);
- uword small_object4 = free_list->TryAllocate(kSmallObjectSize, false);
+ Free(free_list, large_object, kLargeObjectSize, is_protected);
+ uword small_object4 = Allocate(free_list, kSmallObjectSize, is_protected);
EXPECT_EQ(large_object, small_object4);
// Get the full remainder of the large object.
large_object =
- free_list->TryAllocate(kLargeObjectSize - kSmallObjectSize, false);
+ Allocate(free_list, kLargeObjectSize - kSmallObjectSize, is_protected);
EXPECT_EQ(small_object4 + kSmallObjectSize, large_object);
// Get another large object from the large unallocated remainder.
- uword large_object2 = free_list->TryAllocate(kLargeObjectSize, false);
+ uword large_object2 = Allocate(free_list, kLargeObjectSize, is_protected);
EXPECT_EQ(small_object3 + kSmallObjectSize, large_object2);
+}
+
+TEST_CASE(FreeList) {
+ FreeList* free_list = new FreeList();
+ const intptr_t kBlobSize = 1 * MB;
+ VirtualMemory* region = VirtualMemory::Reserve(kBlobSize);
+ region->Commit(/* is_executable */ false);
+
+ TestFreeList(region, free_list, false);
+
+ // Delete the memory associated with the test.
+ delete region;
+ delete free_list;
+}
+
+
+TEST_CASE(FreeListProtected) {
+ FreeList* free_list = new FreeList();
+ const intptr_t kBlobSize = 1 * MB;
+ VirtualMemory* region = VirtualMemory::Reserve(kBlobSize);
+ region->Commit(/* is_executable */ false);
+
+ TestFreeList(region, free_list, true);
+
+ // Delete the memory associated with the test.
+ delete region;
+ delete free_list;
+}
+
+
+TEST_CASE(FreeListProtectedTinyObjects) {
+ FreeList* free_list = new FreeList();
+ const intptr_t kBlobSize = 1 * MB;
+ const intptr_t kObjectSize = 2 * kWordSize;
+ uword* objects = new uword[kBlobSize / kObjectSize];
+
+ VirtualMemory* blob = VirtualMemory::ReserveAligned(kBlobSize, 4096);
+ blob->Commit(/* is_executable = */ false);
+ blob->Protect(VirtualMemory::kReadWrite);
+
+ // Enqueue the large blob as one free block.
+ free_list->Free(blob->start(), blob->size());
+
+ // Write protect the whole region.
+ blob->Protect(VirtualMemory::kReadExecute);
+
+ // Allocate small objects.
+ for (intptr_t i = 0; i < blob->size() / kObjectSize; i++) {
+ objects[i] = Allocate(free_list,
+ kObjectSize,
+ true); // is_protected
+ }
+
+ // All space is occupied. Expect failed allocation.
+ ASSERT(Allocate(free_list, kObjectSize, true) == 0);
+
+ // Free all objects again. Make the whole region writable for this.
+ blob->Protect(VirtualMemory::kReadWrite);
+ for (intptr_t i = 0; i < blob->size() / kObjectSize; i++) {
+ free_list->Free(objects[i], kObjectSize);
+ }
+
+ // Delete the memory associated with the test.
+ delete blob;
+ delete free_list;
+ delete[] objects;
+}
+
+
+TEST_CASE(FreeListProtectedVariableSizeObjects) {
+ FreeList* free_list = new FreeList();
+ const intptr_t kBlobSize = 8 * KB;
+ const intptr_t kMinSize = 2 * kWordSize;
+ uword* objects = new uword[kBlobSize / kMinSize];
+ for (intptr_t i = 0; i < kBlobSize / kMinSize; ++i) {
+ objects[i] = NULL;
+ }
+
+ VirtualMemory* blob = VirtualMemory::ReserveAligned(kBlobSize, 4096);
+ blob->Commit(/* is_executable = */ false);
+ blob->Protect(VirtualMemory::kReadWrite);
+
+ // Enqueue the large blob as one free block.
+ free_list->Free(blob->start(), blob->size());
+
+ // Write protect the whole region.
+ blob->Protect(VirtualMemory::kReadExecute);
+
+ // Allocate and free objects so that free list has > 1 elements.
+ uword e0 = Allocate(free_list, 1 * KB, true);
+ ASSERT(e0);
+ uword e1 = Allocate(free_list, 3 * KB, true);
+ ASSERT(e1);
+ uword e2 = Allocate(free_list, 2 * KB, true);
+ ASSERT(e2);
+ uword e3 = Allocate(free_list, 2 * KB, true);
+ ASSERT(e3);
+
+ Free(free_list, e1, 3 * KB, true);
+ Free(free_list, e2, 2 * KB, true);
+ e0 = Allocate(free_list, 3 * KB - 2 * kWordSize, true);
+ ASSERT(e0);
+
// Delete the memory associated with the test.
- free(reinterpret_cast<void*>(blob));
+ delete blob;
delete free_list;
+ delete[] objects;
}
} // namespace dart
« no previous file with comments | « runtime/vm/freelist.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698