+++ Debian Bug Tracking System [2016-03-22 15:03 +0000]: OK, so the issue is indeed the 47/48 bit pointers. The mozilla jit had the exact same issue. https://bugzilla.mozilla.org/show_bug.cgi?id=1143022
I've hacked up a patch (attached), which changes the pointer length to 48 bits, to demonstrate that the top bit is no longer masked and the segfault goes away. However this patch is not a proper fix (and crashes a bit later) because it does not properly deal with the fact that moving up one bit pushes the 4 tags further up and impinges on the fff8 'NaN' value currently used. My understanding of the code is not sufficient to work out whether everything can simply be shoved up by one bit to make this work. Can the NaN change, or is it set by the IEEE specs? Does it need to change in fact, or is it only use in the 32bit mode? And I don't properly understand the distinction between LJ_64 and LJ_GC64 which affects how things are laid out. So I'm well aware that my patch is half-a-bodge, and merely to prove that I was barking up the right tree. So the issue is nicely described in src/lj_obj.h 'Internal object tags' ** Format for 32 bit GC references (!LJ_GC64): ** ** Internal tags overlap the MSW of a number object (must be a double). ** Interpreted as a double these are special NaNs. The FPU only generates ** one type of NaN (0xfff8_0000_0000_0000). So MSWs > 0xfff80000 are available ** for use as internal tags. Small negative numbers are used to shorten the ** encoding of type comparisons (reg/mem against sign-ext. 8 bit immediate). ** ** ---MSW---.---LSW--- ** primitive types | itype | | ** lightuserdata | itype | void * | (32 bit platforms) ** lightuserdata |ffff| void * | (64 bit platforms, 47 bit pointers) ** GC objects | itype | GCRef | ** int (LJ_DUALNUM)| itype | int | ** number -------double------ ** ** Format for 64 bit GC references (LJ_GC64): ** ** The upper 13 bits must be 1 (0xfff8...) for a special NaN. The next ** 4 bits hold the internal tag. The lowest 47 bits either hold a pointer, ** a zero-extended 32 bit integer or all bits set to 1 for primitive types. ** ** ------MSW------.------LSW------ ** primitive types |1..1|itype|1..................1| ** GC objects/lightud |1..1|itype|-------GCRef--------| ** int (LJ_DUALNUM) |1..1|itype|0..0|-----int-------| ** number ------------double------------- So can we just change that to: ** The upper 12 bits must be 1 (0xfff...) for a special NaN. The next ** 4 bits hold the internal tag. The lowest 48 bits either hold a pointer, ** a zero-extended 32 bit integer or all bits set to 1 for primitive types. ? Or will that just break and we need to keep fff8, leaving only 3 bits for the tags? Ultimately this design needs to change, because ARM64 pointers are going to change to 52 bits in the future and x86 pointers will be getting bigger too as they are subject to the same pressures in new hardware. So putting the tags somewhere else would be smart, or maybe down at the bottom end if you know things are aligned to large enough boundaries? But perhaps we can make a smaller change for now to get this running? I'll file this upstream too, referring back here. Wookey -- Principal hats: Linaro, Debian, Wookware, ARM http://wookware.org/
Description: Change VM pointer size limit to 48bits for aarch64 Aarch64 (arm64) has a 48bit address space, whereas x86_64 has a 47bit address space Luajit checks that pointers fit into 47 bits, which results in chopping off the top bit of an aarch64 pointer and a segfault. This patch fixes that. Author: Wookey <woo...@debian.org> Bug-Debian: https://bugs.debian.org/818616 Bug: <url in upstream bugtracker> Forwarded: no Last-Update: 2016-03-22 --- luajit-2.1.0~beta2+dfsg.orig/src/lj_def.h +++ luajit-2.1.0~beta2+dfsg/src/lj_def.h @@ -47,7 +47,7 @@ typedef unsigned int uintptr_t; /* Various VM limits. */ #define LJ_MAX_MEM32 0x7fffff00 /* Max. 32 bit memory allocation. */ -#define LJ_MAX_MEM64 ((uint64_t)1<<47) /* Max. 64 bit memory allocation. */ +#define LJ_MAX_MEM64 ((uint64_t)1<<48) /* Max. 64 bit memory allocation. */ /* Max. total memory allocation. */ #define LJ_MAX_MEM (LJ_GC64 ? LJ_MAX_MEM64 : LJ_MAX_MEM32) #define LJ_MAX_ALLOC LJ_MAX_MEM /* Max. individual allocation length. */ @@ -103,9 +103,9 @@ typedef unsigned int uintptr_t; #define checki32(x) ((x) == (int32_t)(x)) #define checku32(x) ((x) == (uint32_t)(x)) #define checkptr32(x) ((uintptr_t)(x) == (uint32_t)(uintptr_t)(x)) -#define checkptr47(x) (((uint64_t)(x) >> 47) == 0) +#define checkptr48(x) (((uint64_t)(x) >> 48) == 0) #if LJ_GC64 -#define checkptrGC(x) (checkptr47((x))) +#define checkptrGC(x) (checkptr48((x))) #elif LJ_64 #define checkptrGC(x) (checkptr32((x))) #else --- luajit-2.1.0~beta2+dfsg.orig/src/lj_obj.h +++ luajit-2.1.0~beta2+dfsg/src/lj_obj.h @@ -67,7 +67,7 @@ typedef struct GCRef { #define setgcref(r, gc) ((r).gcptr64 = (uint64_t)&(gc)->gch) #define setgcreft(r, gc, it) \ - (r).gcptr64 = (uint64_t)&(gc)->gch | (((uint64_t)(it)) << 47) + (r).gcptr64 = (uint64_t)&(gc)->gch | (((uint64_t)(it)) << 48) #define setgcrefp(r, p) ((r).gcptr64 = (uint64_t)(p)) #define setgcrefnull(r) ((r).gcptr64 = 0) #define setgcrefr(r, v) ((r).gcptr64 = (v).gcptr64) @@ -232,15 +232,15 @@ typedef const TValue cTValue; ** ---MSW---.---LSW--- ** primitive types | itype | | ** lightuserdata | itype | void * | (32 bit platforms) -** lightuserdata |ffff| void * | (64 bit platforms, 47 bit pointers) +** lightuserdata |ffff| void * | (64 bit platforms, 48 bit pointers) ** GC objects | itype | GCRef | ** int (LJ_DUALNUM)| itype | int | ** number -------double------ ** ** Format for 64 bit GC references (LJ_GC64): ** -** The upper 13 bits must be 1 (0xfff8...) for a special NaN. The next -** 4 bits hold the internal tag. The lowest 47 bits either hold a pointer, +** The upper 12 bits must be 1 (0xfff...) for a special NaN. The next +** 4 bits hold the internal tag. The lowest 48 bits either hold a pointer, ** a zero-extended 32 bit integer or all bits set to 1 for primitive types. ** ** ------MSW------.------LSW------ @@ -282,7 +282,7 @@ typedef const TValue cTValue; #define LJ_TISTABUD LJ_TTAB #if LJ_GC64 -#define LJ_GCVMASK (((uint64_t)1 << 47) - 1) +#define LJ_GCVMASK (((uint64_t)1 << 48) - 1) #endif /* -- String object ------------------------------------------------------- */ @@ -737,7 +737,7 @@ typedef union GCobj { /* Macros to test types. */ #if LJ_GC64 -#define itype(o) ((uint32_t)((o)->it64 >> 47)) +#define itype(o) ((uint32_t)((o)->it64 >> 48)) #define tvisnil(o) ((o)->it64 == -1) #else #define itype(o) ((o)->it) @@ -815,8 +815,8 @@ typedef union GCobj { #if LJ_GC64 #define setitype(o, i) ((o)->it = ((i) << 15)) #define setnilV(o) ((o)->it64 = -1) -#define setpriV(o, x) ((o)->it64 = (int64_t)~((uint64_t)~(x)<<47)) -#define setboolV(o, x) ((o)->it64 = (int64_t)~((uint64_t)((x)+1)<<47)) +#define setpriV(o, x) ((o)->it64 = (int64_t)~((uint64_t)~(x)<<48)) +#define setboolV(o, x) ((o)->it64 = (int64_t)~((uint64_t)((x)+1)<<48)) #else #define setitype(o, i) ((o)->it = (i)) #define setnilV(o) ((o)->it = LJ_TNIL) @@ -827,7 +827,7 @@ typedef union GCobj { static LJ_AINLINE void setlightudV(TValue *o, void *p) { #if LJ_GC64 - o->u64 = (uint64_t)p | (((uint64_t)LJ_TLIGHTUD) << 47); + o->u64 = (uint64_t)p | (((uint64_t)LJ_TLIGHTUD) << 48); #elif LJ_64 o->u64 = (uint64_t)p | (((uint64_t)0xffff) << 48); #else @@ -837,7 +837,7 @@ static LJ_AINLINE void setlightudV(TValu #if LJ_64 #define checklightudptr(L, p) \ - (((uint64_t)(p) >> 47) ? (lj_err_msg(L, LJ_ERR_BADLU), NULL) : (p)) + (((uint64_t)(p) >> 48) ? (lj_err_msg(L, LJ_ERR_BADLU), NULL) : (p)) #else #define checklightudptr(L, p) (p) #endif @@ -883,7 +883,7 @@ define_setV(settabV, GCtab, LJ_TTAB) define_setV(setudataV, GCudata, LJ_TUDATA) #define setnumV(o, x) ((o)->n = (x)) -#define setnanV(o) ((o)->u64 = U64x(fff80000,00000000)) +#define setnanV(o) ((o)->u64 = U64x(fff00000,00000000)) #define setpinfV(o) ((o)->u64 = U64x(7ff00000,00000000)) #define setminfV(o) ((o)->u64 = U64x(fff00000,00000000))
signature.asc
Description: Digital signature