Skip to content
This repository has been archived by the owner on Dec 31, 2019. It is now read-only.

fix(luajit) allow regular pointers to be used as lightuserdata in ARM64 #47

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
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
113 changes: 113 additions & 0 deletions patches/1.15.8.1/LuaJIT-2.1-20190507_03-arm64-lightuserdata.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
This patch allows for regular pointers to be used as lightuserdata in ARM64.

The source of the problem is that ARM64 has 48 bits of addressable memory in
userspace (256 GiB), but LuaJIT only supports 47 bits for lightuserdata (128
GiB). This means that half of the memory is not addressable.

This is what the ARM64 user space memory layout looks like on Linux:

/ 0000000000000000 1111111111111111 1111111111111111 1111111111111111 |
A 32G| ... |
\ 0000000000000000 1110000000000000 0000000000000000 0000000000000000 V stack
/ 0000000000000000 1101111111111111 1111111111111111 1111111111111111
B 32G| ...
\ 0000000000000000 1100000000000000 0000000000000000 0000000000000000
/ 0000000000000000 1011111111111111 1111111111111111 1111111111111111
C 32G| ...
\ 0000000000000000 1010000000000000 0000000000000000 0000000000000000
/ 0000000000000000 1001111111111111 1111111111111111 1111111111111111
D 32G| ...
\ 0000000000000000 1000000000000000 0000000000000000 0000000000000000
/ 0000000000000000 0111111111111111 1111111111111111 1111111111111111
E 32G| ...
\ 0000000000000000 0110000000000000 0000000000000000 0000000000000000
/ 0000000000000000 0101111111111111 1111111111111111 1111111111111111
F 32G| ...
\ 0000000000000000 0100000000000000 0000000000000000 0000000000000000
/ 0000000000000000 0011111111111111 1111111111111111 1111111111111111
G 32G| ...
\ 0000000000000000 0010000000000000 0000000000000000 0000000000000000
/ 0000000000000000 0001111111111111 1111111111111111 1111111111111111 ^ heap
H 32G| ...
\ 0000000000000000 0000000000000000 0000000000000000 0000000000000000

Notice that the stack grows downwards from the top, and the heap grows upwards
from the bottom. By losing bit 48, that means that only the bottom 128 GiB
are addressable, meaning that all pointers to the stack and to static variables
are invalid, and cause a "bad light userdata pointer" error.

This patch modifies ARM64 support so that instead of losing access to the top
128 GiB, we lose access to sections in the _middle_, allowing for normal
heap and stack pointers to be valid.

This greatly restores compatibility with third-party Lua modules, most of
which do not expect over 64 GiB of addressable space but _do_ expect to be
able to store lightuserdata of static variables: it allows, for example,
lua-cjson 2.1.0.6 to run unmodified with LuaJIT on ARM64 (because it stores
lightuserdata pointing to static variables).

The original version of this patch discarded the exact middle section of
the address space (i.e. sections A B for stack and G H for heap were valid,
C D E F were invalid). However, existing libraries for LuaJIT mitigate this
problem by masking bit 48 in stack pointers, resulting in addresses in the
E section. For this reason, the revised version of this patch discards
sections B C D F, providing 32G for stack addresses (A), 64G for heap address
(G H) and 32G for masked stack addresses (E).

Signed-off-by: Hisham Muhammad <hisham@gobolinux.org>

diff -ur a/LuaJIT-2.1-20190507/src/lj_api.c b/LuaJIT-2.1-20190507/src/lj_api.c
--- a/LuaJIT-2.1-20190507/src/lj_api.c 2019-05-02 17:58:14.000000000 -0300
+++ b/LuaJIT-2.1-20190507/src/lj_api.c 2019-08-09 15:36:18.435306003 -0300
@@ -594,9 +594,17 @@
cTValue *o = index2adr(L, idx);
if (tvisudata(o))
return uddata(udataV(o));
- else if (tvislightud(o))
- return lightudV(o);
- else
+ else if (tvislightud(o)) {
+ void *p = lightudV(o);
+#if LJ_TARGET_ARM64
+ switch ((uintptr_t) p & (7UL << 45)) {
+ case (7UL << 45): /* 111 -> 010 */
+ case (2UL << 45): /* 010 -> 111 */
+ p = (void*) ((uintptr_t) p ^ (5UL << 45));
+ }
+#endif
+ return p;
+ } else
return NULL;
}

@@ -696,6 +704,13 @@

LUA_API void lua_pushlightuserdata(lua_State *L, void *p)
{
+#if LJ_TARGET_ARM64
+ switch ((uintptr_t) p & (7UL << 45)) {
+ case (7UL << 45): /* 111 -> 010 */
+ case (2UL << 45): /* 010 -> 111 */
+ p = (void*) ((uintptr_t) p ^ (5UL << 45));
+ }
+#endif
setlightudV(L->top, checklightudptr(L, p));
incr_top(L);
}
diff -ur a/LuaJIT-2.1-20190507/src/lj_cconv.c b/LuaJIT-2.1-20190507/src/lj_cconv.c
--- a/LuaJIT-2.1-20190507/src/lj_cconv.c 2019-05-02 17:58:14.000000000 -0300
+++ b/LuaJIT-2.1-20190507/src/lj_cconv.c 2019-08-09 15:38:14.356301250 -0300
@@ -612,6 +612,13 @@
tmpptr = *(void **)tmpptr;
} else if (tvislightud(o)) {
tmpptr = lightudV(o);
+#if LJ_TARGET_ARM64
+ switch ((uintptr_t) tmpptr & (7UL << 45)) {
+ case (7UL << 45): /* 111 -> 010 */
+ case (2UL << 45): /* 010 -> 111 */
+ tmpptr = (void*) ((uintptr_t) tmpptr ^ (5UL << 45));
+ }
+#endif
} else if (tvisfunc(o)) {
void *p = lj_ccallback_new(cts, d, funcV(o));
if (p) {