Compare commits

..

8 Commits

Author SHA1 Message Date
gns
0bb43d321c
Merge fd1422f59e into e3c70a7d81 2025-03-10 09:42:24 +08:00
Mike Pall
e3c70a7d81 macOS: Fix support for Apple hardened runtime.
Reported by Christian Clason. #1334
2025-03-10 00:05:08 +01:00
Mike Pall
7db2d1b12a Fix handling of nil value markers in template tables.
Thanks to Peter Cawley. #1348 #1155
2025-03-09 23:11:05 +01:00
Mike Pall
e0551670c9 Merge branch 'master' into v2.1 2025-03-09 23:09:02 +01:00
Mike Pall
85c3f2fb6f Avoid unpatching bytecode twice after a trace flush.
Reported by Sergey Kaplun. #1345
2025-03-09 23:04:23 +01:00
Mike Pall
eee16efa77 Fix state restore when recording __concat metamethod.
Reported by Sergey Kaplun. #1338 #1298
2025-03-09 21:28:17 +01:00
Mike Pall
4219efae43 Windows: Allow mixed builds with msvcbuild.bat.
Suggested by alex4814. #1341
2025-03-09 21:05:06 +01:00
Mike Pall
0254770582 macOS: Add suport for Apple hardened runtime.
Thanks to Peter Cawley. #1334
2025-03-09 20:45:22 +01:00
6 changed files with 56 additions and 21 deletions

View File

@ -186,7 +186,7 @@ static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
} else { } else {
MSize i = nhash; MSize i = nhash;
for (;; node--) for (;; node--)
if (!tvisnil(&node->key)) { if (!tvisnil(&node->val)) {
bcwrite_ktabk(ctx, &node->key, 0); bcwrite_ktabk(ctx, &node->key, 0);
bcwrite_ktabk(ctx, &node->val, 1); bcwrite_ktabk(ctx, &node->val, 1);
if (--i == 0) break; if (--i == 0) break;

View File

@ -299,6 +299,14 @@ static void *callback_mcode_init(global_State *g, uint32_t *page)
#define CCPROT_CREATE 0 #define CCPROT_CREATE 0
#endif #endif
/* Check for macOS hardened runtime. */
#if LUAJIT_SECURITY_MCODE != 0 && defined(MAP_JIT) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 110000
#include <pthread.h>
#define CCMAP_CREATE MAP_JIT
#else
#define CCMAP_CREATE 0
#endif
#endif #endif
/* Allocate and initialize area for callback function pointers. */ /* Allocate and initialize area for callback function pointers. */
@ -313,10 +321,13 @@ static void callback_mcode_new(CTState *cts)
if (!p) if (!p)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV); lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#elif LJ_TARGET_POSIX #elif LJ_TARGET_POSIX
p = mmap(NULL, sz, (PROT_READ|PROT_WRITE|CCPROT_CREATE), MAP_PRIVATE|MAP_ANONYMOUS, p = mmap(NULL, sz, PROT_READ|PROT_WRITE|CCPROT_CREATE,
-1, 0); MAP_PRIVATE|MAP_ANONYMOUS|CCMAP_CREATE, -1, 0);
if (p == MAP_FAILED) if (p == MAP_FAILED)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV); lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#if CCMAP_CREATE
pthread_jit_write_protect_np(0);
#endif
#else #else
/* Fallback allocator. Fails if memory is not executable by default. */ /* Fallback allocator. Fails if memory is not executable by default. */
p = lj_mem_new(cts->L, sz); p = lj_mem_new(cts->L, sz);
@ -333,8 +344,12 @@ static void callback_mcode_new(CTState *cts)
LJ_WIN_VPROTECT(p, sz, PAGE_EXECUTE_READ, &oprot); LJ_WIN_VPROTECT(p, sz, PAGE_EXECUTE_READ, &oprot);
} }
#elif LJ_TARGET_POSIX #elif LJ_TARGET_POSIX
#if CCMAP_CREATE
pthread_jit_write_protect_np(1);
#else
mprotect(p, sz, (PROT_READ|PROT_EXEC)); mprotect(p, sz, (PROT_READ|PROT_EXEC));
#endif #endif
#endif
} }
/* Free area for callback function pointers. */ /* Free area for callback function pointers. */

View File

@ -115,6 +115,14 @@ static int mcode_setprot(void *p, size_t sz, DWORD prot)
#define MAP_ANONYMOUS MAP_ANON #define MAP_ANONYMOUS MAP_ANON
#endif #endif
/* Check for macOS hardened runtime. */
#if LUAJIT_SECURITY_MCODE != 0 && defined(MAP_JIT) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 110000
#include <pthread.h>
#define MCMAP_CREATE MAP_JIT
#else
#define MCMAP_CREATE 0
#endif
#define MCPROT_RW (PROT_READ|PROT_WRITE) #define MCPROT_RW (PROT_READ|PROT_WRITE)
#define MCPROT_RX (PROT_READ|PROT_EXEC) #define MCPROT_RX (PROT_READ|PROT_EXEC)
#define MCPROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC) #define MCPROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC)
@ -126,10 +134,14 @@ static int mcode_setprot(void *p, size_t sz, DWORD prot)
static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot) static void *mcode_alloc_at(jit_State *J, uintptr_t hint, size_t sz, int prot)
{ {
void *p = mmap((void *)hint, sz, prot|MCPROT_CREATE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); void *p = mmap((void *)hint, sz, prot|MCPROT_CREATE, MAP_PRIVATE|MAP_ANONYMOUS|MCMAP_CREATE, -1, 0);
if (p == MAP_FAILED) { if (p == MAP_FAILED) {
if (!hint) lj_trace_err(J, LJ_TRERR_MCODEAL); if (!hint) lj_trace_err(J, LJ_TRERR_MCODEAL);
p = NULL; p = NULL;
#if MCMAP_CREATE
} else {
pthread_jit_write_protect_np(0);
#endif
} }
return p; return p;
} }
@ -142,7 +154,12 @@ static void mcode_free(jit_State *J, void *p, size_t sz)
static int mcode_setprot(void *p, size_t sz, int prot) static int mcode_setprot(void *p, size_t sz, int prot)
{ {
#if MCMAP_CREATE
pthread_jit_write_protect_np((prot & PROT_EXEC));
return 0;
#else
return mprotect(p, sz, prot); return mprotect(p, sz, prot);
#endif
} }
#else #else

View File

@ -2079,6 +2079,7 @@ static TRef rec_tnew(jit_State *J, uint32_t ah)
/* -- Concatenation ------------------------------------------------------- */ /* -- Concatenation ------------------------------------------------------- */
typedef struct RecCatDataCP { typedef struct RecCatDataCP {
TValue savetv[5+LJ_FR2];
jit_State *J; jit_State *J;
BCReg baseslot, topslot; BCReg baseslot, topslot;
TRef tr; TRef tr;
@ -2119,7 +2120,9 @@ static TValue *rec_mm_concat_cp(lua_State *L, lua_CFunction dummy, void *ud)
return NULL; return NULL;
} }
/* Pass partial result. */ /* Pass partial result. */
topslot = J->maxslot--; rcd->topslot = topslot = J->maxslot--;
/* Save updated range of slots. */
memcpy(rcd->savetv, &L->base[topslot-1], sizeof(rcd->savetv));
*xbase = tr; *xbase = tr;
top = xbase; top = xbase;
setstrV(J->L, &ix.keyv, &J2G(J)->strempty); /* Simulate string result. */ setstrV(J->L, &ix.keyv, &J2G(J)->strempty); /* Simulate string result. */
@ -2139,16 +2142,18 @@ static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot)
{ {
lua_State *L = J->L; lua_State *L = J->L;
ptrdiff_t delta = L->top - L->base; ptrdiff_t delta = L->top - L->base;
TValue savetv[5+LJ_FR2], errobj; TValue errobj;
RecCatDataCP rcd; RecCatDataCP rcd;
int errcode; int errcode;
rcd.J = J; rcd.J = J;
rcd.baseslot = baseslot; rcd.baseslot = baseslot;
rcd.topslot = topslot; rcd.topslot = topslot;
memcpy(savetv, &L->base[topslot-1], sizeof(savetv)); /* Save slots. */ /* Save slots. */
memcpy(rcd.savetv, &L->base[topslot-1], sizeof(rcd.savetv));
errcode = lj_vm_cpcall(L, NULL, &rcd, rec_mm_concat_cp); errcode = lj_vm_cpcall(L, NULL, &rcd, rec_mm_concat_cp);
if (errcode) copyTV(L, &errobj, L->top-1); if (errcode) copyTV(L, &errobj, L->top-1);
memcpy(&L->base[topslot-1], savetv, sizeof(savetv)); /* Restore slots. */ /* Restore slots. */
memcpy(&L->base[rcd.topslot-1], rcd.savetv, sizeof(rcd.savetv));
if (errcode) { if (errcode) {
L->top = L->base + delta; L->top = L->base + delta;
copyTV(L, L->top++, &errobj); copyTV(L, L->top++, &errobj);

View File

@ -222,14 +222,6 @@ static void trace_unpatch(jit_State *J, GCtrace *T)
bc_isret(op), "bad original bytecode %d", op); bc_isret(op), "bad original bytecode %d", op);
*pc = T->startins; *pc = T->startins;
break; break;
case BC_JMP:
lj_assertJ(op == BC_ITERL, "bad original bytecode %d", op);
pc += bc_j(*pc)+2;
if (bc_op(*pc) == BC_JITERL) {
lj_assertJ(traceref(J, bc_d(*pc)) == T, "JITERL references other trace");
*pc = T->startins;
}
break;
case BC_JFUNCF: case BC_JFUNCF:
lj_assertJ(op == BC_FUNCF, "bad original bytecode %d", op); lj_assertJ(op == BC_FUNCF, "bad original bytecode %d", op);
*pc = T->startins; *pc = T->startins;
@ -245,18 +237,19 @@ static void trace_flushroot(jit_State *J, GCtrace *T)
GCproto *pt = &gcref(T->startpt)->pt; GCproto *pt = &gcref(T->startpt)->pt;
lj_assertJ(T->root == 0, "not a root trace"); lj_assertJ(T->root == 0, "not a root trace");
lj_assertJ(pt != NULL, "trace has no prototype"); lj_assertJ(pt != NULL, "trace has no prototype");
/* First unpatch any modified bytecode. */
trace_unpatch(J, T);
/* Unlink root trace from chain anchored in prototype. */ /* Unlink root trace from chain anchored in prototype. */
if (pt->trace == T->traceno) { /* Trace is first in chain. Easy. */ if (pt->trace == T->traceno) { /* Trace is first in chain. Easy. */
pt->trace = T->nextroot; pt->trace = T->nextroot;
unpatch:
/* Unpatch modified bytecode only if the trace has not been flushed. */
trace_unpatch(J, T);
} else if (pt->trace) { /* Otherwise search in chain of root traces. */ } else if (pt->trace) { /* Otherwise search in chain of root traces. */
GCtrace *T2 = traceref(J, pt->trace); GCtrace *T2 = traceref(J, pt->trace);
if (T2) { if (T2) {
for (; T2->nextroot; T2 = traceref(J, T2->nextroot)) for (; T2->nextroot; T2 = traceref(J, T2->nextroot))
if (T2->nextroot == T->traceno) { if (T2->nextroot == T->traceno) {
T2->nextroot = T->nextroot; /* Unlink from chain. */ T2->nextroot = T->nextroot; /* Unlink from chain. */
break; goto unpatch;
} }
} }
} }

View File

@ -8,7 +8,8 @@
@rem nogc64 disable LJ_GC64 mode for x64 @rem nogc64 disable LJ_GC64 mode for x64
@rem debug emit debug symbols @rem debug emit debug symbols
@rem amalg amalgamated build @rem amalg amalgamated build
@rem static static linkage @rem static create static lib to statically link into your project
@rem mixed create static lib to build a DLL in your project
@if not defined INCLUDE goto :FAIL @if not defined INCLUDE goto :FAIL
@ -106,12 +107,14 @@ buildvm -m folddef -o lj_folddef.h lj_opt_fold.c
@if "%1"=="static" goto :STATIC @if "%1"=="static" goto :STATIC
%LJCOMPILE% %LJDYNBUILD% lj_*.c lib_*.c %LJCOMPILE% %LJDYNBUILD% lj_*.c lib_*.c
@if errorlevel 1 goto :BAD @if errorlevel 1 goto :BAD
@if "%1"=="mixed" goto :STATICLIB
%LJLINK% /DLL /OUT:%LJDLLNAME% lj_*.obj lib_*.obj %LJLINK% /DLL /OUT:%LJDLLNAME% lj_*.obj lib_*.obj
@if errorlevel 1 goto :BAD @if errorlevel 1 goto :BAD
@goto :MTDLL @goto :MTDLL
:STATIC :STATIC
%LJCOMPILE% lj_*.c lib_*.c %LJCOMPILE% lj_*.c lib_*.c
@if errorlevel 1 goto :BAD @if errorlevel 1 goto :BAD
:STATICLIB
%LJLIB% /OUT:%LJLIBNAME% lj_*.obj lib_*.obj %LJLIB% /OUT:%LJLIBNAME% lj_*.obj lib_*.obj
@if errorlevel 1 goto :BAD @if errorlevel 1 goto :BAD
@goto :MTDLL @goto :MTDLL
@ -119,13 +122,15 @@ buildvm -m folddef -o lj_folddef.h lj_opt_fold.c
@if "%2"=="static" goto :AMALGSTATIC @if "%2"=="static" goto :AMALGSTATIC
%LJCOMPILE% %LJDYNBUILD% ljamalg.c %LJCOMPILE% %LJDYNBUILD% ljamalg.c
@if errorlevel 1 goto :BAD @if errorlevel 1 goto :BAD
@if "%2"=="mixed" goto :AMALGSTATICLIB
%LJLINK% /DLL /OUT:%LJDLLNAME% ljamalg.obj lj_vm.obj %LJLINK% /DLL /OUT:%LJDLLNAME% ljamalg.obj lj_vm.obj
@if errorlevel 1 goto :BAD @if errorlevel 1 goto :BAD
@goto :MTDLL @goto :MTDLL
:AMALGSTATIC :AMALGSTATIC
%LJCOMPILE% ljamalg.c %LJCOMPILE% ljamalg.c
@if errorlevel 1 goto :BAD @if errorlevel 1 goto :BAD
%LJLINK% /OUT:%LJDLLNAME% ljamalg.obj lj_vm.obj :AMALGSTATICLIB
%LJLIB% /OUT:%LJLIBNAME% ljamalg.obj lj_vm.obj
@if errorlevel 1 goto :BAD @if errorlevel 1 goto :BAD
:MTDLL :MTDLL
if exist %LJDLLNAME%.manifest^ if exist %LJDLLNAME%.manifest^