[Dev-luatex] Fix for pdf_literal Lua string / token list conversions

Michal Vlasák lahcim8 at gmail.com
Sat Aug 28 21:14:23 CEST 2021


Hello,

take this plain LuaTeX example:

    \setbox0=\hbox{\pdfextension literal{0 g}}

    % 1)
    \directlua{
        local literal = tex.getbox(0).head
        texio.write_nl("log", "literal.data="..literal.data)
    }
    \showbox0
    
    % 2)
    \directlua{
        local literal = tex.getbox(0).head
        literal.data = "test"
        literal.token = "toks"
        texio.write_nl("log", "literal.token="..(literal.token or "nil"))
        }
    \showbox0
    
    % 3) patch test
    \directlua{
        tex.set("everyjob", "asd")
        texio.write_nl("log", tex.get("everyjob"))
    }
    
    \bye

Expected log output (abridged):
1)
    literal.data=0 g
    .\pdfliteral origin{0 g}

2)
    literal.token=toks
    .\pdfliteral origin{toks}


Actual output:
1)
    literal.data=data
    .\pdfliteral origin{0 g}

2)
    literal.token=characters
    .\pdfliteral origin <lua data reference 153>


In the first case the Lua accessor returns a value which happens to be
on top of the stack (the key "data" itself). In the second case an index
into TeX memory is misinterpreted as a Lua registry index, so the
returned data is essentially garbage.

Patch for both issues is attached. I also extended `tokenlist_from_lua`
(which is what `nodelib_gettoks` is defined as) to allow an index
argument. The previous version used the value on top of the stack, which
probably worked for every use currently in LuaTeX, but seemed rather
dangerous and subtle.

The patch is from git, though it can be applied normally with

    patch -Np1 < pdf_literal.patch

Kind regards,
Michal Vlasák
-------------- next part --------------
diff --git a/source/texk/web2c/luatexdir/lua/lnodelib.c b/source/texk/web2c/luatexdir/lua/lnodelib.c
index 0cd680384..4fbf96db7 100644
--- a/source/texk/web2c/luatexdir/lua/lnodelib.c
+++ b/source/texk/web2c/luatexdir/lua/lnodelib.c
@@ -150,7 +150,7 @@
 
 #define nodelib_setattr(L, s, n)     reassign_attribute(n,nodelib_getlist(L,s))
 
-#define nodelib_gettoks(L,a)   tokenlist_from_lua(L)
+#define nodelib_gettoks(L,a)   tokenlist_from_lua(L, a)
 
 #define nodelib_getspec        nodelib_getlist
 #define nodelib_getaction      nodelib_getlist
@@ -1566,7 +1566,7 @@ static int lua_nodelib_direct_setleader(lua_State * L)
 #define get_pdf_literal_direct_value(L,n) do {                  \
     if (pdf_literal_type(n) == lua_refid_literal) {             \
         lua_rawgeti(L, LUA_REGISTRYINDEX, pdf_literal_data(n)); \
-    } else if (pdf_literal_type(n) == lua_refid_literal) {      \
+    } else if (pdf_literal_type(n) == normal) {                 \
         tokenlist_to_luastring(L, pdf_literal_data(n));         \
     }                                                           \
 } while (0)
@@ -1584,6 +1584,7 @@ static int lua_nodelib_direct_setleader(lua_State * L)
 
 #define set_pdf_literal_direct_token(L,n,i) do { \
     pdf_literal_data(n) = nodelib_gettoks(L, i); \
+    pdf_literal_type(n) = normal;                \
 } while (0)
 
 #define cleanup_late_lua(n) do {                               \
diff --git a/source/texk/web2c/luatexdir/lua/ltexlib.c b/source/texk/web2c/luatexdir/lua/ltexlib.c
index 6e19e0727..590a83144 100644
--- a/source/texk/web2c/luatexdir/lua/ltexlib.c
+++ b/source/texk/web2c/luatexdir/lua/ltexlib.c
@@ -1790,7 +1790,7 @@ static int settex(lua_State * L)
                 }
             } else if (is_toks_assign(cur_cmd1)) {
                 if (lua_type(L,i) == LUA_TSTRING) {
-                    j = tokenlist_from_lua(L);  /* uses stack -1 */
+                    j = tokenlist_from_lua(L, i);
                     assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), j);
 
                 } else {
diff --git a/source/texk/web2c/luatexdir/lua/luatex-api.h b/source/texk/web2c/luatexdir/lua/luatex-api.h
index f50664764..996ef6466 100644
--- a/source/texk/web2c/luatexdir/lua/luatex-api.h
+++ b/source/texk/web2c/luatexdir/lua/luatex-api.h
@@ -162,7 +162,7 @@ extern int characters_from_lua(lua_State * L, int f); /* return is boolean */
 extern int luaopen_token(lua_State * L);
 extern void tokenlist_to_lua(lua_State * L, int p);
 extern void tokenlist_to_luastring(lua_State * L, int p);
-extern int tokenlist_from_lua(lua_State * L);
+extern int tokenlist_from_lua(lua_State * L, int n);
 
 extern void lua_nodelib_push(lua_State * L);
 extern int nodelib_getdir(lua_State * L, int n);
diff --git a/source/texk/web2c/luatexdir/lua/luatoken.c b/source/texk/web2c/luatexdir/lua/luatoken.c
index dc2c6b8aa..56de5407a 100644
--- a/source/texk/web2c/luatexdir/lua/luatoken.c
+++ b/source/texk/web2c/luatexdir/lua/luatoken.c
@@ -482,7 +482,7 @@ void tokenlist_to_luastring(lua_State * L, int p)
     free(s);
 }
 
-int tokenlist_from_lua(lua_State * L)
+int tokenlist_from_lua(lua_State * L, int n)
 {
     const char *s;
     int tok, t;
@@ -492,12 +492,12 @@ int tokenlist_from_lua(lua_State * L)
     token_info(r) = 0;
     token_link(r) = null;
     p = r;
-    t = lua_type(L, -1);
+    t = lua_type(L, n);
     if (t == LUA_TTABLE) {
-        j = lua_rawlen(L, -1);
+        j = lua_rawlen(L, n);
         if (j > 0) {
             for (i = 1; i <= j; i++) {
-                lua_rawgeti(L, -1, (int) i);
+                lua_rawgeti(L, n, (int) i);
                 tok = token_from_lua(L);
                 if (tok >= 0) {
                     store_new_token(tok);
@@ -507,7 +507,7 @@ int tokenlist_from_lua(lua_State * L)
         }
         return r;
     } else if (t == LUA_TSTRING) {
-        s = lua_tolstring(L, -1, &j);
+        s = lua_tolstring(L, n, &j);
         for (i = 0; i < j; i++) {
             if (s[i] == 32) {
                 tok = token_val(10, s[i]);


More information about the dev-luatex mailing list