ports/lang/pypy/patches/patch-rpython_rlib_rmmap_py

106 lines
4.3 KiB
Text

Make the CPython bootstrap W^X compatible.
Index: rpython/rlib/rmmap.py
--- rpython/rlib/rmmap.py.orig
+++ rpython/rlib/rmmap.py
@@ -166,6 +166,9 @@ if _POSIX:
_, c_madvise_safe = external('madvise', [PTR, size_t, rffi.INT],
rffi.INT, _nowrapper=True)
+ c_mprotect, _ = external('mprotect',
+ [PTR, size_t, rffi.INT], rffi.INT)
+
# this one is always safe
_pagesize = rffi_platform.getintegerfunctionresult('getpagesize',
includes=includes)
@@ -717,6 +720,25 @@ if _POSIX:
prot = NonConstant(prot)
return c_mmap_safe(hintp, map_size, prot, flags, -1, 0)
+ def alloc_hinted_noexec(hintp, map_size):
+ """Same as alloc_hinted, but allocates pages non-executable.
+ Duplicated because of constancy constraints on prot."""
+
+ flags = MAP_PRIVATE | MAP_ANONYMOUS
+ prot = PROT_READ | PROT_WRITE
+
+ if we_are_translated():
+ flags = NonConstant(flags)
+ prot = NonConstant(prot)
+ return c_mmap_safe(hintp, map_size, prot, flags, -1, 0)
+
+ def set_pages_executable(addr, size):
+ from rpython.rlib import debug
+
+ rv = c_mprotect(addr, size, PROT_EXEC)
+ if rv < 0:
+ debug.fatalerror_notb("set_pages_executable failed")
+
def clear_large_memory_chunk_aligned(addr, map_size):
addr = rffi.cast(PTR, addr)
flags = MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
@@ -732,10 +754,44 @@ if _POSIX:
pos = -0x4fff0000 # for reproducible results
hint = Hint()
+ def alloc_noexec(map_size):
+ """The same as `alloc`, but doesn't set the executable flag.
+ Duplicated because of constancy constraints on prot."""
+ from errno import ENOMEM
+ from rpython.rlib import debug
+
+ if _CYGWIN:
+ # XXX: JIT memory should be using mmap MAP_PRIVATE with
+ # PROT_EXEC but Cygwin's fork() fails. mprotect()
+ # cannot be used, but seems to be unnecessary there.
+ res = c_malloc_safe(map_size)
+ if res == rffi.cast(PTR, 0):
+ raise MemoryError
+ return res
+ res = alloc_hinted_noexec(rffi.cast(PTR, hint.pos), map_size)
+ if res == rffi.cast(PTR, -1):
+ # some systems (some versions of OS/X?) complain if they
+ # are passed a non-zero address. Try again.
+ res = alloc_hinted_noexec(rffi.cast(PTR, 0), map_size)
+ if res == rffi.cast(PTR, -1):
+ # ENOMEM simply raises MemoryError, but other errors are fatal
+ if rposix.get_saved_errno() != ENOMEM:
+ debug.fatalerror_notb(
+ "Got an unexpected error trying to allocate some "
+ "memory for the JIT (tried to do mmap() with "
+ "PROT_EXEC|PROT_READ|PROT_WRITE). This can be caused "
+ "by a system policy like PAX. You need to find how "
+ "to work around the policy on your system.")
+ raise MemoryError
+ else:
+ hint.pos += map_size
+ return res
+ alloc_noexec._annenforceargs_ = (int,)
+
def alloc(map_size):
"""Allocate memory. This is intended to be used by the JIT,
- so the memory has the executable bit set and gets allocated
- internally in case of a sandboxed process.
+ so the memory has the executable bit set.
+ and gets allocated internally in case of a sandboxed process.
"""
from errno import ENOMEM
from rpython.rlib import debug
@@ -936,6 +992,17 @@ elif _MS_WINDOWS:
pos = -0x4fff0000 # for reproducible results
hint = Hint()
# XXX this has no effect on windows
+ def alloc_noexec(map_size):
+ """Allocate memory. This is intended to be used by the JIT,
+ so the memory has the executable bit set.
+ XXX implement me: it should get allocated internally in
+ case of a sandboxed process
+
+ XXX no_exec ignored on windows
+ """
+ return alloc(map_size)
+ alloc_noexec._annenforceargs_ = (int,)
+
def alloc(map_size):
"""Allocate memory. This is intended to be used by the JIT,