diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 131b5f54bbb..33216e7f6e2 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -70,6 +70,7 @@ DECLARE_FLAG(bool, trace_deoptimization); DECLARE_FLAG(bool, trace_deoptimization_verbose); DECLARE_FLAG(bool, verbose_stacktrace); DECLARE_FLAG(charp, coverage_dir); +DECLARE_FLAG(bool, write_protect_code); static const char* kGetterPrefix = "get:"; static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix); @@ -10228,7 +10229,9 @@ RawCode* Code::FinalizeCode(const char* name, bool status = VirtualMemory::Protect(reinterpret_cast(instrs.raw_ptr()), instrs.raw()->Size(), - VirtualMemory::kReadExecute); + FLAG_write_protect_code + ? VirtualMemory::kReadExecute + : VirtualMemory::kReadWriteExecute); ASSERT(status); } return code.raw(); diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc index 9353177cd8d..49b9444e7a1 100644 --- a/runtime/vm/object_test.cc +++ b/runtime/vm/object_test.cc @@ -17,6 +17,8 @@ namespace dart { +DECLARE_FLAG(bool, write_protect_code); + static RawLibrary* CreateDummyLibrary(const String& library_name) { return Library::New(library_name); } @@ -2486,6 +2488,11 @@ TEST_CASE(CodeImmutability) { #endif EXPECT_EQ(3, retval); EXPECT_EQ(instructions.raw(), Instructions::FromEntryPoint(entry_point)); + if (!FLAG_write_protect_code) { + // Since this test is expected to crash, crash if write protection of code + // is switched off. + OS::DebugBreak(); + } } diff --git a/runtime/vm/virtual_memory.h b/runtime/vm/virtual_memory.h index 58c841ea780..09eeb7e8a24 100644 --- a/runtime/vm/virtual_memory.h +++ b/runtime/vm/virtual_memory.h @@ -13,12 +13,12 @@ namespace dart { class VirtualMemory { public: - // Read-write-execute is not available because it is never used. enum Protection { kNoAccess, kReadOnly, kReadWrite, kReadExecute, + kReadWriteExecute }; // The reserved memory is unmapped on destruction. diff --git a/runtime/vm/virtual_memory_android.cc b/runtime/vm/virtual_memory_android.cc index af7adc389c7..d4d4a218725 100644 --- a/runtime/vm/virtual_memory_android.cc +++ b/runtime/vm/virtual_memory_android.cc @@ -94,6 +94,9 @@ bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) { case kReadExecute: prot = PROT_READ | PROT_EXEC; break; + case kReadWriteExecute: + prot = PROT_READ | PROT_WRITE | PROT_EXEC; + break; } return (mprotect(reinterpret_cast(page_address), end_address - page_address, diff --git a/runtime/vm/virtual_memory_linux.cc b/runtime/vm/virtual_memory_linux.cc index c71242e5124..35f55247a61 100644 --- a/runtime/vm/virtual_memory_linux.cc +++ b/runtime/vm/virtual_memory_linux.cc @@ -94,6 +94,9 @@ bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) { case kReadExecute: prot = PROT_READ | PROT_EXEC; break; + case kReadWriteExecute: + prot = PROT_READ | PROT_WRITE | PROT_EXEC; + break; } return (mprotect(reinterpret_cast(page_address), end_address - page_address, diff --git a/runtime/vm/virtual_memory_macos.cc b/runtime/vm/virtual_memory_macos.cc index 93c92926623..e74acab552a 100644 --- a/runtime/vm/virtual_memory_macos.cc +++ b/runtime/vm/virtual_memory_macos.cc @@ -94,6 +94,9 @@ bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) { case kReadExecute: prot = PROT_READ | PROT_EXEC; break; + case kReadWriteExecute: + prot = PROT_READ | PROT_WRITE | PROT_EXEC; + break; } return (mprotect(reinterpret_cast(page_address), end_address - page_address, diff --git a/runtime/vm/virtual_memory_win.cc b/runtime/vm/virtual_memory_win.cc index 144e19378ff..a9caf8f51f1 100644 --- a/runtime/vm/virtual_memory_win.cc +++ b/runtime/vm/virtual_memory_win.cc @@ -82,6 +82,9 @@ bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) { case kReadExecute: prot = PAGE_EXECUTE_READ; break; + case kReadWriteExecute: + prot = PAGE_EXECUTE_READWRITE; + break; } DWORD old_prot = 0; bool result = VirtualProtect(reinterpret_cast(page_address),