|
28 | 28 |
|
29 | 29 | /******************************************************************/ |
30 | 30 |
|
| 31 | +#if defined(MS_WIN32) && !defined(MS_WINDOWS_DESKTOP) |
| 32 | +/* UWP does not allow memory to be writable and executable at the same time: |
| 33 | + VirtualAllocFromApp() rejects PAGE_EXECUTE_READWRITE. Instead, each |
| 34 | + closure gets its own page, which is allocated as PAGE_READWRITE so that |
| 35 | + ffi_prep_closure_loc() can write the trampoline, and is then switched to |
| 36 | + PAGE_EXECUTE_READ by Py_ffi_closure_make_executable(). Using one page |
| 37 | + per closure ensures that changing the protection never affects another |
| 38 | + closure which may be executing concurrently. This requires the |
| 39 | + "codeGeneration" capability in the application manifest. */ |
| 40 | + |
| 41 | +void Py_ffi_closure_free(void *p) |
| 42 | +{ |
| 43 | + VirtualFree(p, 0, MEM_RELEASE); |
| 44 | +} |
| 45 | + |
| 46 | +void *Py_ffi_closure_alloc(size_t size, void** codeloc) |
| 47 | +{ |
| 48 | + void *p = VirtualAllocFromApp(NULL, size, MEM_COMMIT | MEM_RESERVE, |
| 49 | + PAGE_READWRITE); |
| 50 | + if (p == NULL) { |
| 51 | + return NULL; |
| 52 | + } |
| 53 | +#ifdef _M_ARM |
| 54 | + // set Thumb bit so that blx is called correctly |
| 55 | + *codeloc = (void *)((uintptr_t)p | 1); |
| 56 | +#else |
| 57 | + *codeloc = p; |
| 58 | +#endif |
| 59 | + return p; |
| 60 | +} |
| 61 | + |
| 62 | +int Py_ffi_closure_make_executable(void *p, size_t size) |
| 63 | +{ |
| 64 | + ULONG old_protect; |
| 65 | + if (!VirtualProtectFromApp(p, size, PAGE_EXECUTE_READ, &old_protect) |
| 66 | + || !FlushInstructionCache(GetCurrentProcess(), p, size)) |
| 67 | + { |
| 68 | + PyErr_SetFromWindowsErr(0); |
| 69 | + return -1; |
| 70 | + } |
| 71 | + return 0; |
| 72 | +} |
| 73 | + |
| 74 | +#else /* MS_WINDOWS_DESKTOP or not MS_WIN32 */ |
31 | 75 |
|
32 | 76 | #ifdef Py_GIL_DISABLED |
33 | 77 | static PyMutex malloc_closure_lock; |
@@ -68,25 +112,10 @@ static void more_core(void) |
68 | 112 |
|
69 | 113 | /* allocate a memory block */ |
70 | 114 | #ifdef MS_WIN32 |
71 | | -#ifdef MS_WINDOWS_DESKTOP |
72 | 115 | item = (ITEM *)VirtualAlloc(NULL, |
73 | 116 | count * sizeof(ITEM), |
74 | 117 | MEM_COMMIT, |
75 | 118 | PAGE_EXECUTE_READWRITE); |
76 | | -#else // UWP |
77 | | - /* Due security restrictions, UWP not allows request Read-Write-Execute permissions at once. |
78 | | - The correct flow in UWP for execute dynamic code in memmory is: |
79 | | - 1. Alloate as Read-Write (PAGE_READWRITE) and write dynamic code to memmory. |
80 | | - 2. Change to Executable (PAGE_EXECUTE_READ) with 'VirtualProtectFromApp'. |
81 | | - 3. Flush cache with 'FlushInstructionCache' to ensure CPU instruction cache coherency |
82 | | - before executing the generated code. |
83 | | - TODO: Implement 2 and 3 in the appropriate places. For now, this defers |
84 | | - the error from import time to time of use (or never, if an app avoids it). */ |
85 | | - item = (ITEM*)VirtualAllocFromApp(NULL, |
86 | | - count * sizeof(ITEM), |
87 | | - MEM_COMMIT | MEM_RESERVE, |
88 | | - PAGE_READWRITE); |
89 | | -#endif // !MS_WINDOWS_DESKTOP |
90 | 119 | if (item == NULL) |
91 | 120 | return; |
92 | 121 | #else |
@@ -176,3 +205,5 @@ void *Py_ffi_closure_alloc(size_t size, void** codeloc) |
176 | 205 | FT_MUTEX_UNLOCK(&malloc_closure_lock); |
177 | 206 | return (void *)item; |
178 | 207 | } |
| 208 | + |
| 209 | +#endif /* MS_WINDOWS_DESKTOP or not MS_WIN32 */ |
0 commit comments