+++ 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))

Attachment: signature.asc
Description: Digital signature

Reply via email to