
----- Original Message ----- From: Armin Rigo <arigo@tunes.org> Sent: Monday, June 11, 2012 4:59 AM
On Sun, Jun 10, 2012 at 11:12 AM, Amaury Forgeot d'Arc <amauryfa@gmail.com> wrote: I think memory allocated for JIT must be marked with PROT_EXEC (it contains machine code), so malloc() is not an option. Exactly. On Linux it would work, because you can use mprotect() to make even malloc()ed memory executable, but I doubt this non-Posix extension works on cygwin. What might work instead would be using the Windows API instead of the POSIX one. In pypy/rlib/rmmap.py, look for "def alloc" and "def free": there are the two versions.
Cygwin implements the POSIX API on top of the Windows API, and some things are tricky to implement, and memory handling and permissions tend to be part of those. To see if it may just work, I modified rmmap.pyto use malloc() and free(), and indeed pypy seems to work just fine. Following up on this email I also added an mprotect() call, which does exist under Cygwin. However, POSIX says that the behavior of mprotect() is unspecified if it is applied to a region of memory that was not obtained via mmap(2), and indeed this fails. Here's the patch that works, using malloc() and free(), and not using mprotect(). *** pypy/pypy/rlib/rmmap.pyMon Jun 11 10:18:55 2012 --- pypy/pypy/rlib/rmmap.pyMon Jun 11 10:16:12 2012 *************** *** 14,19 **** --- 14,20 ---- _MS_WINDOWS = os.name == "nt" _LINUX = "linux" in sys.platform _64BIT = "64bit" in platform.architecture()[0] + _CYGWIN = "cygwin" == sys.platform class RValueError(Exception): def __init__(self, message): *************** *** 115,120 **** --- 116,126 ---- PTR = rffi.CCHARP + if _CYGWIN: + c_malloc, _ = external('malloc', [size_t], PTR) + #c_mprotect, _ = external('mprotect', [PTR, size_t, rffi.INT], rffi.INT) + c_free, _ = external('free', [PTR], lltype.Void) + c_memmove, _ = external('memmove', [PTR, PTR, size_t], lltype.Void) if _POSIX: *************** *** 692,714 **** so the memory has the executable bit set and gets allocated internally in case of a sandboxed process. """ ! flags = MAP_PRIVATE | MAP_ANONYMOUS ! prot = PROT_EXEC | PROT_READ | PROT_WRITE ! hintp = rffi.cast(PTR, hint.pos) ! res = c_mmap_safe(hintp, map_size, prot, flags, -1, 0) ! if res == rffi.cast(PTR, -1): ! # some systems (some versions of OS/X?) complain if they ! # are passed a non-zero address. Try again. ! hintp = rffi.cast(PTR, 0) ! res = c_mmap_safe(hintp, map_size, prot, flags, -1, 0) ! if res == rffi.cast(PTR, -1): raise MemoryError else: ! hint.pos += map_size return res alloc._annenforceargs_ = (int,) ! free = c_munmap_safe elif _MS_WINDOWS: def mmap(fileno, length, tagname="", access=_ACCESS_DEFAULT, offset=0): --- 698,739 ---- so the memory has the executable bit set and gets allocated internally in case of a sandboxed process. """ ! if _CYGWIN: ! # XXX: JIT memory should be using mmap MAP_PRIVATE with ! # PROT_EXEC but Cygwin's fork() fails ! res = c_malloc(map_size) ! if res == rffi.cast(PTR, 0): raise MemoryError + # XXX POSIX says that the behavior of mprotect() is unspecified + # if it is applied to a region of memory that was not obtained + # via mmap(2), and indeed it does not work here. + # prot = PROT_EXEC | PROT_READ | PROT_WRITE + # res2 = c_mprotect(res, map_size, prot) + # if res2 == -1: + # errno = rposix.get_errno() + # raise OSError(errno, os.strerror(errno)) else: ! flags = MAP_PRIVATE | MAP_ANONYMOUS ! prot = PROT_EXEC | PROT_READ | PROT_WRITE ! hintp = rffi.cast(PTR, hint.pos) ! res = c_mmap_safe(hintp, map_size, prot, flags, -1, 0) ! if res == rffi.cast(PTR, -1): ! # some systems (some versions of OS/X?) complain if they ! # are passed a non-zero address. Try again. ! hintp = rffi.cast(PTR, 0) ! res = c_mmap_safe(hintp, map_size, prot, flags, -1, 0) ! if res == rffi.cast(PTR, -1): ! raise MemoryError ! else: ! hint.pos += map_size return res + alloc._annenforceargs_ = (int,) ! if _CYGWIN: ! free = c_free ! else: ! free = c_munmap_safe elif _MS_WINDOWS: def mmap(fileno, length, tagname="", access=_ACCESS_DEFAULT, offset=0):