[Dev-luatex] Callbacks in Lua wrapper of mplib

Marcel Kr├╝ger tex at 2krueger.de
Wed Nov 7 12:16:58 CET 2018


Hi,

I recently discovered that the Lua wrapper of mplib registers all callbacks globally
such that creating multiple mplib instances with different callbacks breaks.
This affects the undocumented `run_script` and `make_text` callbacks, but also the documented `find_file`:

For example the plain LuaTeX document

    \directlua{
      local mp = mplib.new{
        find_file = function(name, mode, type)
          return name
        end
      }
      do
        % Create a temporary second instance with a different run_script handler
        mplib.new{
          find_file = function(name, mode, type)
            if name == 'cmr10' then
              print'This should not happen'
            end
            return name
          end
        }:finish()
      end
      % Now trigger find_file using the *first* mp instance which should *not* trigger a message
      mp:execute[[
        input cmr10;
      ]]
    }
    \bye

shows the message 'This should not happen', because the find_file implementation of the
second call to `mplib.new` is also used for the first `mp` instance.

This can be fixed by storing the callbacks in userdata associated with the mp uservalue instead of in the global registry:

diff --git a/source/texk/web2c/mplibdir/lmplib.c b/source/texk/web2c/mplibdir/lmplib.c
index eb8432bb5..88873ed66 100644
--- a/source/texk/web2c/mplibdir/lmplib.c
+++ b/source/texk/web2c/mplibdir/lmplib.c
@@ -329,7 +329,9 @@ static char *mplib_find_file(MP mp, const char *fname, const char *fmode, int ft
 {
     lua_State *L = (lua_State *)mp_userdata(mp);
     lua_checkstack(L, 4);
-    lua_getfield(L, LUA_REGISTRYINDEX, "mplib.file_finder");
+    lua_getuservalue(L, 1);
+    lua_getfield(L, -1, "file_finder");
+    lua_replace(L, -2);
     if (lua_isfunction(L, -1)) {
         char *s = NULL;
         const char *x = NULL;
@@ -365,9 +367,9 @@ static int mplib_find_file_function(lua_State * L)
         /*tex An error. */
         return 1;
     }
-    lua_pushstring(L, "mplib.file_finder");
+    lua_pushstring(L, "file_finder");
     lua_pushvalue(L, -2);
-    lua_rawset(L, LUA_REGISTRYINDEX);
+    lua_rawset(L, -4);
     return 0;
 }
 
@@ -379,8 +381,10 @@ static void mplib_warning(const char *str)
 static void mplib_script_error(MP mp, const char *str)
 {
     lua_State *L = (lua_State *)mp_userdata(mp);
-    lua_checkstack(L, 1);
-    lua_getfield(L, LUA_REGISTRYINDEX, "mplib.script_error");
+    lua_checkstack(L, 2);
+    lua_getuservalue(L, 1);
+    lua_getfield(L, -1, "script_error");
+    lua_replace(L, -2);
     if (lua_isfunction(L, -1)) {
         lua_pushstring(L, str);
         /*tex We assume that the function is okay. */
@@ -397,17 +401,19 @@ static int mplib_script_error_function(lua_State * L)
         /*tex An error. */
         return 1;
     }
-    lua_pushstring(L, "mplib.script_error");
+    lua_pushstring(L, "script_error");
     lua_pushvalue(L, -2);
-    lua_rawset(L, LUA_REGISTRYINDEX);
+    lua_rawset(L, -4);
     return 0;
 }
 
 static char *mplib_run_script(MP mp, const char *str)
 {
     lua_State *L = (lua_State *)mp_userdata(mp);
-    lua_checkstack(L, 1);
-    lua_getfield(L, LUA_REGISTRYINDEX, "mplib.run_script");
+    lua_checkstack(L, 2);
+    lua_getuservalue(L, 1);
+    lua_getfield(L, -1, "run_script");
+    lua_replace(L, -2);
     if (lua_isfunction(L, -1)) {
         char *s = NULL;
         const char *x = NULL;
@@ -433,17 +439,19 @@ static int mplib_run_script_function(lua_State * L)
     if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) {
         return 1; /* error */
     }
-    lua_pushstring(L, "mplib.run_script");
+    lua_pushstring(L, "run_script");
     lua_pushvalue(L, -2);
-    lua_rawset(L, LUA_REGISTRYINDEX);
+    lua_rawset(L, -4);
     return 0;
 }
 
 static char *mplib_make_text(MP mp, const char *str, int mode)
 {
     lua_State *L = (lua_State *)mp_userdata(mp);
-    lua_checkstack(L, 1);
-    lua_getfield(L, LUA_REGISTRYINDEX, "mplib.make_text");
+    lua_checkstack(L, 2);
+    lua_getuservalue(L, 1);
+    lua_getfield(L, -1, "make_text");
+    lua_replace(L, -2);
     if (lua_isfunction(L, -1)) {
         char *s = NULL;
         const char *x = NULL;
@@ -471,9 +479,9 @@ static int mplib_make_text_function(lua_State * L)
         /*tex An error. */
         return 1;
     }
-    lua_pushstring(L, "mplib.make_text");
+    lua_pushstring(L, "make_text");
     lua_pushvalue(L, -2);
-    lua_rawset(L, LUA_REGISTRYINDEX);
+    lua_rawset(L, -4);
     return 0;
 }
 
@@ -544,6 +552,8 @@ static int mplib_new(lua_State * L)
     /*  options->script_error = mplib_script_error; */
         options->print_found_names = 1;
         options->ini_version = 1;
+        /*tex Here we create the uservalue table for the callbacks: */
+        lua_newtable(L);
         if (lua_type(L, 1) == LUA_TTABLE) {
             for (i = 0; mplib_parms[i].name != NULL; i++) {
                 lua_getfield(L, 1, mplib_parms[i].name);
@@ -606,6 +616,7 @@ static int mplib_new(lua_State * L)
                 lua_pop(L, 1);
             }
         }
+        lua_setuservalue(L, -2);
         *mp_ptr = mp_initialize(options);
         xfree(options->command_line);
         xfree(options->mem_name);





More information about the dev-luatex mailing list