Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e3c70a7
macOS: Fix support for Apple hardened runtime.
Mar 9, 2025
4f2bb19
macOS: Fix Apple hardened runtime support and put behind build option.
Mar 10, 2025
84cb21f
REVERT: Change handling of nil value markers in template tables.
Mar 10, 2025
538a821
Change handling of nil value markers in template tables.
Mar 11, 2025
e9e4b6d
Initialize unused value when specializing to cdata metatable.
Apr 7, 2025
e76bb50
Fix error generation in load*.
Apr 7, 2025
e0a7ea8
Merge branch 'master' into v2.1
Apr 7, 2025
c262976
ARM64: Fix pass-by-value struct calling conventions.
Apr 10, 2025
51d4c26
ARM: Fix soft-float math.min()/math.max().
Apr 10, 2025
eec7a80
Prevent Clang UB 'optimization' which breaks integerness checks.
Apr 10, 2025
9c8eb7c
FFI: Fix dangling CType references.
May 28, 2025
852c3a0
Merge branch 'master' into v2.1
May 28, 2025
cd4af8a
Avoid out-of-range PC for stack overflow error from snapshot restore.
May 28, 2025
0a8cd58
Merge branch 'master' into v2.1
May 28, 2025
048972d
Fix JIT slot overflow during up-recursion.
May 28, 2025
f9140a6
Merge branch 'master' into v2.1
May 28, 2025
c64020f
FFI: Fix dangling CType references (again).
Jul 24, 2025
e3fa3c4
Avoid out-of-range PC for stack overflow error from snapshot restore.
Jul 24, 2025
c92d0cb
x86/x64: Don't use undefined MUL/IMUL zero flag.
Jul 24, 2025
eed22e9
Merge branch 'master' into v2.1
Jul 24, 2025
871db2c
Windows: Add lua52compat option to msvcbuild.bat.
Jul 24, 2025
54a1626
Fix reporting of an error during error handling.
Oct 16, 2025
a69aef4
Fix io.write() of newly created buffer.
Oct 16, 2025
a21ba1c
Add GNU/Hurd build support.
Oct 16, 2025
5c3254d
Gracefully handle broken custom allocator.
Oct 16, 2025
25a61a1
x64: Add support for CET IBT.
Oct 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ endif
ifneq (,$(INSTALL_LJLIBD))
TARGET_XCFLAGS+= -DLUA_LJDIR=\"$(INSTALL_LJLIBD)\"
endif
ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-strict-float-cast-overflow 2>/dev/null || echo 1))
TARGET_XCFLAGS+= -fno-strict-float-cast-overflow
endif

##############################################################################
# Target system detection.
Expand Down Expand Up @@ -354,6 +357,9 @@ else
ifeq (GNU/kFreeBSD,$(TARGET_SYS))
TARGET_XLIBS+= -ldl
endif
ifeq (GNU,$(TARGET_SYS))
TARGET_XLIBS+= -ldl
endif
endif
endif
endif
Expand Down Expand Up @@ -440,6 +446,10 @@ ifneq (,$(findstring LJ_ABI_PAUTH 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D PAUTH
TARGET_ARCH+= -DLJ_ABI_PAUTH=1
endif
ifneq (,$(findstring LJ_CET_BR 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D CET_BR
TARGET_ARCH+= -DLJ_CET_BR=1
endif
DASM_AFLAGS+= -D VER=$(subst LJ_ARCH_VERSION_,,$(filter LJ_ARCH_VERSION_%,$(subst LJ_ARCH_VERSION ,LJ_ARCH_VERSION_,$(TARGET_TESTARCH))))
ifeq (Windows,$(TARGET_SYS))
DASM_AFLAGS+= -D WIN
Expand Down
20 changes: 19 additions & 1 deletion src/jit/dis_x86.lua
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ local map_opc2 = {
"movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm",
"movhpsXmr||movhpdXmr",
"$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm",
"hintnopVm","hintnopVm","hintnopVm","hintnopVm",
"hintnopVm","hintnopVm","endbr*hintnopVm","hintnopVm",
--2x
"movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil,
"movapsXrm||movapdXrm",
Expand Down Expand Up @@ -804,6 +804,24 @@ map_act = {
return dispatch(ctx, map_opcvm[ctx.mrm])
end,

-- Special NOP for endbr64/endbr32.
endbr = function(ctx, name, pat)
if ctx.rep then
local pos = ctx.pos
local b = byte(ctx.code, pos)
local text
if b == 0xfa then text = "endbr64"
elseif b == 0xfb then text = "endbr64"
end
if text then
ctx.pos = pos + 1
ctx.rep = nil
return putop(ctx, text)
end
end
return dispatch(ctx, pat)
end,

-- Floating point opcode dispatch.
fp = function(ctx, name, pat)
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
Expand Down
14 changes: 14 additions & 0 deletions src/lj_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@
#elif defined(__QNX__)
#define LJ_TARGET_QNX 1
#define LUAJIT_OS LUAJIT_OS_POSIX
#elif defined(__GNU__)
#define LJ_TARGET_HURD 1
#define LUAJIT_OS LUAJIT_OS_POSIX
#else
#define LUAJIT_OS LUAJIT_OS_OTHER
#endif
Expand Down Expand Up @@ -216,6 +219,17 @@
#error "macOS requires GC64 -- don't disable it"
#endif

#if (__CET__ & 1) && defined(LUAJIT_ENABLE_CET_BR)
/*
** Control-Flow Enforcement Technique (CET) indirect branch tracking (IBT).
** This is not enabled by default because it causes a notable slowdown of
** the interpreter on all x64 CPUs, whether they have CET enabled or not.
** If your toolchain enables -fcf-protection=branch by default, you need
** to build with: make XCFLAGS=-DLUAJIT_ENABLE_CET_BR
*/
#define LJ_CET_BR 1
#endif

#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM

#define LJ_ARCH_NAME "arm"
Expand Down
3 changes: 3 additions & 0 deletions src/lj_asm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2586,6 +2586,9 @@ void lj_asm_trace(jit_State *J, GCtrace *T)
asm_head_side(as);
else
asm_head_root(as);
#if LJ_CET_BR
emit_endbr(as);
#endif
asm_phi_fixup(as);

if (J->curfinal->nins >= T->nins) { /* IR didn't grow? */
Expand Down
2 changes: 1 addition & 1 deletion src/lj_asm_arm.h
Original file line number Diff line number Diff line change
Expand Up @@ -1927,7 +1927,7 @@ static void asm_hiop(ASMState *as, IRIns *ir)
} else if ((ir-1)->o == IR_MIN || (ir-1)->o == IR_MAX) {
as->curins--; /* Always skip the loword min/max. */
if (uselo || usehi)
asm_sfpmin_max(as, ir-1, (ir-1)->o == IR_MIN ? CC_PL : CC_LE);
asm_sfpmin_max(as, ir-1, (ir-1)->o == IR_MIN ? CC_HS : CC_LS);
return;
#elif LJ_HASFFI
} else if ((ir-1)->o == IR_CONV) {
Expand Down
3 changes: 2 additions & 1 deletion src/lj_asm_x86.h
Original file line number Diff line number Diff line change
Expand Up @@ -2084,7 +2084,8 @@ static void asm_intarith(ASMState *as, IRIns *ir, x86Arith xa)
RegSet allow = RSET_GPR;
Reg dest, right;
int32_t k = 0;
if (as->flagmcp == as->mcp) { /* Drop test r,r instruction. */
if (as->flagmcp == as->mcp && xa != XOg_X_IMUL) {
/* Drop test r,r instruction. */
MCode *p = as->mcp + ((LJ_64 && *as->mcp < XI_TESTb) ? 3 : 2);
MCode *q = p[0] == 0x0f ? p+1 : p;
if ((*q & 15) < 14) {
Expand Down
5 changes: 5 additions & 0 deletions src/lj_bc.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ static LJ_AINLINE int bc_isret(BCOp op)
return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1);
}

static LJ_AINLINE int bc_isret_or_tail(BCOp op)
{
return (op == BC_CALLMT || op == BC_CALLT || bc_isret(op));
}

LJ_DATA const uint16_t lj_bc_mode[];
LJ_DATA const uint16_t lj_bc_ofs[];

Expand Down
6 changes: 3 additions & 3 deletions src/lj_bcread.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ static void bcread_ktabk(LexState *ls, TValue *o, GCtab *t)
} else if (tp == BCDUMP_KTAB_NUM) {
o->u32.lo = bcread_uleb128(ls);
o->u32.hi = bcread_uleb128(ls);
} else if (tp == BCDUMP_KTAB_NIL) { /* Restore nil value marker. */
} else if (t && tp == BCDUMP_KTAB_NIL) { /* Restore nil value marker. */
settabV(ls->L, o, t);
} else {
lj_assertLS(tp <= BCDUMP_KTAB_TRUE, "bad constant type %d", tp);
Expand All @@ -209,13 +209,13 @@ static GCtab *bcread_ktab(LexState *ls)
MSize i;
TValue *o = tvref(t->array);
for (i = 0; i < narray; i++, o++)
bcread_ktabk(ls, o, t);
bcread_ktabk(ls, o, NULL);
}
if (nhash) { /* Read hash entries. */
MSize i;
for (i = 0; i < nhash; i++) {
TValue key;
bcread_ktabk(ls, &key, t);
bcread_ktabk(ls, &key, NULL);
lj_assertLS(!tvisnil(&key), "nil key");
bcread_ktabk(ls, lj_tab_set(ls->L, t, &key), t);
}
Expand Down
39 changes: 26 additions & 13 deletions src/lj_ccall.c
Original file line number Diff line number Diff line change
Expand Up @@ -781,17 +781,24 @@ static unsigned int ccall_classify_struct(CTState *cts, CType *ct)
{
CTSize sz = ct->size;
unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION);
while (ct->sib) {
while (ct->sib && n <= 4) {
unsigned int m = 1;
CType *sct;
ct = ctype_get(cts, ct->sib);
if (ctype_isfield(ct->info)) {
sct = ctype_rawchild(cts, ct);
if (ctype_isarray(sct->info)) {
CType *cct = ctype_rawchild(cts, sct);
if (!cct->size) continue;
m = sct->size / cct->size;
sct = cct;
}
if (ctype_isfp(sct->info)) {
r |= sct->size;
if (!isu) n++; else if (n == 0) n = 1;
if (!isu) n += m; else if (n < m) n = m;
} else if (ctype_iscomplex(sct->info)) {
r |= (sct->size >> 1);
if (!isu) n += 2; else if (n < 2) n = 2;
if (!isu) n += 2*m; else if (n < 2*m) n = 2*m;
} else if (ctype_isstruct(sct->info)) {
goto substruct;
} else {
Expand All @@ -803,10 +810,11 @@ static unsigned int ccall_classify_struct(CTState *cts, CType *ct)
sct = ctype_rawchild(cts, ct);
substruct:
if (sct->size > 0) {
unsigned int s = ccall_classify_struct(cts, sct);
unsigned int s = ccall_classify_struct(cts, sct), sn;
if (s <= 1) goto noth;
r |= (s & 255);
if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8);
sn = (s >> 8) * m;
if (!isu) n += sn; else if (n < sn) n = sn;
}
}
}
Expand Down Expand Up @@ -893,7 +901,9 @@ static void ccall_copy_struct(CCallState *cc, CType *ctr, void *dp, void *sp,

/* -- Common C call handling ---------------------------------------------- */

/* Infer the destination CTypeID for a vararg argument. */
/* Infer the destination CTypeID for a vararg argument.
** Note: may reallocate cts->tab and invalidate CType pointers.
*/
CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o)
{
if (tvisnumber(o)) {
Expand Down Expand Up @@ -921,13 +931,16 @@ CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o)
}
}

/* Setup arguments for C call. */
/* Setup arguments for C call.
** Note: may reallocate cts->tab and invalidate CType pointers.
*/
static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
CCallState *cc)
{
int gcsteps = 0;
TValue *o, *top = L->top;
CTypeID fid;
CTInfo info = ct->info; /* lj_ccall_ctid_vararg may invalidate ct pointer. */
CType *ctr;
MSize maxgpr, ngpr = 0, nsp = 0, narg;
#if CCALL_NARG_FPR
Expand All @@ -946,7 +959,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
#if LJ_TARGET_X86
/* x86 has several different calling conventions. */
cc->resx87 = 0;
switch (ctype_cconv(ct->info)) {
switch (ctype_cconv(info)) {
case CTCC_FASTCALL: maxgpr = 2; break;
case CTCC_THISCALL: maxgpr = 1; break;
default: maxgpr = 0; break;
Expand All @@ -963,7 +976,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
} else if (ctype_iscomplex(ctr->info) || ctype_isstruct(ctr->info)) {
/* Preallocate cdata object and anchor it after arguments. */
CTSize sz = ctr->size;
GCcdata *cd = lj_cdata_new(cts, ctype_cid(ct->info), sz);
GCcdata *cd = lj_cdata_new(cts, ctype_cid(info), sz);
void *dp = cdataptr(cd);
setcdataV(L, L->top++, cd);
if (ctype_isstruct(ctr->info)) {
Expand All @@ -986,7 +999,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
}

#if LJ_TARGET_ARM64 && LJ_ABI_WIN
if ((ct->info & CTF_VARARG)) {
if ((info & CTF_VARARG)) {
nsp -= maxgpr * CTSIZE_PTR; /* May end up with negative nsp. */
ngpr = maxgpr;
nfpr = CCALL_NARG_FPR;
Expand All @@ -1007,7 +1020,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
lj_assertL(ctype_isfield(ctf->info), "field expected");
did = ctype_cid(ctf->info);
} else {
if (!(ct->info & CTF_VARARG))
if (!(info & CTF_VARARG))
lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too many arguments. */
did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */
isva = 1;
Expand Down Expand Up @@ -1178,19 +1191,19 @@ int lj_ccall_func(lua_State *L, GCcdata *cd)
ct = ctype_rawchild(cts, ct);
}
if (ctype_isfunc(ct->info)) {
CTypeID id = ctype_typeid(cts, ct);
CCallState cc;
int gcsteps, ret;
cc.func = (void (*)(void))cdata_getptr(cdataptr(cd), sz);
gcsteps = ccall_set_args(L, cts, ct, &cc);
ct = (CType *)((intptr_t)ct-(intptr_t)cts->tab);
cts->cb.slot = ~0u;
lj_vm_ffi_call(&cc);
if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */
TValue tv;
tv.u64 = ((uintptr_t)(void *)cc.func >> 2) | U64x(800000000, 00000000);
setboolV(lj_tab_set(L, cts->miscmap, &tv), 1);
}
ct = (CType *)((intptr_t)ct+(intptr_t)cts->tab); /* May be reallocated. */
ct = ctype_get(cts, id); /* Table may have been reallocated. */
gcsteps += ccall_get_results(L, cts, ct, &cc, &ret);
#if LJ_TARGET_X86 && LJ_ABI_WIN
/* Automatically detect __stdcall and fix up C function declaration. */
Expand Down
2 changes: 1 addition & 1 deletion src/lj_ccallback.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ static void *callback_mcode_init(global_State *g, uint32_t *page)
#endif

/* Check for macOS hardened runtime. */
#if LUAJIT_SECURITY_MCODE != 0 && defined(MAP_JIT) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 110000
#if defined(LUAJIT_ENABLE_OSX_HRT) && LUAJIT_SECURITY_MCODE != 0 && defined(MAP_JIT) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 110000
#include <pthread.h>
#define CCMAP_CREATE MAP_JIT
#else
Expand Down
32 changes: 19 additions & 13 deletions src/lj_crecord.c
Original file line number Diff line number Diff line change
Expand Up @@ -1101,12 +1101,15 @@ static void crec_alloc(jit_State *J, RecordFFData *rd, CTypeID id)
crec_finalizer(J, trcd, 0, fin);
}

/* Record argument conversions. */
/* Record argument conversions.
** Note: may reallocate cts->tab and invalidate CType pointers.
*/
static TRef crec_call_args(jit_State *J, RecordFFData *rd,
CTState *cts, CType *ct)
{
TRef args[CCI_NARGS_MAX];
CTypeID fid;
CTInfo info = ct->info; /* lj_ccall_ctid_vararg may invalidate ct pointer. */
MSize i, n;
TRef tr, *base;
cTValue *o;
Expand All @@ -1115,9 +1118,9 @@ static TRef crec_call_args(jit_State *J, RecordFFData *rd,
TRef *arg0 = NULL, *arg1 = NULL;
#endif
int ngpr = 0;
if (ctype_cconv(ct->info) == CTCC_THISCALL)
if (ctype_cconv(info) == CTCC_THISCALL)
ngpr = 1;
else if (ctype_cconv(ct->info) == CTCC_FASTCALL)
else if (ctype_cconv(info) == CTCC_FASTCALL)
ngpr = 2;
#elif LJ_TARGET_ARM64 && LJ_TARGET_OSX
int ngpr = CCALL_NARG_GPR;
Expand All @@ -1144,7 +1147,7 @@ static TRef crec_call_args(jit_State *J, RecordFFData *rd,
lj_assertJ(ctype_isfield(ctf->info), "field expected");
did = ctype_cid(ctf->info);
} else {
if (!(ct->info & CTF_VARARG))
if (!(info & CTF_VARARG))
lj_trace_err(J, LJ_TRERR_NYICALL); /* Too many arguments. */
#if LJ_TARGET_ARM64 && LJ_TARGET_OSX
if (ngpr >= 0) {
Expand Down Expand Up @@ -1248,37 +1251,40 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd)
{
CTState *cts = ctype_ctsG(J2G(J));
CType *ct = ctype_raw(cts, cd->ctypeid);
CTInfo info;
IRType tp = IRT_PTR;
if (ctype_isptr(ct->info)) {
tp = (LJ_64 && ct->size == 8) ? IRT_P64 : IRT_P32;
ct = ctype_rawchild(cts, ct);
}
if (ctype_isfunc(ct->info)) {
info = ct->info; /* crec_call_args may invalidate ct pointer. */
if (ctype_isfunc(info)) {
TRef func = emitir(IRT(IR_FLOAD, tp), J->base[0], IRFL_CDATA_PTR);
CType *ctr = ctype_rawchild(cts, ct);
CTInfo ctr_info = ctr->info; /* crec_call_args may invalidate ctr. */
IRType t = crec_ct2irt(cts, ctr);
TRef tr;
TValue tv;
/* Check for blacklisted C functions that might call a callback. */
tv.u64 = ((uintptr_t)cdata_getptr(cdataptr(cd), (LJ_64 && tp == IRT_P64) ? 8 : 4) >> 2) | U64x(800000000, 00000000);
if (tvistrue(lj_tab_get(J->L, cts->miscmap, &tv)))
lj_trace_err(J, LJ_TRERR_BLACKL);
if (ctype_isvoid(ctr->info)) {
if (ctype_isvoid(ctr_info)) {
t = IRT_NIL;
rd->nres = 0;
} else if (!(ctype_isnum(ctr->info) || ctype_isptr(ctr->info) ||
ctype_isenum(ctr->info)) || t == IRT_CDATA) {
} else if (!(ctype_isnum(ctr_info) || ctype_isptr(ctr_info) ||
ctype_isenum(ctr_info)) || t == IRT_CDATA) {
lj_trace_err(J, LJ_TRERR_NYICALL);
}
if ((ct->info & CTF_VARARG)
if ((info & CTF_VARARG)
#if LJ_TARGET_X86
|| ctype_cconv(ct->info) != CTCC_CDECL
|| ctype_cconv(info) != CTCC_CDECL
#endif
)
func = emitir(IRT(IR_CARG, IRT_NIL), func,
lj_ir_kint(J, ctype_typeid(cts, ct)));
tr = emitir(IRT(IR_CALLXS, t), crec_call_args(J, rd, cts, ct), func);
if (ctype_isbool(ctr->info)) {
if (ctype_isbool(ctr_info)) {
if (frame_islua(J->L->base-1) && bc_b(frame_pc(J->L->base-1)[-1]) == 1) {
/* Don't check result if ignored. */
tr = TREF_NIL;
Expand All @@ -1294,8 +1300,8 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd)
tr = TREF_TRUE;
}
} else if (t == IRT_PTR || (LJ_64 && t == IRT_P32) ||
t == IRT_I64 || t == IRT_U64 || ctype_isenum(ctr->info)) {
TRef trid = lj_ir_kint(J, ctype_cid(ct->info));
t == IRT_I64 || t == IRT_U64 || ctype_isenum(ctr_info)) {
TRef trid = lj_ir_kint(J, ctype_cid(info));
tr = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, tr);
if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J);
} else if (t == IRT_FLOAT || t == IRT_U32) {
Expand Down
Loading