Skip to content

Commit 7693da7

Browse files
mkustermanncommit-bot@chromium.org
authored andcommitted
[vm] When dual mapping is enabled map the executable part as RX immediately
Currently the initial mapping for the executable mapping is read-only. Once the first instruction object was allocated into an OS page we would map that page as RX. Any further allocations of instructions objects into the same page would just end up mapping it to RX again (even though it is already that way). To avoid those additional protection calls we can map the executable mapping RX from the beginning (it will be filled with zeros after allocation). Issue #37739 Issue #36097 Change-Id: Ib83f0be8ea8dacc86646c0a3c0335f4886516caa Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112244 Commit-Queue: Martin Kustermann <[email protected]> Reviewed-by: Régis Crelier <[email protected]>
1 parent 559f7cd commit 7693da7

File tree

3 files changed

+28
-8
lines changed

3 files changed

+28
-8
lines changed

runtime/vm/object.cc

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ DEFINE_FLAG(bool,
8080
false,
8181
"Remove script timestamps to allow for deterministic testing.");
8282

83+
DECLARE_FLAG(bool, dual_map_code);
8384
DECLARE_FLAG(bool, intrinsify);
8485
DECLARE_FLAG(bool, show_invisible_frames);
8586
DECLARE_FLAG(bool, trace_deoptimization);
@@ -14964,15 +14965,24 @@ RawCode* Code::FinalizeCode(FlowGraphCompiler* compiler,
1496414965
// Check if a dual mapping exists.
1496514966
instrs = Instructions::RawCast(HeapPage::ToExecutable(instrs.raw()));
1496614967
uword exec_address = RawObject::ToAddr(instrs.raw());
14967-
if (exec_address != address) {
14968+
const bool use_dual_mapping = exec_address != address;
14969+
ASSERT(use_dual_mapping == FLAG_dual_map_code);
14970+
14971+
// When dual mapping is enabled the executable mapping is RX from the
14972+
// point of allocation and never changes protection.
14973+
// Yet the writable mapping is still turned back from RW to R.
14974+
if (use_dual_mapping) {
1496814975
VirtualMemory::Protect(reinterpret_cast<void*>(address),
1496914976
instrs.raw()->HeapSize(),
1497014977
VirtualMemory::kReadOnly);
1497114978
address = exec_address;
14979+
} else {
14980+
// If dual mapping is disabled and we write protect then we have to
14981+
// change the single mapping from RW -> RX.
14982+
VirtualMemory::Protect(reinterpret_cast<void*>(address),
14983+
instrs.raw()->HeapSize(),
14984+
VirtualMemory::kReadExecute);
1497214985
}
14973-
VirtualMemory::Protect(reinterpret_cast<void*>(address),
14974-
instrs.raw()->HeapSize(),
14975-
VirtualMemory::kReadExecute);
1497614986
}
1497714987

1497814988
// Hook up Code and Instructions objects.

runtime/vm/virtual_memory_fuchsia.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
6969
// is_executable = true) is allocated as non-executable and later
7070
// changed to executable via VirtualMemory::Protect, which requires
7171
// ZX_RIGHT_EXECUTE on the underlying VMO.
72+
//
73+
// If FLAG_dual_map_code is active, the executable mapping will be mapped RX
74+
// immediately and never changes protection until it is eventually unmapped.
75+
//
7276
// In addition, dual mapping of the same underlying code memory is provided.
7377
const bool dual_mapping =
7478
is_executable && FLAG_write_protect_code && FLAG_dual_map_code;
@@ -122,8 +126,10 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
122126
VirtualMemory* result;
123127

124128
if (dual_mapping) {
125-
// ZX_VM_PERM_EXECUTE is added later via VirtualMemory::Protect.
126-
const zx_vm_option_t alias_options = ZX_VM_PERM_READ | align_flag;
129+
// The mapping will be RX and stays that way until it will eventually be
130+
// unmapped.
131+
const zx_vm_option_t alias_options =
132+
ZX_VM_PERM_READ | ZX_VM_PERM_EXECUTE | align_flag;
127133
status = zx_vmar_map(vmar, alias_options, 0, vmo, 0u, size, &base);
128134
LOG_INFO("zx_vmar_map(%u, 0x%lx, 0x%lx)\n", alias_options, base, size);
129135
if (status != ZX_OK) {

runtime/vm/virtual_memory_posix.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
164164
// When FLAG_write_protect_code is active, code memory (indicated by
165165
// is_executable = true) is allocated as non-executable and later
166166
// changed to executable via VirtualMemory::Protect.
167+
//
168+
// If FLAG_dual_map_code is active, the executable mapping will be mapped RX
169+
// immediately and never changes protection until it is eventually unmapped.
167170
ASSERT(Utils::IsAligned(size, page_size_));
168171
ASSERT(Utils::IsPowerOfTwo(alignment));
169172
ASSERT(Utils::IsAligned(alignment, page_size_));
@@ -188,9 +191,10 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
188191
close(fd);
189192
return NULL;
190193
}
194+
// The mapping will be RX and stays that way until it will eventually be
195+
// unmapped.
191196
MemoryRegion region(region_ptr, size);
192-
// PROT_EXEC is added later via VirtualMemory::Protect.
193-
const int alias_prot = PROT_READ;
197+
const int alias_prot = PROT_READ | PROT_EXEC;
194198
void* alias_ptr =
195199
MapAligned(fd, alias_prot, size, alignment, allocated_size);
196200
close(fd);

0 commit comments

Comments
 (0)