aboutsummaryrefslogtreecommitdiff
path: root/src/lj_mcode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_mcode.c')
-rw-r--r--src/lj_mcode.c320
1 files changed, 198 insertions, 122 deletions
diff --git a/src/lj_mcode.c b/src/lj_mcode.c
index 6e8457ba..edcc4bd9 100644
--- a/src/lj_mcode.c
+++ b/src/lj_mcode.c
@@ -14,6 +14,7 @@
14#include "lj_mcode.h" 14#include "lj_mcode.h"
15#include "lj_trace.h" 15#include "lj_trace.h"
16#include "lj_dispatch.h" 16#include "lj_dispatch.h"
17#include "lj_prng.h"
17#endif 18#endif
18#if LJ_HASJIT || LJ_HASFFI 19#if LJ_HASJIT || LJ_HASFFI
19#include "lj_vm.h" 20#include "lj_vm.h"
@@ -28,6 +29,11 @@
28#include <valgrind/valgrind.h> 29#include <valgrind/valgrind.h>
29#endif 30#endif
30 31
32#if LJ_TARGET_WINDOWS
33#define WIN32_LEAN_AND_MEAN
34#include <windows.h>
35#endif
36
31#if LJ_TARGET_IOS 37#if LJ_TARGET_IOS
32void sys_icache_invalidate(void *start, size_t len); 38void sys_icache_invalidate(void *start, size_t len);
33#endif 39#endif
@@ -40,11 +46,13 @@ void lj_mcode_sync(void *start, void *end)
40#endif 46#endif
41#if LJ_TARGET_X86ORX64 47#if LJ_TARGET_X86ORX64
42 UNUSED(start); UNUSED(end); 48 UNUSED(start); UNUSED(end);
49#elif LJ_TARGET_WINDOWS
50 FlushInstructionCache(GetCurrentProcess(), start, (char *)end-(char *)start);
43#elif LJ_TARGET_IOS 51#elif LJ_TARGET_IOS
44 sys_icache_invalidate(start, (char *)end-(char *)start); 52 sys_icache_invalidate(start, (char *)end-(char *)start);
45#elif LJ_TARGET_PPC 53#elif LJ_TARGET_PPC
46 lj_vm_cachesync(start, end); 54 lj_vm_cachesync(start, end);
47#elif defined(__GNUC__) 55#elif defined(__GNUC__) || defined(__clang__)
48 __clear_cache(start, end); 56 __clear_cache(start, end);
49#else 57#else
50#error "Missing builtin to flush instruction cache" 58#error "Missing builtin to flush instruction cache"
@@ -55,34 +63,46 @@ void lj_mcode_sync(void *start, void *end)
55 63
56#if LJ_HASJIT 64#if LJ_HASJIT
57 65
58#if LJ_TARGET_WINDOWS 66#if LUAJIT_SECURITY_MCODE != 0
67/* Protection twiddling failed. Probably due to kernel security. */
68static LJ_NORET LJ_NOINLINE void mcode_protfail(jit_State *J)
69{
70 lua_CFunction panic = J2G(J)->panic;
71 if (panic) {
72 lua_State *L = J->L;
73 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_JITPROT));
74 panic(L);
75 }
76 exit(EXIT_FAILURE);
77}
78#endif
59 79
60#define WIN32_LEAN_AND_MEAN 80#if LJ_TARGET_WINDOWS
61#include <windows.h>
62 81
63#define MCPROT_RW PAGE_READWRITE 82#define MCPROT_RW PAGE_READWRITE
64#define MCPROT_RX PAGE_EXECUTE_READ 83#define MCPROT_RX PAGE_EXECUTE_READ
65#define MCPROT_RWX PAGE_EXECUTE_READWRITE 84#define MCPROT_RWX PAGE_EXECUTE_READWRITE
66 85
67static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, DWORD prot) 86static void *mcode_alloc_at(uintptr_t hint, size_t sz, DWORD prot)
68{ 87{
69 void *p = VirtualAlloc((void *)hint, sz, 88 return LJ_WIN_VALLOC((void *)hint, sz,
70 MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, prot); 89 MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, prot);
71 if (!p && !hint)
72 lj_trace_err(J, LJ_TRERR_MCODEAL);
73 return p;
74} 90}
75 91
76static void mcode_free(jit_State *J, void *p, size_t sz) 92static void mcode_free(void *p, size_t sz)
77{ 93{
78 UNUSED(J); UNUSED(sz); 94 UNUSED(sz);
79 VirtualFree(p, 0, MEM_RELEASE); 95 VirtualFree(p, 0, MEM_RELEASE);
80} 96}
81 97
82static int mcode_setprot(void *p, size_t sz, DWORD prot) 98static void mcode_setprot(jit_State *J, void *p, size_t sz, DWORD prot)
83{ 99{
100#if LUAJIT_SECURITY_MCODE != 0
84 DWORD oprot; 101 DWORD oprot;
85 return !VirtualProtect(p, sz, prot, &oprot); 102 if (!LJ_WIN_VPROTECT(p, sz, prot, &oprot)) mcode_protfail(J);
103#else
104 UNUSED(J); UNUSED(p); UNUSED(sz); UNUSED(prot);
105#endif
86} 106}
87 107
88#elif LJ_TARGET_POSIX 108#elif LJ_TARGET_POSIX
@@ -93,70 +113,119 @@ static int mcode_setprot(void *p, size_t sz, DWORD prot)
93#define MAP_ANONYMOUS MAP_ANON 113#define MAP_ANONYMOUS MAP_ANON
94#endif 114#endif
95 115
116/* Check for macOS hardened runtime. */
117#if defined(LUAJIT_ENABLE_OSX_HRT) && LUAJIT_SECURITY_MCODE != 0 && defined(MAP_JIT) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 110000
118#include <pthread.h>
119#define MCMAP_CREATE MAP_JIT
120#else
121#define MCMAP_CREATE 0
122#endif
123
96#define MCPROT_RW (PROT_READ|PROT_WRITE) 124#define MCPROT_RW (PROT_READ|PROT_WRITE)
97#define MCPROT_RX (PROT_READ|PROT_EXEC) 125#define MCPROT_RX (PROT_READ|PROT_EXEC)
98#define MCPROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC) 126#define MCPROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC)
127#ifdef PROT_MPROTECT
128#define MCPROT_CREATE (PROT_MPROTECT(MCPROT_RWX))
129#elif MCMAP_CREATE
130#define MCPROT_CREATE PROT_EXEC
131#else
132#define MCPROT_CREATE 0
133#endif
99 134
100static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot) 135static void *mcode_alloc_at(uintptr_t hint, size_t sz, int prot)
101{ 136{
102 void *p = mmap((void *)hint, sz, prot, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 137 void *p = mmap((void *)hint, sz, prot|MCPROT_CREATE, MAP_PRIVATE|MAP_ANONYMOUS|MCMAP_CREATE, -1, 0);
103 if (p == MAP_FAILED) { 138 if (p == MAP_FAILED) return NULL;
104 if (!hint) lj_trace_err(J, LJ_TRERR_MCODEAL); 139#if MCMAP_CREATE
105 p = NULL; 140 pthread_jit_write_protect_np(0);
106 } 141#endif
107 return p; 142 return p;
108} 143}
109 144
110static void mcode_free(jit_State *J, void *p, size_t sz) 145static void mcode_free(void *p, size_t sz)
111{ 146{
112 UNUSED(J);
113 munmap(p, sz); 147 munmap(p, sz);
114} 148}
115 149
116static int mcode_setprot(void *p, size_t sz, int prot) 150static void mcode_setprot(jit_State *J, void *p, size_t sz, int prot)
117{ 151{
118 return mprotect(p, sz, prot); 152#if LUAJIT_SECURITY_MCODE != 0
153#if MCMAP_CREATE
154 UNUSED(J); UNUSED(p); UNUSED(sz);
155 pthread_jit_write_protect_np((prot & PROT_EXEC));
156 return 0;
157#else
158 if (mprotect(p, sz, prot)) mcode_protfail(J);
159#endif
160#else
161 UNUSED(J); UNUSED(p); UNUSED(sz); UNUSED(prot);
162#endif
119} 163}
120 164
121#elif LJ_64
122
123#error "Missing OS support for explicit placement of executable memory"
124
125#else 165#else
126 166
127/* Fallback allocator. This will fail if memory is not executable by default. */ 167#error "Missing OS support for explicit placement of executable memory"
128#define LUAJIT_UNPROTECT_MCODE
129#define MCPROT_RW 0
130#define MCPROT_RX 0
131#define MCPROT_RWX 0
132 168
133static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot) 169#endif
134{
135 UNUSED(hint); UNUSED(prot);
136 return lj_mem_new(J->L, sz);
137}
138 170
139static void mcode_free(jit_State *J, void *p, size_t sz) 171#ifdef LUAJIT_MCODE_TEST
172/* Test wrapper for mcode allocation. DO NOT ENABLE in production! Try:
173** LUAJIT_MCODE_TEST=hhhhhhhhhhhhhhhh luajit -jv main.lua
174** LUAJIT_MCODE_TEST=F luajit -jv main.lua
175*/
176static void *mcode_alloc_at_TEST(jit_State *J, uintptr_t hint, size_t sz, int prot)
140{ 177{
141 lj_mem_free(J2G(J), p, sz); 178 static int test_ofs = 0;
179 static const char *test_str;
180 if (!test_str) {
181 test_str = getenv("LUAJIT_MCODE_TEST");
182 if (!test_str) test_str = "";
183 }
184 switch (test_str[test_ofs]) {
185 case 'a': /* OK for one allocation. */
186 test_ofs++;
187 /* fallthrough */
188 case '\0': /* EOS: OK for any further allocations. */
189 break;
190 case 'h': /* Ignore one hint. */
191 test_ofs++;
192 /* fallthrough */
193 case 'H': /* Ignore any further hints. */
194 hint = 0u;
195 break;
196 case 'r': /* Randomize one hint. */
197 test_ofs++;
198 /* fallthrough */
199 case 'R': /* Randomize any further hints. */
200 hint = lj_prng_u64(&J2G(J)->prng) & ~(uintptr_t)0xffffu;
201 hint &= ((uintptr_t)1 << (LJ_64 ? 47 : 31)) - 1;
202 break;
203 case 'f': /* Fail one allocation. */
204 test_ofs++;
205 /* fallthrough */
206 default: /* 'F' or unknown: Fail any further allocations. */
207 return NULL;
208 }
209 return mcode_alloc_at(hint, sz, prot);
142} 210}
143 211#define mcode_alloc_at(hint, sz, prot) mcode_alloc_at_TEST(J, hint, sz, prot)
144#endif 212#endif
145 213
146/* -- MCode area protection ----------------------------------------------- */ 214/* -- MCode area protection ----------------------------------------------- */
147 215
148/* Define this ONLY if page protection twiddling becomes a bottleneck. */ 216#if LUAJIT_SECURITY_MCODE == 0
149#ifdef LUAJIT_UNPROTECT_MCODE
150 217
151/* It's generally considered to be a potential security risk to have 218/* Define this ONLY if page protection twiddling becomes a bottleneck.
219**
220** It's generally considered to be a potential security risk to have
152** pages with simultaneous write *and* execute access in a process. 221** pages with simultaneous write *and* execute access in a process.
153** 222**
154** Do not even think about using this mode for server processes or 223** Do not even think about using this mode for server processes or
155** apps handling untrusted external data (such as a browser). 224** apps handling untrusted external data.
156** 225**
157** The security risk is not in LuaJIT itself -- but if an adversary finds 226** The security risk is not in LuaJIT itself -- but if an adversary finds
158** any *other* flaw in your C application logic, then any RWX memory page 227** any *other* flaw in your C application logic, then any RWX memory pages
159** simplifies writing an exploit considerably. 228** simplify writing an exploit considerably.
160*/ 229*/
161#define MCPROT_GEN MCPROT_RWX 230#define MCPROT_GEN MCPROT_RWX
162#define MCPROT_RUN MCPROT_RWX 231#define MCPROT_RUN MCPROT_RWX
@@ -179,24 +248,11 @@ static void mcode_protect(jit_State *J, int prot)
179#define MCPROT_GEN MCPROT_RW 248#define MCPROT_GEN MCPROT_RW
180#define MCPROT_RUN MCPROT_RX 249#define MCPROT_RUN MCPROT_RX
181 250
182/* Protection twiddling failed. Probably due to kernel security. */
183static LJ_NORET LJ_NOINLINE void mcode_protfail(jit_State *J)
184{
185 lua_CFunction panic = J2G(J)->panic;
186 if (panic) {
187 lua_State *L = J->L;
188 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_JITPROT));
189 panic(L);
190 }
191 exit(EXIT_FAILURE);
192}
193
194/* Change protection of MCode area. */ 251/* Change protection of MCode area. */
195static void mcode_protect(jit_State *J, int prot) 252static void mcode_protect(jit_State *J, int prot)
196{ 253{
197 if (J->mcprot != prot) { 254 if (J->mcprot != prot) {
198 if (LJ_UNLIKELY(mcode_setprot(J->mcarea, J->szmcarea, prot))) 255 mcode_setprot(J, J->mcarea, J->szmcarea, prot);
199 mcode_protfail(J);
200 J->mcprot = prot; 256 J->mcprot = prot;
201 } 257 }
202} 258}
@@ -205,47 +261,74 @@ static void mcode_protect(jit_State *J, int prot)
205 261
206/* -- MCode area allocation ----------------------------------------------- */ 262/* -- MCode area allocation ----------------------------------------------- */
207 263
208#if LJ_64
209#define mcode_validptr(p) (p)
210#else
211#define mcode_validptr(p) ((p) && (uintptr_t)(p) < 0xffff0000)
212#endif
213
214#ifdef LJ_TARGET_JUMPRANGE 264#ifdef LJ_TARGET_JUMPRANGE
215 265
216/* Get memory within relative jump distance of our code in 64 bit mode. */ 266#define MCODE_RANGE64 ((1u << LJ_TARGET_JUMPRANGE) - 0x10000u)
217static void *mcode_alloc(jit_State *J, size_t sz) 267
268/* Set a memory range for mcode allocation with addr in the middle. */
269static void mcode_setrange(jit_State *J, uintptr_t addr)
218{ 270{
219 /* Target an address in the static assembler code (64K aligned).
220 ** Try addresses within a distance of target-range/2+1MB..target+range/2-1MB.
221 ** Use half the jump range so every address in the range can reach any other.
222 */
223#if LJ_TARGET_MIPS 271#if LJ_TARGET_MIPS
224 /* Use the middle of the 256MB-aligned region. */ 272 /* Use the whole 256MB-aligned region. */
225 uintptr_t target = ((uintptr_t)(void *)lj_vm_exit_handler & 0xf0000000u) + 273 J->mcmin = addr & ~(uintptr_t)((1u << LJ_TARGET_JUMPRANGE) - 1);
226 0x08000000u; 274 J->mcmax = J->mcmin + (1u << LJ_TARGET_JUMPRANGE);
227#else 275#else
228 uintptr_t target = (uintptr_t)(void *)lj_vm_exit_handler & ~(uintptr_t)0xffff; 276 /* Every address in the 64KB-aligned range should be able to reach
277 ** any other, so MCODE_RANGE64 is only half the (signed) branch range.
278 */
279 J->mcmin = (addr - (MCODE_RANGE64 >> 1) + 0xffffu) & ~(uintptr_t)0xffffu;
280 J->mcmax = J->mcmin + MCODE_RANGE64;
229#endif 281#endif
230 const uintptr_t range = (1u << (LJ_TARGET_JUMPRANGE-1)) - (1u << 21); 282 /* Avoid wrap-around and the 64KB corners. */
231 /* First try a contiguous area below the last one. */ 283 if (addr < J->mcmin || !J->mcmin) J->mcmin = 0x10000u;
232 uintptr_t hint = J->mcarea ? (uintptr_t)J->mcarea - sz : 0; 284 if (addr > J->mcmax) J->mcmax = ~(uintptr_t)0xffffu;
233 int i; 285}
234 /* Limit probing iterations, depending on the available pool size. */ 286
235 for (i = 0; i < LJ_TARGET_JUMPRANGE; i++) { 287/* Check if an address is in range of the mcode allocation range. */
236 if (mcode_validptr(hint)) { 288static LJ_AINLINE int mcode_inrange(jit_State *J, uintptr_t addr, size_t sz)
237 void *p = mcode_alloc_at(J, hint, sz, MCPROT_GEN); 289{
238 290 /* Take care of unsigned wrap-around of addr + sz, too. */
239 if (mcode_validptr(p) && 291 return addr >= J->mcmin && addr + sz >= J->mcmin && addr + sz <= J->mcmax;
240 ((uintptr_t)p + sz - target < range || target - (uintptr_t)p < range)) 292}
241 return p; 293
242 if (p) mcode_free(J, p, sz); /* Free badly placed area. */ 294/* Get memory within a specific jump range in 64 bit mode. */
243 } 295static void *mcode_alloc(jit_State *J, size_t sz)
244 /* Next try probing 64K-aligned pseudo-random addresses. */ 296{
297 uintptr_t hint;
298 int i = 0, j;
299 if (!J->mcmin) /* Place initial range near the interpreter code. */
300 mcode_setrange(J, (uintptr_t)(void *)lj_vm_exit_handler);
301 else if (!J->mcmax) /* Switch to a new range (already flushed). */
302 goto newrange;
303 /* First try a contiguous area below the last one (if in range). */
304 hint = (uintptr_t)J->mcarea - sz;
305 if (!mcode_inrange(J, hint, sz)) /* Also takes care of NULL J->mcarea. */
306 goto probe;
307 for (; i < 16; i++) {
308 void *p = mcode_alloc_at(hint, sz, MCPROT_GEN);
309 if (mcode_inrange(J, (uintptr_t)p, sz))
310 return p; /* Success. */
311 else if (p)
312 mcode_free(p, sz); /* Free badly placed area. */
313 probe:
314 /* Next try probing 64KB-aligned pseudo-random addresses. */
315 j = 0;
245 do { 316 do {
246 hint = LJ_PRNG_BITS(J, LJ_TARGET_JUMPRANGE-16) << 16; 317 hint = J->mcmin + (lj_prng_u64(&J2G(J)->prng) & MCODE_RANGE64);
247 } while (!(hint + sz < range+range)); 318 if (++j > 15) goto fail;
248 hint = target + hint - range; 319 } while (!mcode_inrange(J, hint, sz));
320 }
321fail:
322 if (!J->mcarea) { /* Switch to a new range now. */
323 void *p;
324 newrange:
325 p = mcode_alloc_at(0, sz, MCPROT_GEN);
326 if (p) {
327 mcode_setrange(J, (uintptr_t)p + (sz >> 1));
328 return p; /* Success. */
329 }
330 } else {
331 J->mcmax = 0; /* Switch to a new range after the flush. */
249 } 332 }
250 lj_trace_err(J, LJ_TRERR_MCODEAL); /* Give up. OS probably ignores hints? */ 333 lj_trace_err(J, LJ_TRERR_MCODEAL); /* Give up. OS probably ignores hints? */
251 return NULL; 334 return NULL;
@@ -256,17 +339,15 @@ static void *mcode_alloc(jit_State *J, size_t sz)
256/* All memory addresses are reachable by relative jumps. */ 339/* All memory addresses are reachable by relative jumps. */
257static void *mcode_alloc(jit_State *J, size_t sz) 340static void *mcode_alloc(jit_State *J, size_t sz)
258{ 341{
259#ifdef __OpenBSD__ 342#if defined(__OpenBSD__) || defined(__NetBSD__) || LJ_TARGET_UWP
260 /* Allow better executable memory allocation for OpenBSD W^X mode. */ 343 /* Allow better executable memory allocation for OpenBSD W^X mode. */
261 void *p = mcode_alloc_at(J, 0, sz, MCPROT_RUN); 344 void *p = mcode_alloc_at(0, sz, MCPROT_RUN);
262 if (p && mcode_setprot(p, sz, MCPROT_GEN)) { 345 if (p) mcode_setprot(J, p, sz, MCPROT_GEN);
263 mcode_free(J, p, sz);
264 return NULL;
265 }
266 return p;
267#else 346#else
268 return mcode_alloc_at(J, 0, sz, MCPROT_GEN); 347 void *p = mcode_alloc_at(0, sz, MCPROT_GEN);
269#endif 348#endif
349 if (!p) lj_trace_err(J, LJ_TRERR_MCODEAL);
350 return p;
270} 351}
271 352
272#endif 353#endif
@@ -278,7 +359,6 @@ static void mcode_allocarea(jit_State *J)
278{ 359{
279 MCode *oldarea = J->mcarea; 360 MCode *oldarea = J->mcarea;
280 size_t sz = (size_t)J->param[JIT_P_sizemcode] << 10; 361 size_t sz = (size_t)J->param[JIT_P_sizemcode] << 10;
281 sz = (sz + LJ_PAGESIZE-1) & ~(size_t)(LJ_PAGESIZE - 1);
282 J->mcarea = (MCode *)mcode_alloc(J, sz); 362 J->mcarea = (MCode *)mcode_alloc(J, sz);
283 J->szmcarea = sz; 363 J->szmcarea = sz;
284 J->mcprot = MCPROT_GEN; 364 J->mcprot = MCPROT_GEN;
@@ -287,6 +367,7 @@ static void mcode_allocarea(jit_State *J)
287 ((MCLink *)J->mcarea)->next = oldarea; 367 ((MCLink *)J->mcarea)->next = oldarea;
288 ((MCLink *)J->mcarea)->size = sz; 368 ((MCLink *)J->mcarea)->size = sz;
289 J->szallmcarea += sz; 369 J->szallmcarea += sz;
370 J->mcbot = (MCode *)lj_err_register_mcode(J->mcarea, sz, (uint8_t *)J->mcbot);
290} 371}
291 372
292/* Free all MCode areas. */ 373/* Free all MCode areas. */
@@ -297,7 +378,9 @@ void lj_mcode_free(jit_State *J)
297 J->szallmcarea = 0; 378 J->szallmcarea = 0;
298 while (mc) { 379 while (mc) {
299 MCode *next = ((MCLink *)mc)->next; 380 MCode *next = ((MCLink *)mc)->next;
300 mcode_free(J, mc, ((MCLink *)mc)->size); 381 size_t sz = ((MCLink *)mc)->size;
382 lj_err_deregister_mcode(mc, sz, (uint8_t *)mc + sizeof(MCLink));
383 mcode_free(mc, sz);
301 mc = next; 384 mc = next;
302 } 385 }
303} 386}
@@ -332,35 +415,29 @@ void lj_mcode_abort(jit_State *J)
332/* Set/reset protection to allow patching of MCode areas. */ 415/* Set/reset protection to allow patching of MCode areas. */
333MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish) 416MCode *lj_mcode_patch(jit_State *J, MCode *ptr, int finish)
334{ 417{
335#ifdef LUAJIT_UNPROTECT_MCODE
336 UNUSED(J); UNUSED(ptr); UNUSED(finish);
337 return NULL;
338#else
339 if (finish) { 418 if (finish) {
340 if (J->mcarea == ptr) 419 if (J->mcarea == ptr)
341 mcode_protect(J, MCPROT_RUN); 420 mcode_protect(J, MCPROT_RUN);
342 else if (LJ_UNLIKELY(mcode_setprot(ptr, ((MCLink *)ptr)->size, MCPROT_RUN))) 421 else
343 mcode_protfail(J); 422 mcode_setprot(J, ptr, ((MCLink *)ptr)->size, MCPROT_RUN);
344 return NULL; 423 return NULL;
345 } else { 424 } else {
346 MCode *mc = J->mcarea; 425 uintptr_t base = (uintptr_t)J->mcarea, addr = (uintptr_t)ptr;
347 /* Try current area first to use the protection cache. */ 426 /* Try current area first to use the protection cache. */
348 if (ptr >= mc && ptr < (MCode *)((char *)mc + J->szmcarea)) { 427 if (addr >= base && addr < base + J->szmcarea) {
349 mcode_protect(J, MCPROT_GEN); 428 mcode_protect(J, MCPROT_GEN);
350 return mc; 429 return (MCode *)base;
351 } 430 }
352 /* Otherwise search through the list of MCode areas. */ 431 /* Otherwise search through the list of MCode areas. */
353 for (;;) { 432 for (;;) {
354 mc = ((MCLink *)mc)->next; 433 base = (uintptr_t)(((MCLink *)base)->next);
355 lua_assert(mc != NULL); 434 lj_assertJ(base != 0, "broken MCode area chain");
356 if (ptr >= mc && ptr < (MCode *)((char *)mc + ((MCLink *)mc)->size)) { 435 if (addr >= base && addr < base + ((MCLink *)base)->size) {
357 if (LJ_UNLIKELY(mcode_setprot(mc, ((MCLink *)mc)->size, MCPROT_GEN))) 436 mcode_setprot(J, (MCode *)base, ((MCLink *)base)->size, MCPROT_GEN);
358 mcode_protfail(J); 437 return (MCode *)base;
359 return mc;
360 } 438 }
361 } 439 }
362 } 440 }
363#endif
364} 441}
365 442
366/* Limit of MCode reservation reached. */ 443/* Limit of MCode reservation reached. */
@@ -369,7 +446,6 @@ void lj_mcode_limiterr(jit_State *J, size_t need)
369 size_t sizemcode, maxmcode; 446 size_t sizemcode, maxmcode;
370 lj_mcode_abort(J); 447 lj_mcode_abort(J);
371 sizemcode = (size_t)J->param[JIT_P_sizemcode] << 10; 448 sizemcode = (size_t)J->param[JIT_P_sizemcode] << 10;
372 sizemcode = (sizemcode + LJ_PAGESIZE-1) & ~(size_t)(LJ_PAGESIZE - 1);
373 maxmcode = (size_t)J->param[JIT_P_maxmcode] << 10; 449 maxmcode = (size_t)J->param[JIT_P_maxmcode] << 10;
374 if (need * sizeof(MCode) > sizemcode) 450 if (need * sizeof(MCode) > sizemcode)
375 lj_trace_err(J, LJ_TRERR_MCODEOV); /* Too long for any area. */ 451 lj_trace_err(J, LJ_TRERR_MCODEOV); /* Too long for any area. */