-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathvirtual_memory_test.cc
139 lines (119 loc) · 4.48 KB
/
virtual_memory_test.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/virtual_memory.h"
#include "platform/assert.h"
#include "vm/heap/heap.h"
#include "vm/unit_test.h"
#include "vm/virtual_memory_compressed.h"
namespace dart {
bool IsZero(char* begin, char* end) {
for (char* current = begin; current < end; ++current) {
if (*current != 0) {
return false;
}
}
return true;
}
VM_UNIT_TEST_CASE(AllocateVirtualMemory) {
const intptr_t kVirtualMemoryBlockSize = 64 * KB;
VirtualMemory* vm =
VirtualMemory::Allocate(kVirtualMemoryBlockSize, false, false, "test");
EXPECT(vm != nullptr);
EXPECT(vm->address() != nullptr);
EXPECT_EQ(vm->start(), reinterpret_cast<uword>(vm->address()));
EXPECT_EQ(kVirtualMemoryBlockSize, vm->size());
EXPECT_EQ(vm->start() + kVirtualMemoryBlockSize, vm->end());
EXPECT(vm->Contains(vm->start()));
EXPECT(vm->Contains(vm->start() + 1));
EXPECT(vm->Contains(vm->start() + kVirtualMemoryBlockSize - 1));
EXPECT(vm->Contains(vm->start() + (kVirtualMemoryBlockSize / 2)));
EXPECT(!vm->Contains(vm->start() - 1));
EXPECT(!vm->Contains(vm->end()));
EXPECT(!vm->Contains(vm->end() + 1));
EXPECT(!vm->Contains(0));
EXPECT(!vm->Contains(static_cast<uword>(-1)));
char* buf = reinterpret_cast<char*>(vm->address());
EXPECT(IsZero(buf, buf + vm->size()));
buf[0] = 'a';
buf[1] = 'c';
buf[2] = '/';
buf[3] = 'd';
buf[4] = 'c';
buf[5] = 0;
EXPECT_STREQ("ac/dc", buf);
delete vm;
}
VM_UNIT_TEST_CASE(AllocateAlignedVirtualMemory) {
intptr_t kHeapPageSize = kPageSize;
intptr_t kVirtualPageSize = 4096;
intptr_t kIterations = kHeapPageSize / kVirtualPageSize;
for (intptr_t i = 0; i < kIterations; i++) {
VirtualMemory* vm = VirtualMemory::AllocateAligned(
kHeapPageSize, kHeapPageSize, false, false, "test");
EXPECT(Utils::IsAligned(vm->start(), kHeapPageSize));
EXPECT_EQ(kHeapPageSize, vm->size());
delete vm;
}
}
VM_UNIT_TEST_CASE(FreeVirtualMemory) {
// Reservations should always be handed back to OS upon destruction.
const intptr_t kVirtualMemoryBlockSize = 10 * MB;
const intptr_t kIterations = 900; // Enough to exhaust 32-bit address space.
for (intptr_t i = 0; i < kIterations; ++i) {
VirtualMemory* vm =
VirtualMemory::Allocate(kVirtualMemoryBlockSize, false, false, "test");
delete vm;
}
// Check that truncation does not introduce leaks.
for (intptr_t i = 0; i < kIterations; ++i) {
VirtualMemory* vm =
VirtualMemory::Allocate(kVirtualMemoryBlockSize, false, false, "test");
vm->Truncate(kVirtualMemoryBlockSize / 2);
delete vm;
}
for (intptr_t i = 0; i < kIterations; ++i) {
VirtualMemory* vm =
VirtualMemory::Allocate(kVirtualMemoryBlockSize, true, false, "test");
vm->Truncate(0);
delete vm;
}
}
#if !defined(DART_TARGET_OS_FUCHSIA)
// TODO(https://dartbug.com/52579): Reenable on Fuchsia.
static int testFunction(int x) {
return x * 2;
}
NO_SANITIZE_UNDEFINED("function") // See https://dartbug.com/52440
VM_UNIT_TEST_CASE(DuplicateRXVirtualMemory) {
const uword page_size = VirtualMemory::PageSize();
const uword pointer = reinterpret_cast<uword>(&testFunction);
const uword page_start = Utils::RoundDown(pointer, page_size);
const uword offset = pointer - page_start;
// Grab 2 * page_size, in case testFunction happens to land near the end of
// the page.
VirtualMemory* vm = VirtualMemory::ForImagePage(
reinterpret_cast<void*>(page_start), 2 * page_size);
EXPECT_NE(nullptr, vm);
#if defined(DART_HOST_OS_MACOS) && !defined(DART_PRECOMPILED_RUNTIME)
// If we are not going to use vm_remap then we need to pass
// is_executable=true so that pages get allocated with MAP_JIT flag if
// necessary. Otherwise OS will kill us with a codesigning violation if
// hardened runtime is enabled.
const bool is_executable = true;
#else
const bool is_executable = false;
#endif
VirtualMemory* vm2 = VirtualMemory::AllocateAligned(
vm->size(), kPageSize, is_executable,
/*is_compressed=*/false, "FfiCallbackMetadata::TrampolinePage");
bool ok = vm->DuplicateRX(vm2);
EXPECT_EQ(true, ok);
auto testFunction2 = reinterpret_cast<int (*)(int)>(vm2->start() + offset);
EXPECT_NE(&testFunction, testFunction2);
EXPECT_EQ(246, testFunction2(123));
delete vm;
delete vm2;
}
#endif // !defined(DART_TARGET_OS_FUCHSIA)
} // namespace dart