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