Compare commits

...

17 Commits

Author SHA1 Message Date
Ilya Leoshkevich
4feefef7e1
Merge 6a079a441b into e3c70a7d81 2025-03-10 09:46:04 +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
Mike Pall
f14556234c Merge branch 'master' into v2.1 2025-03-09 16:25:34 +01:00
Mike Pall
d508715ab6 Add compatibility string coercion for fp:seek() argument.
Reported by Magnus Wibeck. #1343
2025-03-09 16:21:29 +01:00
Mike Pall
e27ee68817 Windows: Clarify installation directory layout.
Suggested by eabase. #1346
2025-03-09 16:10:22 +01:00
Mike Pall
55a42da36e Remove Cygwin from docs, since it's not a supported target. 2025-03-09 16:09:36 +01:00
Mike Pall
423ac2144b Improve CLI signal handling on POSIX. 2025-03-09 15:50:01 +01:00
Mike Pall
54dc2fa5d7 FFI: Add pre-declared int128_t, uint128_t, __int128 types.
Note: Only declaration and copy (interpreted only) are implemented.
2025-03-09 15:37:35 +01:00
Mike Pall
b1179ea5f7 Use dylib extension for iOS installs, too.
Reported by Andrey Filipenkov. #1336
2025-03-09 15:00:15 +01:00
Mike Pall
5eb9509468 Change handling of nil value markers in template tables.
Reported by Bernhard M. Wiedemann. #1348 #1155
2025-03-09 14:44:57 +01:00
Ilya Leoshkevich
6a079a441b FFI: Support VLA function parameters
glibc 2.39's regex.h contains the following declaration:

    extern int regexec (const regex_t *_Restrict_ __preg,
                        const char *_Restrict_ __String, size_t __nmatch,
                        regmatch_t __pmatch[_Restrict_arr_
                                            _REGEX_NELTS (__nmatch)],
                        int __eflags);

__pmatch is a VLA, which LuaJIT currently cannot parse. Implement
parsing VLA function parameters as follows:

- Allow parsing CT_FIELD identifiers. Long-term it's probably better to
  define a new CT_* constant to avoid mix-ups, but currently struct
  fields are not added to the hash, so in this context CT_FIELD is
  guaranteed to be a function parameter.
- Allow function parameter lists to reference CT_FIELD ctypes (function
  parameters are CT_FIELDs).
- Add function parameters to the hash table as they are being parsed;
  remove them after the function parameter list is parsed, since they
  go out of scope.
- Mark CPValues that are compile-time constants using the new "imm"
  flag. Integer literals and enum members are compile-time constants;
  arithmetic operations propagate this property if all operands are
  compile-time constants.
- Distinguish array sizes that are compile-time constants from those
  that are not. Treat variable sizes as CTSIZE_INVALID.
2024-11-12 21:33:52 +01:00
20 changed files with 225 additions and 102 deletions

View File

@ -110,7 +110,7 @@ else
endif
TARGET_SYS?= $(HOST_SYS)
ifeq (Darwin,$(TARGET_SYS))
ifneq (,$(filter $(TARGET_SYS),Darwin iOS))
INSTALL_SONAME= $(INSTALL_DYLIBNAME)
INSTALL_SOSHORT1= $(INSTALL_DYLIBSHORT1)
INSTALL_SOSHORT2= $(INSTALL_DYLIBSHORT2)

View File

@ -117,7 +117,7 @@ hold all user-configurable settings:
<li><tt>Makefile</tt> has settings for <b>installing</b> LuaJIT (POSIX
only).</li>
<li><tt>src/Makefile</tt> has settings for <b>compiling</b> LuaJIT
under POSIX, MinGW or Cygwin.</li>
under POSIX or MinGW.</li>
<li><tt>src/msvcbuild.bat</tt> has settings for compiling LuaJIT with
MSVC (Visual Studio).</li>
</ul>
@ -195,10 +195,8 @@ Obviously the prefixes given during build and installation need to be the same.
<h2 id="windows">Windows Systems</h2>
<h3>Prerequisites</h3>
<p>
Either install one of the open source SDKs
(<a href="http://mingw.org/"><span class="ext">&raquo;</span>&nbsp;MinGW</a> or
<a href="https://www.cygwin.com/"><span class="ext">&raquo;</span>&nbsp;Cygwin</a>), which come with a modified
GCC plus the required development headers.
Either install the open source SDK <a href="http://mingw.org/"><span class="ext">&raquo;</span>&nbsp;MinGW</a>,
which comes with a modified GCC plus the required development headers.
Or install Microsoft's Visual Studio (MSVC).
</p>
<h3>Building with MSVC</h3>
@ -217,9 +215,9 @@ Then follow the installation instructions below.
<p>
For an x64 to ARM64 cross-build run this first: <tt>vcvarsall.bat x64_arm64</tt>
</p>
<h3>Building with MinGW or Cygwin</h3>
<h3>Building with MinGW</h3>
<p>
Open a command prompt window and make sure the MinGW or Cygwin programs
Open a command prompt window and make sure the MinGW programs
are in your path. Then <tt>cd</tt> to the directory of the git repository.
Then run this command for MinGW:
</p>
@ -227,12 +225,6 @@ Then run this command for MinGW:
mingw32-make
</pre>
<p>
Or this command for Cygwin:
</p>
<pre class="code">
make
</pre>
<p>
Then follow the installation instructions below.
</p>
<h3>Installing LuaJIT</h3>
@ -249,6 +241,19 @@ absolute path names &mdash; all modules are loaded relative to the
directory where <tt>luajit.exe</tt> is installed
(see <tt>src/luaconf.h</tt>).
</p>
<p>
The final directory layout should look like this:
</p>
<pre class="code">
├── luajit.exe
├── lua51.dll
├── <- put your own classic Lua/C API modules (*.dll) here
└── lua
├── <- put your own Lua modules (*.lua) here
└── jit
├── bc.lua
└── (etc …)
</pre>
<h2 id="cross">Cross-compiling LuaJIT</h2>
<p>

View File

@ -25,7 +25,7 @@ lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_state.h \
lj_strfmt.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
lj_strfmt.h lj_ff.h lj_ffdef.h lj_lib.h lj_strscan.h lj_libdef.h
lib_jit.o: lib_jit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h \
lj_state.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \

View File

@ -25,6 +25,7 @@
#include "lj_strfmt.h"
#include "lj_ff.h"
#include "lj_lib.h"
#include "lj_strscan.h"
/* Userdata payload for I/O file. */
typedef struct IOFileUD {
@ -323,13 +324,14 @@ LJLIB_CF(io_method_seek)
FILE *fp = io_tofile(L)->fp;
int opt = lj_lib_checkopt(L, 2, 1, "\3set\3cur\3end");
int64_t ofs = 0;
cTValue *o;
TValue *o;
int res;
if (opt == 0) opt = SEEK_SET;
else if (opt == 1) opt = SEEK_CUR;
else if (opt == 2) opt = SEEK_END;
o = L->base+2;
if (o < L->top) {
if (tvisstr(o)) lj_strscan_num(strV(o), o);
if (tvisint(o))
ofs = (int64_t)intV(o);
else if (tvisnum(o))

View File

@ -179,7 +179,7 @@ static const void *bcread_varinfo(GCproto *pt)
}
/* Read a single constant key/value of a template table. */
static void bcread_ktabk(LexState *ls, TValue *o)
static void bcread_ktabk(LexState *ls, TValue *o, GCtab *t)
{
MSize tp = bcread_uleb128(ls);
if (tp >= BCDUMP_KTAB_STR) {
@ -191,6 +191,8 @@ static void bcread_ktabk(LexState *ls, TValue *o)
} 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. */
settabV(ls->L, o, t);
} else {
lj_assertLS(tp <= BCDUMP_KTAB_TRUE, "bad constant type %d", tp);
setpriV(o, ~tp);
@ -207,15 +209,15 @@ static GCtab *bcread_ktab(LexState *ls)
MSize i;
TValue *o = tvref(t->array);
for (i = 0; i < narray; i++, o++)
bcread_ktabk(ls, o);
bcread_ktabk(ls, o, t);
}
if (nhash) { /* Read hash entries. */
MSize i;
for (i = 0; i < nhash; i++) {
TValue key;
bcread_ktabk(ls, &key);
bcread_ktabk(ls, &key, t);
lj_assertLS(!tvisnil(&key), "nil key");
bcread_ktabk(ls, lj_tab_set(ls->L, t, &key));
bcread_ktabk(ls, lj_tab_set(ls->L, t, &key), t);
}
}
return t;

View File

@ -71,6 +71,8 @@ static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow)
*p++ = BCDUMP_KTAB_NUM;
p = lj_strfmt_wuleb128(p, o->u32.lo);
p = lj_strfmt_wuleb128(p, o->u32.hi);
} else if (tvistab(o)) { /* Write the nil value marker as a nil. */
*p++ = BCDUMP_KTAB_NIL;
} else {
lj_assertBCW(tvispri(o), "unhandled type %d", itype(o));
*p++ = BCDUMP_KTAB_NIL+~itype(o);
@ -133,7 +135,7 @@ static void bcwrite_ktab_sorted_hash(BCWriteCtx *ctx, Node *node, MSize nhash)
TValue **heap = ctx->heap;
MSize i = nhash;
for (;; node--) { /* Build heap. */
if (!tvisnil(&node->key)) {
if (!tvisnil(&node->val)) {
bcwrite_ktabk_heap_insert(heap, --i, nhash, &node->key);
if (i == 0) break;
}
@ -163,7 +165,7 @@ static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
MSize i, hmask = t->hmask;
Node *node = noderef(t->node);
for (i = 0; i <= hmask; i++)
nhash += !tvisnil(&node[i].key);
nhash += !tvisnil(&node[i].val);
}
/* Write number of array slots and hash slots. */
p = lj_strfmt_wuleb128(p, narray);
@ -184,7 +186,7 @@ static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
} else {
MSize i = nhash;
for (;; node--)
if (!tvisnil(&node->key)) {
if (!tvisnil(&node->val)) {
bcwrite_ktabk(ctx, &node->key, 0);
bcwrite_ktabk(ctx, &node->val, 1);
if (--i == 0) break;

View File

@ -262,6 +262,14 @@ static void *callback_mcode_init(global_State *g, uint32_t *page)
#define CCPROT_CREATE 0
#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
/* Allocate and initialize area for callback function pointers. */
@ -276,10 +284,13 @@ static void callback_mcode_new(CTState *cts)
if (!p)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#elif LJ_TARGET_POSIX
p = mmap(NULL, sz, (PROT_READ|PROT_WRITE|CCPROT_CREATE), MAP_PRIVATE|MAP_ANONYMOUS,
-1, 0);
p = mmap(NULL, sz, PROT_READ|PROT_WRITE|CCPROT_CREATE,
MAP_PRIVATE|MAP_ANONYMOUS|CCMAP_CREATE, -1, 0);
if (p == MAP_FAILED)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#if CCMAP_CREATE
pthread_jit_write_protect_np(0);
#endif
#else
/* Fallback allocator. Fails if memory is not executable by default. */
p = lj_mem_new(cts->L, sz);
@ -296,8 +307,12 @@ static void callback_mcode_new(CTState *cts)
LJ_WIN_VPROTECT(p, sz, PAGE_EXECUTE_READ, &oprot);
}
#elif LJ_TARGET_POSIX
#if CCMAP_CREATE
pthread_jit_write_protect_np(1);
#else
mprotect(p, sz, (PROT_READ|PROT_EXEC));
#endif
#endif
}
/* Free area for callback function pointers. */

View File

@ -182,6 +182,7 @@ static CPToken cp_number(CPState *cp)
else if (!(cp->mode & CPARSE_MODE_SKIP))
cp_errmsg(cp, CTOK_INTEGER, LJ_ERR_XNUMBER);
cp->val.u32 = (uint32_t)o.i;
cp->val.imm = 1;
return CTOK_INTEGER;
}
@ -191,6 +192,7 @@ static CPToken cp_ident(CPState *cp)
do { cp_save(cp, cp->c); } while (lj_char_isident(cp_get(cp)));
cp->str = lj_buf_str(cp->L, &cp->sb);
cp->val.id = lj_ctype_getname(cp->cts, &cp->ct, cp->str, cp->tmask);
cp->val.imm = 0;
if (ctype_type(cp->ct->info) == CT_KW)
return ctype_cid(cp->ct->info);
return CTOK_IDENT;
@ -209,11 +211,13 @@ static CPToken cp_param(CPState *cp)
if (tvisstr(o)) {
cp->str = strV(o);
cp->val.id = 0;
cp->val.imm = 0;
cp->ct = &cp->cts->tab[0];
return CTOK_IDENT;
} else if (tvisnumber(o)) {
cp->val.i32 = numberVint(o);
cp->val.id = CTID_INT32;
cp->val.imm = 1;
return CTOK_INTEGER;
} else {
GCcdata *cd;
@ -224,6 +228,7 @@ static CPToken cp_param(CPState *cp)
cp->val.id = *(CTypeID *)cdataptr(cd);
else
cp->val.id = cd->ctypeid;
cp->val.imm = 0;
return '$';
}
}
@ -281,6 +286,7 @@ static CPToken cp_string(CPState *cp)
if (sbuflen(&cp->sb) != 1) cp_err_token(cp, '\'');
cp->val.i32 = (int32_t)(char)*cp->sb.b;
cp->val.id = CTID_INT32;
cp->val.imm = 1;
return CTOK_INTEGER;
}
}
@ -478,6 +484,7 @@ static void cp_expr_sizeof(CPState *cp, CPValue *k, int wantsz)
k->u32 = 1u << ctype_align(info);
}
k->id = CTID_UINT32; /* Really size_t. */
k->imm = 1;
}
/* Parse prefix operators. */
@ -509,22 +516,25 @@ static void cp_expr_prefix(CPState *cp, CPValue *k)
ct = lj_ctype_rawref(cp->cts, k->id);
if (!ctype_ispointer(ct->info))
cp_err_badidx(cp, ct);
k->u32 = 0; k->id = ctype_cid(ct->info);
k->u32 = 0; k->id = ctype_cid(ct->info); k->imm = 0;
} else if (cp_opt(cp, '&')) { /* Address operator. */
cp_expr_unary(cp, k);
k->id = lj_ctype_intern(cp->cts, CTINFO(CT_PTR, CTALIGN_PTR+k->id),
CTSIZE_PTR);
k->imm = 0;
} else if (cp_opt(cp, CTOK_SIZEOF)) {
cp_expr_sizeof(cp, k, 1);
} else if (cp_opt(cp, CTOK_ALIGNOF)) {
cp_expr_sizeof(cp, k, 0);
} else if (cp->tok == CTOK_IDENT) {
if (ctype_type(cp->ct->info) == CT_CONSTVAL) {
k->u32 = cp->ct->size; k->id = ctype_cid(cp->ct->info);
k->u32 = cp->ct->size; k->id = ctype_cid(cp->ct->info); k->imm = 1;
} else if (ctype_type(cp->ct->info) == CT_EXTERN) {
k->u32 = cp->val.id; k->id = ctype_cid(cp->ct->info);
k->u32 = cp->val.id; k->id = ctype_cid(cp->ct->info); k->imm = 0;
} else if (ctype_type(cp->ct->info) == CT_FUNC) {
k->u32 = cp->val.id; k->id = cp->val.id;
k->u32 = cp->val.id; k->id = cp->val.id; k->imm = 0;
} else if (ctype_type(cp->ct->info) == CT_FIELD) {
k->u32 = cp->ct->size; k->id = ctype_cid(cp->ct->info); k->imm = 0;
} else {
goto err_expr;
}
@ -535,6 +545,7 @@ static void cp_expr_prefix(CPState *cp, CPValue *k)
sz += cp->str->len;
k->u32 = sz + 1;
k->id = CTID_A_CCHAR;
k->imm = 0;
} else {
err_expr:
cp_errmsg(cp, cp->tok, LJ_ERR_XSYMBOL);
@ -557,6 +568,7 @@ static void cp_expr_postfix(CPState *cp, CPValue *k)
}
cp_check(cp, ']');
k->u32 = 0;
k->imm = 0;
} else if (cp->tok == '.' || cp->tok == CTOK_DEREF) { /* Struct deref. */
CTSize ofs;
CType *fct;
@ -575,7 +587,8 @@ static void cp_expr_postfix(CPState *cp, CPValue *k)
cp_errmsg(cp, 0, LJ_ERR_FFI_BADMEMBER, strdata(s), strdata(cp->str));
}
ct = fct;
k->u32 = ctype_isconstval(ct->info) ? ct->size : 0;
k->imm = ctype_isconstval(ct->info);
k->u32 = k->imm ? ct->size : 0;
cp_next(cp);
} else {
return;
@ -599,19 +612,20 @@ static void cp_expr_infix(CPState *cp, CPValue *k, int pri)
cp_expr_sub(cp, &k3, 0);
k->u32 = k->u32 ? k2.u32 : k3.u32;
k->id = k2.id > k3.id ? k2.id : k3.id;
k->imm = k->imm && (k->u32 ? k2.imm : k3.imm);
continue;
}
/* fallthrough */
case 1:
if (cp_opt(cp, CTOK_OROR)) {
cp_expr_sub(cp, &k2, 2); k->i32 = k->u32 || k2.u32; k->id = CTID_INT32;
continue;
goto arith_imm;
}
/* fallthrough */
case 2:
if (cp_opt(cp, CTOK_ANDAND)) {
cp_expr_sub(cp, &k2, 3); k->i32 = k->u32 && k2.u32; k->id = CTID_INT32;
continue;
goto arith_imm;
}
/* fallthrough */
case 3:
@ -632,10 +646,10 @@ static void cp_expr_infix(CPState *cp, CPValue *k, int pri)
case 6:
if (cp_opt(cp, CTOK_EQ)) {
cp_expr_sub(cp, &k2, 7); k->i32 = k->u32 == k2.u32; k->id = CTID_INT32;
continue;
goto arith_imm;
} else if (cp_opt(cp, CTOK_NE)) {
cp_expr_sub(cp, &k2, 7); k->i32 = k->u32 != k2.u32; k->id = CTID_INT32;
continue;
goto arith_imm;
}
/* fallthrough */
case 7:
@ -646,7 +660,7 @@ static void cp_expr_infix(CPState *cp, CPValue *k, int pri)
else
k->i32 = k->u32 < k2.u32;
k->id = CTID_INT32;
continue;
goto arith_imm;
} else if (cp_opt(cp, '>')) {
cp_expr_sub(cp, &k2, 8);
if (k->id == CTID_INT32 && k2.id == CTID_INT32)
@ -654,7 +668,7 @@ static void cp_expr_infix(CPState *cp, CPValue *k, int pri)
else
k->i32 = k->u32 > k2.u32;
k->id = CTID_INT32;
continue;
goto arith_imm;
} else if (cp_opt(cp, CTOK_LE)) {
cp_expr_sub(cp, &k2, 8);
if (k->id == CTID_INT32 && k2.id == CTID_INT32)
@ -662,7 +676,7 @@ static void cp_expr_infix(CPState *cp, CPValue *k, int pri)
else
k->i32 = k->u32 <= k2.u32;
k->id = CTID_INT32;
continue;
goto arith_imm;
} else if (cp_opt(cp, CTOK_GE)) {
cp_expr_sub(cp, &k2, 8);
if (k->id == CTID_INT32 && k2.id == CTID_INT32)
@ -670,20 +684,20 @@ static void cp_expr_infix(CPState *cp, CPValue *k, int pri)
else
k->i32 = k->u32 >= k2.u32;
k->id = CTID_INT32;
continue;
goto arith_imm;
}
/* fallthrough */
case 8:
if (cp_opt(cp, CTOK_SHL)) {
cp_expr_sub(cp, &k2, 9); k->u32 = k->u32 << k2.u32;
continue;
goto arith_imm;
} else if (cp_opt(cp, CTOK_SHR)) {
cp_expr_sub(cp, &k2, 9);
if (k->id == CTID_INT32)
k->i32 = k->i32 >> k2.i32;
else
k->u32 = k->u32 >> k2.u32;
continue;
goto arith_imm;
}
/* fallthrough */
case 9:
@ -691,6 +705,8 @@ static void cp_expr_infix(CPState *cp, CPValue *k, int pri)
cp_expr_sub(cp, &k2, 10); k->u32 = k->u32 + k2.u32;
arith_result:
if (k2.id > k->id) k->id = k2.id; /* Trivial promotion to unsigned. */
arith_imm:
k->imm = k->imm && k2.imm;
continue;
} else if (cp_opt(cp, '-')) {
cp_expr_sub(cp, &k2, 10); k->u32 = k->u32 - k2.u32; goto arith_result;
@ -702,6 +718,7 @@ static void cp_expr_infix(CPState *cp, CPValue *k, int pri)
} else if (cp_opt(cp, '/')) {
cp_expr_unary(cp, &k2);
if (k2.id > k->id) k->id = k2.id; /* Trivial promotion to unsigned. */
if (k->imm && k2.imm) {
if (k2.u32 == 0 ||
(k->id == CTID_INT32 && k->u32 == 0x80000000u && k2.i32 == -1))
cp_err(cp, LJ_ERR_BADVAL);
@ -709,10 +726,12 @@ static void cp_expr_infix(CPState *cp, CPValue *k, int pri)
k->i32 = k->i32 / k2.i32;
else
k->u32 = k->u32 / k2.u32;
continue;
}
goto arith_imm;
} else if (cp_opt(cp, '%')) {
cp_expr_unary(cp, &k2);
if (k2.id > k->id) k->id = k2.id; /* Trivial promotion to unsigned. */
if (k->imm && k2.imm) {
if (k2.u32 == 0 ||
(k->id == CTID_INT32 && k->u32 == 0x80000000u && k2.i32 == -1))
cp_err(cp, LJ_ERR_BADVAL);
@ -720,7 +739,8 @@ static void cp_expr_infix(CPState *cp, CPValue *k, int pri)
k->i32 = k->i32 % k2.i32;
else
k->u32 = k->u32 % k2.u32;
continue;
}
goto arith_imm;
}
default:
return;
@ -750,7 +770,7 @@ static void cp_expr_kint(CPState *cp, CPValue *k)
CType *ct;
cp_expr_sub(cp, k, 0);
ct = ctype_raw(cp->cts, k->id);
if (!ctype_isinteger(ct->info)) cp_err(cp, LJ_ERR_BADVAL);
if (!ctype_isinteger(ct->info) || !k->imm) cp_err(cp, LJ_ERR_BADVAL);
}
/* Parse (non-negative) size expression. */
@ -1447,6 +1467,7 @@ static CTypeID cp_decl_enum(CPState *cp, CPDecl *sdecl)
CTypeID lastid = eid;
k.u32 = 0;
k.id = CTID_INT32;
k.imm = 1;
do {
GCstr *name = cp->str;
if (cp->tok != CTOK_IDENT) cp_err_token(cp, CTOK_IDENT);
@ -1610,10 +1631,26 @@ static void cp_decl_array(CPState *cp, CPDecl *decl)
CTInfo info = CTINFO(CT_ARRAY, 0);
CTSize nelem = CTSIZE_INVALID; /* Default size for a[] or a[?]. */
cp_decl_attributes(cp, decl);
if (cp_opt(cp, '?'))
if (cp_opt(cp, '?')) {
info |= CTF_VLA; /* Create variable-length array a[?]. */
else if (cp->tok != ']')
nelem = cp_expr_ksize(cp);
} else if (cp->tok != ']') {
CPValue k;
CType *ct;
cp_expr_sub(cp, &k, 0);
ct = ctype_raw(cp->cts, k.id);
if (ctype_isinteger(ct->info)) {
if (k.imm) {
if (k.u32 < 0x80000000u)
nelem = k.u32;
else
cp_err(cp, LJ_ERR_FFI_INVSIZE);
} else {
info |= CTF_VLA;
}
} else {
cp_err(cp, LJ_ERR_BADVAL);
}
}
cp_check(cp, ']');
cp_add(decl, info, nelem);
}
@ -1623,11 +1660,13 @@ static void cp_decl_func(CPState *cp, CPDecl *fdecl)
{
CTSize nargs = 0;
CTInfo info = CTINFO(CT_FUNC, 0);
CTypeID lastid = 0, anchor = 0;
CTypeID lastid = 0, anchor = 0, fieldid;
uint32_t oldtmask = cp->tmask;
cp->tmask |= (1 << CT_FIELD); /* Allow referencing parameters. */
if (cp->tok != ')') {
do {
CPDecl decl;
CTypeID ctypeid, fieldid;
CTypeID ctypeid;
CType *ct;
if (cp_opt(cp, '.')) { /* Vararg function. */
cp_check(cp, '.'); /* Workaround for the minimalistic lexer. */
@ -1658,8 +1697,14 @@ static void cp_decl_func(CPState *cp, CPDecl *fdecl)
if (decl.name) ctype_setname(ct, decl.name);
ct->info = CTINFO(CT_FIELD, ctypeid);
ct->size = nargs++;
lj_ctype_addname(cp->cts, ct, fieldid);
} while (cp_opt(cp, ','));
}
/* Parameters went out of scope. */
cp->tmask = oldtmask;
for (fieldid = anchor; fieldid; fieldid = ctype_get(cp->cts, fieldid)->sib) {
lj_ctype_deltype(cp->cts, fieldid);
}
cp_check(cp, ')');
if (cp_opt(cp, '{')) { /* Skip function definition. */
int level = 1;
@ -1893,6 +1938,7 @@ static void cp_decl_single(CPState *cp)
cp_decl_spec(cp, &decl, 0);
cp_declarator(cp, &decl);
cp->val.id = cp_decl_intern(cp, &decl);
cp->val.imm = 0;
if (cp->tok != CTOK_EOF) cp_err_token(cp, CTOK_EOF);
}

View File

@ -35,6 +35,7 @@ typedef struct CPValue {
uint32_t u32; /* Value for CTID_UINT32. */
};
CTypeID id; /* C Type ID of the value. */
unsigned imm : 1; /* Value is a compile-time constant. */
} CPValue;
/* C parser state. */

View File

@ -33,10 +33,12 @@
_("int16_t", INT16) \
_("int32_t", INT32) \
_("int64_t", INT64) \
_("int128_t", INT128) \
_("uint8_t", UINT8) \
_("uint16_t", UINT16) \
_("uint32_t", UINT32) \
_("uint64_t", UINT64) \
_("uint128_t", UINT128) \
_("intptr_t", INT_PSZ) \
_("uintptr_t", UINT_PSZ) \
/* From POSIX. */ \
@ -55,6 +57,7 @@
_("__int16", 2, CTOK_INT) \
_("__int32", 4, CTOK_INT) \
_("__int64", 8, CTOK_INT) \
_("__int128", 16, CTOK_INT) \
_("float", 4, CTOK_FP) \
_("double", 8, CTOK_FP) \
_("long", 0, CTOK_LONG) \
@ -232,6 +235,20 @@ void lj_ctype_addname(CTState *cts, CType *ct, CTypeID id)
cts->hash[h] = (CTypeID1)id;
}
/* Remove type element from hash table. */
void lj_ctype_deltype(CTState *cts, CTypeID id)
{
CType *ct = ctype_get(cts, id);
uint32_t h = ct_hashname(gcref(ct->name));
CTypeID1 *next = &cts->hash[h];
while (1) {
lj_assertCTS(*next, "ctype not in hash");
if (*next == id) break;
next = &ctype_get(cts, *next)->next;
}
*next = ct->next;
}
/* Get a C type by name, matching the type mask. */
CTypeID lj_ctype_getname(CTState *cts, CType **ctp, GCstr *name, uint32_t tmask)
{

View File

@ -292,6 +292,8 @@ typedef struct CTState {
_(UINT32, 4, CT_NUM, CTF_UNSIGNED|CTALIGN(2)) \
_(INT64, 8, CT_NUM, CTF_LONG_IF8|CTALIGN(3)) \
_(UINT64, 8, CT_NUM, CTF_UNSIGNED|CTF_LONG_IF8|CTALIGN(3)) \
_(INT128, 16, CT_NUM, CTALIGN(4)) \
_(UINT128, 16, CT_NUM, CTF_UNSIGNED|CTALIGN(4)) \
_(FLOAT, 4, CT_NUM, CTF_FP|CTALIGN(2)) \
_(DOUBLE, 8, CT_NUM, CTF_FP|CTALIGN(3)) \
_(COMPLEX_FLOAT, 8, CT_ARRAY, CTF_COMPLEX|CTALIGN(2)|CTID_FLOAT) \
@ -459,6 +461,7 @@ static LJ_AINLINE void ctype_setname(CType *ct, GCstr *s)
LJ_FUNC CTypeID lj_ctype_new(CTState *cts, CType **ctp);
LJ_FUNC CTypeID lj_ctype_intern(CTState *cts, CTInfo info, CTSize size);
LJ_FUNC void lj_ctype_addname(CTState *cts, CType *ct, CTypeID id);
LJ_FUNC void lj_ctype_deltype(CTState *cts, CTypeID id);
LJ_FUNC CTypeID lj_ctype_getname(CTState *cts, CType **ctp, GCstr *name,
uint32_t tmask);
LJ_FUNC CType *lj_ctype_getfieldq(CTState *cts, CType *ct, GCstr *name,

View File

@ -98,6 +98,14 @@ static int mcode_setprot(void *p, size_t sz, DWORD prot)
#define MAP_ANONYMOUS MAP_ANON
#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_RX (PROT_READ|PROT_EXEC)
#define MCPROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC)
@ -109,10 +117,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)
{
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 (!hint) lj_trace_err(J, LJ_TRERR_MCODEAL);
p = NULL;
#if MCMAP_CREATE
} else {
pthread_jit_write_protect_np(0);
#endif
}
return p;
}
@ -125,7 +137,12 @@ static void mcode_free(jit_State *J, void *p, size_t sz)
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);
#endif
}
#else

View File

@ -2217,9 +2217,11 @@ LJFOLD(HREF TDUP KNUM)
LJFOLDF(fwd_href_tdup)
{
TValue keyv;
cTValue *val;
lj_ir_kvalue(J->L, &keyv, fright);
if (lj_tab_get(J->L, ir_ktab(IR(fleft->op1)), &keyv) == niltvg(J2G(J)) &&
lj_opt_fwd_href_nokey(J))
val = lj_tab_get(J->L, ir_ktab(IR(fleft->op1)), &keyv);
/* Check for either nil or the nil value marker in the template table. */
if ((tvisnil(val) || tvistab(val)) && lj_opt_fwd_href_nokey(J))
return lj_ir_kkptr(J, niltvg(J2G(J)));
return NEXTFOLD;
}

View File

@ -233,7 +233,9 @@ static TRef fwd_ahload(jit_State *J, IRRef xref)
return lj_ir_knum_u64(J, tv->u64);
else if (tvisint(tv))
return lj_ir_kint(J, intV(tv));
else if (tvisgcv(tv))
else if (tvistab(tv)) /* Template table nil value marker. */
return TREF_NIL;
else if (tvisstr(tv))
return lj_ir_kstr(J, strV(tv));
}
/* Othwerwise: don't intern as a constant. */

View File

@ -1725,7 +1725,7 @@ static void expr_table(LexState *ls, ExpDesc *e)
FuncState *fs = ls->fs;
BCLine line = ls->linenumber;
GCtab *t = NULL;
int vcall = 0, needarr = 0, fixt = 0;
int vcall = 0, needarr = 0;
uint32_t narr = 1; /* First array index. */
uint32_t nhash = 0; /* Number of hash entries. */
BCReg freg = fs->freereg;
@ -1769,9 +1769,10 @@ static void expr_table(LexState *ls, ExpDesc *e)
lj_gc_anybarriert(fs->L, t);
if (expr_isk_nojump(&val)) { /* Add const key/value to template table. */
expr_kvalue(fs, v, &val);
} else { /* Otherwise create dummy string key (avoids lj_tab_newkey). */
settabV(fs->L, v, t); /* Preserve key with table itself as value. */
fixt = 1; /* Fix this later, after all resizes. */
/* Mark nil value with table value itself to preserve the key. */
if (key.k == VKSTR && tvisnil(v)) settabV(fs->L, v, t);
} else { /* Preserve the key for the following non-const store. */
settabV(fs->L, v, t);
goto nonconst;
}
} else {
@ -1813,17 +1814,6 @@ static void expr_table(LexState *ls, ExpDesc *e)
} else {
if (needarr && t->asize < narr)
lj_tab_reasize(fs->L, t, narr-1);
if (fixt) { /* Fix value for dummy keys in template table. */
Node *node = noderef(t->node);
uint32_t i, hmask = t->hmask;
for (i = 0; i <= hmask; i++) {
Node *n = &node[i];
if (tvistab(&n->val)) {
lj_assertFS(tabV(&n->val) == t, "bad dummy key in template table");
setnilV(&n->val); /* Turn value into nil. */
}
}
}
lj_gc_check(fs->L);
}
}

View File

@ -2079,6 +2079,7 @@ static TRef rec_tnew(jit_State *J, uint32_t ah)
/* -- Concatenation ------------------------------------------------------- */
typedef struct RecCatDataCP {
TValue savetv[5+LJ_FR2];
jit_State *J;
BCReg baseslot, topslot;
TRef tr;
@ -2119,7 +2120,9 @@ static TValue *rec_mm_concat_cp(lua_State *L, lua_CFunction dummy, void *ud)
return NULL;
}
/* 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;
top = xbase;
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;
ptrdiff_t delta = L->top - L->base;
TValue savetv[5+LJ_FR2], errobj;
TValue errobj;
RecCatDataCP rcd;
int errcode;
rcd.J = J;
rcd.baseslot = baseslot;
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);
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) {
L->top = L->base + delta;
copyTV(L, L->top++, &errobj);

View File

@ -194,6 +194,7 @@ GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt)
Node *next = nextnode(kn);
/* Don't use copyTV here, since it asserts on a copy of a dead key. */
n->val = kn->val; n->key = kn->key;
if (tvistab(&n->val)) setnilV(&n->val); /* Replace nil value marker. */
setmref(n->next, next == NULL? next : (Node *)((char *)next + d));
}
}

View File

@ -222,14 +222,6 @@ static void trace_unpatch(jit_State *J, GCtrace *T)
bc_isret(op), "bad original bytecode %d", op);
*pc = T->startins;
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:
lj_assertJ(op == BC_FUNCF, "bad original bytecode %d", op);
*pc = T->startins;
@ -245,18 +237,19 @@ static void trace_flushroot(jit_State *J, GCtrace *T)
GCproto *pt = &gcref(T->startpt)->pt;
lj_assertJ(T->root == 0, "not a root trace");
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. */
if (pt->trace == T->traceno) { /* Trace is first in chain. Easy. */
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. */
GCtrace *T2 = traceref(J, pt->trace);
if (T2) {
for (; T2->nextroot; T2 = traceref(J, T2->nextroot))
if (T2->nextroot == T->traceno) {
T2->nextroot = T->nextroot; /* Unlink from chain. */
break;
goto unpatch;
}
}
}

View File

@ -35,6 +35,21 @@
#if !LJ_TARGET_CONSOLE
#include <signal.h>
#if LJ_TARGET_POSIX
/* Improve signal handling on POSIX. Try CTRL-C on: luajit -e 'io.read()' */
static void signal_set(int sig, void (*h)(int))
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = h;
sigemptyset(&sa.sa_mask);
sigaction(sig, &sa, NULL);
}
#else
#define signal_set signal
#endif
#endif
static lua_State *globalL = NULL;
@ -54,8 +69,8 @@ static void lstop(lua_State *L, lua_Debug *ar)
static void laction(int i)
{
signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
terminate process (default action) */
/* Terminate process if another SIGINT happens (double CTRL-C). */
signal_set(i, SIG_DFL);
lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
}
#endif
@ -117,11 +132,11 @@ static int docall(lua_State *L, int narg, int clear)
lua_pushcfunction(L, traceback); /* push traceback function */
lua_insert(L, base); /* put it under chunk and args */
#if !LJ_TARGET_CONSOLE
signal(SIGINT, laction);
signal_set(SIGINT, laction);
#endif
status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
#if !LJ_TARGET_CONSOLE
signal(SIGINT, SIG_DFL);
signal_set(SIGINT, SIG_DFL);
#endif
lua_remove(L, base); /* remove traceback function */
/* force a complete garbage collection in case of errors */

View File

@ -8,7 +8,8 @@
@rem nogc64 disable LJ_GC64 mode for x64
@rem debug emit debug symbols
@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
@ -106,12 +107,14 @@ buildvm -m folddef -o lj_folddef.h lj_opt_fold.c
@if "%1"=="static" goto :STATIC
%LJCOMPILE% %LJDYNBUILD% lj_*.c lib_*.c
@if errorlevel 1 goto :BAD
@if "%1"=="mixed" goto :STATICLIB
%LJLINK% /DLL /OUT:%LJDLLNAME% lj_*.obj lib_*.obj
@if errorlevel 1 goto :BAD
@goto :MTDLL
:STATIC
%LJCOMPILE% lj_*.c lib_*.c
@if errorlevel 1 goto :BAD
:STATICLIB
%LJLIB% /OUT:%LJLIBNAME% lj_*.obj lib_*.obj
@if errorlevel 1 goto :BAD
@goto :MTDLL
@ -119,13 +122,15 @@ buildvm -m folddef -o lj_folddef.h lj_opt_fold.c
@if "%2"=="static" goto :AMALGSTATIC
%LJCOMPILE% %LJDYNBUILD% ljamalg.c
@if errorlevel 1 goto :BAD
@if "%2"=="mixed" goto :AMALGSTATICLIB
%LJLINK% /DLL /OUT:%LJDLLNAME% ljamalg.obj lj_vm.obj
@if errorlevel 1 goto :BAD
@goto :MTDLL
:AMALGSTATIC
%LJCOMPILE% ljamalg.c
@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
:MTDLL
if exist %LJDLLNAME%.manifest^