Skip to content

Commit c111f69

Browse files
mralephCommit Queue
authored andcommitted
[vm] Fix freelist interaction with dual mapping
Freelist implementation was trying to mark pages executable (RX) which does not respect possibility that it is working with RW mapping which can't be directly marked as executable. It needed to use RO permission instead if dual mapping is enabled. This CL consolidates all code mentioning RX permission in one place: VirtualMemory::WriteProtectCode so that we avoid this mistake in the future. [email protected] TEST=tested by doing large reloads which cause more churn in code space Change-Id: If99692cac3ce3ff54b907e4c43d7f26bae7439ff Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/435860 Commit-Queue: Martin Kustermann <[email protected]> Auto-Submit: Slava Egorov <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent faf1baf commit c111f69

File tree

9 files changed

+30
-42
lines changed

9 files changed

+30
-42
lines changed

runtime/vm/code_patcher.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ WritableInstructionsScope::WritableInstructionsScope(uword address,
3737

3838
WritableInstructionsScope::~WritableInstructionsScope() {
3939
if (FLAG_write_protect_code) {
40-
VirtualMemory::Protect(reinterpret_cast<void*>(address_), size_,
41-
VirtualMemory::kReadExecute);
40+
VirtualMemory::WriteProtectCode(reinterpret_cast<void*>(address_), size_);
4241
}
4342
}
4443
#endif // defined(TARGET_ARCH_IA32)

runtime/vm/compiler/relocation_test.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,7 @@ struct RelocatorTestHelper {
263263
ASSERT(!VirtualMemory::ShouldDualMapExecutablePages());
264264
const uword address = UntaggedObject::ToAddr(instructions.ptr());
265265
const auto size = instructions.ptr()->untag()->HeapSize();
266-
VirtualMemory::Protect(reinterpret_cast<void*>(address), size,
267-
VirtualMemory::kReadExecute);
266+
VirtualMemory::WriteProtectCode(reinterpret_cast<void*>(address), size);
268267
}
269268
CPU::FlushICache(instructions.PayloadStart(), instructions.Size());
270269
}

runtime/vm/ffi_callback_metadata.cc

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,16 +187,12 @@ VirtualMemory* FfiCallbackMetadata::AllocateTrampolinePage() {
187187
memcpy(new_page->address(), stub_page_->address(), // NOLINT
188188
stub_page_->size());
189189

190+
VirtualMemory::WriteProtectCode(new_page->address(), aligned_size);
190191
if (VirtualMemory::ShouldDualMapExecutablePages()) {
191192
ASSERT(new_page->OffsetToExecutableAlias() != 0);
192-
VirtualMemory::Protect(new_page->address(), aligned_size,
193-
VirtualMemory::kReadOnly);
194193
VirtualMemory::Protect(
195194
reinterpret_cast<void*>(RXAreaStart(new_page) + RXMappingSize()),
196195
RWMappingSize(), VirtualMemory::kReadWrite);
197-
} else {
198-
VirtualMemory::Protect(new_page->address(), aligned_size,
199-
VirtualMemory::kReadExecute);
200196
}
201197
}
202198

runtime/vm/heap/freelist.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ uword FreeList::TryAllocateLocked(intptr_t size, bool is_protected) {
172172
}
173173
previous->set_next(current->next());
174174
if (target_is_protected) {
175-
VirtualMemory::Protect(reinterpret_cast<void*>(target_address),
176-
kWordSize, VirtualMemory::kReadExecute);
175+
VirtualMemory::WriteProtectCode(
176+
reinterpret_cast<void*>(target_address), kWordSize);
177177
}
178178
}
179179
SplitElementAfterAndEnqueue(current, size, is_protected);
@@ -266,12 +266,11 @@ void FreeList::SplitElementAfterAndEnqueue(FreeListElement* element,
266266
if (!VirtualMemory::InSamePage(
267267
remainder_address - 1,
268268
remainder_address + remainder_header_size - 1)) {
269-
VirtualMemory::Protect(
269+
VirtualMemory::WriteProtectCode(
270270
reinterpret_cast<void*>(
271271
Utils::RoundUp(remainder_address, VirtualMemory::PageSize())),
272272
remainder_address + remainder_header_size -
273-
Utils::RoundUp(remainder_address, VirtualMemory::PageSize()),
274-
VirtualMemory::kReadExecute);
273+
Utils::RoundUp(remainder_address, VirtualMemory::PageSize()));
275274
}
276275
}
277276
}

runtime/vm/heap/freelist_test.cc

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ namespace dart {
1414
static uword Allocate(FreeList* free_list, intptr_t size, bool is_protected) {
1515
uword result = free_list->TryAllocate(size, is_protected);
1616
if ((result != 0u) && is_protected) {
17-
VirtualMemory::Protect(reinterpret_cast<void*>(result), size,
18-
VirtualMemory::kReadExecute);
17+
VirtualMemory::WriteProtectCode(reinterpret_cast<void*>(result), size);
1918
}
2019
return result;
2120
}
@@ -30,8 +29,7 @@ static void Free(FreeList* free_list,
3029
}
3130
free_list->Free(address, size);
3231
if (is_protected) {
33-
VirtualMemory::Protect(reinterpret_cast<void*>(address), size,
34-
VirtualMemory::kReadExecute);
32+
VirtualMemory::WriteProtectCode(reinterpret_cast<void*>(address), size);
3533
}
3634
}
3735

@@ -47,7 +45,7 @@ static void TestFreeList(VirtualMemory* region,
4745

4846
if (is_protected) {
4947
// Write protect the whole region.
50-
region->Protect(VirtualMemory::kReadExecute);
48+
region->WriteProtectCode();
5149
}
5250

5351
// Allocate a small object. Expect it to be positioned as the first element.
@@ -122,7 +120,7 @@ TEST_CASE(FreeListProtectedTinyObjects) {
122120
free_list->Free(blob->start(), blob->size());
123121

124122
// Write protect the whole region.
125-
blob->Protect(VirtualMemory::kReadExecute);
123+
blob->WriteProtectCode();
126124

127125
// Allocate small objects.
128126
for (intptr_t i = 0; i < blob->size() / kObjectSize; i++) {
@@ -221,10 +219,9 @@ static void TestRegress38528(intptr_t header_overlap) {
221219
memcpy(other_code, ret, sizeof(ret)); // NOLINT
222220

223221
free_list->Free(blob->start(), alloc_size + remainder_size);
224-
blob->Protect(VirtualMemory::kReadExecute); // not writable
222+
blob->WriteProtectCode(); // not writable
225223
Allocate(free_list.get(), alloc_size, /*is_protected=*/true);
226-
VirtualMemory::Protect(blob->address(), alloc_size,
227-
VirtualMemory::kReadExecute);
224+
VirtualMemory::WriteProtectCode(blob->address(), alloc_size);
228225
reinterpret_cast<void (*)()>(other_code)();
229226
}
230227

runtime/vm/heap/page.cc

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -293,19 +293,13 @@ void Page::ResetProgressBar() {
293293

294294
void Page::WriteProtect(bool read_only) {
295295
ASSERT(!is_image());
296-
VirtualMemory::Protection prot;
297-
if (read_only) {
298-
// When dual mapping code pages we don't change protection on RX page, but
299-
// flip RW to R and back.
300-
if (is_executable() && !VirtualMemory::ShouldDualMapExecutablePages()) {
301-
prot = VirtualMemory::kReadExecute;
302-
} else {
303-
prot = VirtualMemory::kReadOnly;
304-
}
296+
if (is_executable() && read_only) {
297+
// Handle making code executable in a special way.
298+
memory_->WriteProtectCode();
305299
} else {
306-
prot = VirtualMemory::kReadWrite;
300+
memory_->Protect(read_only ? VirtualMemory::kReadOnly
301+
: VirtualMemory::kReadWrite);
307302
}
308-
memory_->Protect(prot);
309303
}
310304

311305
} // namespace dart

runtime/vm/object.cc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18746,11 +18746,8 @@ CodePtr Code::FinalizeCode(FlowGraphCompiler* compiler,
1874618746
// RX mapping never changes protection while RW mapping flips between
1874718747
// R and RW.
1874818748
uword address = UntaggedObject::ToAddr(instrs.ptr());
18749-
VirtualMemory::Protect(reinterpret_cast<void*>(address),
18750-
instrs.ptr()->untag()->HeapSize(),
18751-
VirtualMemory::ShouldDualMapExecutablePages()
18752-
? VirtualMemory::kReadOnly
18753-
: VirtualMemory::kReadExecute);
18749+
VirtualMemory::WriteProtectCode(reinterpret_cast<void*>(address),
18750+
instrs.ptr()->untag()->HeapSize());
1875418751
}
1875518752

1875618753
// Hook up Code and Instructions objects.

runtime/vm/virtual_memory.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@ class VirtualMemory {
8080
#endif
8181
}
8282

83+
// Write protect a chunk of machine code which is currently writable.
84+
DART_FORCE_INLINE static void WriteProtectCode(void* address, intptr_t size) {
85+
Protect(address, size,
86+
ShouldDualMapExecutablePages() ? kReadOnly : kReadExecute);
87+
}
88+
DART_FORCE_INLINE void WriteProtectCode() const {
89+
WriteProtectCode(address(), size());
90+
}
91+
8392
bool Contains(uword addr) const { return region_.Contains(addr); }
8493

8594
// Changes the protection of the virtual memory area.

runtime/vm/virtual_memory_posix.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -493,9 +493,7 @@ bool CheckIfRXWorks() {
493493
0xd65f03c0 // ret
494494
};
495495
memmove(mem->address(), kSquareFunctionCode, sizeof(kSquareFunctionCode));
496-
mem->Protect(VirtualMemory::ShouldDualMapExecutablePages()
497-
? VirtualMemory::kReadOnly
498-
: VirtualMemory::kReadExecute);
496+
VirtualMemory::WriteProtectCode(mem->address(), mem->size());
499497

500498
// Get executable entry point and check that write have succeeded.
501499
const uword entry_point = mem->start() + mem->OffsetToExecutableAlias();

0 commit comments

Comments
 (0)