[Lua5.4] lua_toclose will close the wrong value

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

[Lua5.4] lua_toclose will close the wrong value

actboy168@gmail.com
#include <lua.h>
#include <lauxlib.h>

static int close(lua_State *L) {
  return 0;
}

static void newtable(lua_State *L) {
    static const luaL_Reg mt[] = {
        {"__close", close},
        {NULL, NULL}
    };
    lua_newtable(L);
    luaL_newlib(L, mt);
    lua_setmetatable(L, -2);
}

int luaopen_toclose(lua_State *L) {
    lua_pushinteger(L, 1);
    newtable(L);
    lua_toclose(L, -1);
    lua_remove(L, -2); // throw error: attempt to close non-closable variable '?'
    return 1;
}


-- actboy168
Reply | Threaded
Open this post in threaded view
|

Re: [Lua5.4] lua_toclose will close the wrong value

Sean Conner
It was thus said that the Great actboy168 once stated:

> #include <lua.h>
> #include <lauxlib.h>
>
> static int close(lua_State *L) {
>   return 0;
> }
>
> static void newtable(lua_State *L) {
>     static const luaL_Reg mt[] = {
>         {"__close", close},
>         {NULL, NULL}
>     };
>     lua_newtable(L);
>     luaL_newlib(L, mt);
>     lua_setmetatable(L, -2);
> }
>
> int luaopen_toclose(lua_State *L) {
>     lua_pushinteger(L, 1);
>     newtable(L);
>     lua_toclose(L, -1);
>     lua_remove(L, -2); // throw error: attempt to close non-closable
> variable '?'
>     return 1;
> }

So the flow is:

        lua_pushinteger(L,1); // int
        lua_newtable(L): // table int
        luaL_newlib(L,mt); // table table int
        lua_setmetatable(L,-2); // table int
        lua_toclose(L,-1); // table int
        lua_remove(L,-2); // table

  The manual states for lua_toclose():

        ... the value at that index in the stack will be closed when it goes
        out of scope. Here, in the context of a C function, to go out of
        scope means that the running function returns to Lua, there is an
        error, or the index is removed from the stack through lua_settop or
        lua_pop. An index marked as to-be-closed should not be removed from
        the stack by any other function in the API except lua_settop or
        lua_pop.

        This function should not be called for an index that is equal to or
        below an already marked to-be-closed index.

  Hmm ... the code seems like it should work.  Try commenting out the
lua_remove() and see if it works. It might be that moving the item to be
cleaned is disallowed as well and the manual doesn't mention it.

  -spc



Reply | Threaded
Open this post in threaded view
|

Re: [Lua5.4] lua_toclose will close the wrong value

Sean Conner
In reply to this post by actboy168@gmail.com
It was thus said that the Great actboy168 once stated:

> #include <lua.h>
> #include <lauxlib.h>
>
> static int close(lua_State *L) {
>   return 0;
> }
>
> static void newtable(lua_State *L) {
>     static const luaL_Reg mt[] = {
>         {"__close", close},
>         {NULL, NULL}
>     };
>     lua_newtable(L);
>     luaL_newlib(L, mt);
>     lua_setmetatable(L, -2);
> }
>
> int luaopen_toclose(lua_State *L) {
>     lua_pushinteger(L, 1);
>     newtable(L);
>     lua_toclose(L, -1);
>     lua_remove(L, -2); // throw error: attempt to close non-closable variable '?'
>     return 1;
> }

  Okay, I removed the call to lua_remove() and that cleared up the error
message.  I then added a call to printf() in the close() function and did
the the following Lua code:

        do
          local x = require "toclose"
          print(x)
        end

  The output I got was:

        CLOSING!
        table: 0x949aa70

  Going back to the manual:

        Here, in the context of a C function, to go out of scope means that
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        the running function returns to Lua, there is an error, or the index
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        is removed from the stack through lua_settop or lua_pop. An index
        marked as to-be-closed should not be removed from the stack by any
        other function in the API except lua_settop or lua_pop.

                (emphasis added)

  So that explains "CLOSING" being printed before variable x being printed.
It also seems that once a variable is marked "toclose" on the stack in C,
then one should not shift it about via lua_remove() (and possibly
lua_insert()).  It's looking like the manual should clarify aspects of
toclose variables on the C side of things.

  -spc



Reply | Threaded
Open this post in threaded view
|

Re: [Lua5.4] lua_toclose will close the wrong value

Roberto Ierusalimschy
In reply to this post by Sean Conner
>   The manual states for lua_toclose():
>
> [...] AN INDEX MARKED AS TO-BE-CLOSED SHOULD NOT BE REMOVED FROM
> THE STACK BY ANY OTHER FUNCTION IN THE API EXCEPT LUA_SETTOP OR
> LUA_POP.
>
> [...]
>
>   [...] It might be that moving the item to be
> cleaned is disallowed as well and the manual doesn't mention it.
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It seems it does.

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: [Lua5.4] lua_toclose will close the wrong value

Sean Conner
It was thus said that the Great Roberto Ierusalimschy once stated:

> >   The manual states for lua_toclose():
> >
> > [...] AN INDEX MARKED AS TO-BE-CLOSED SHOULD NOT BE REMOVED FROM
> > THE STACK BY ANY OTHER FUNCTION IN THE API EXCEPT LUA_SETTOP OR
> > LUA_POP.
> >
> > [...]
> >
> >   [...] It might be that moving the item to be
> > cleaned is disallowed as well and the manual doesn't mention it.
>                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> It seems it does.

  No, it wasn't removed, it was *moved*.  As I stated in the email
(switching the comments to use a Forth-like stack notation):

                                // before -- after | stack
        lua_pushinteger(L,1); // -- i           | i
        lua_newtable(L); // -- t            | t i
        luaL_newlib(L,mt); // -- t            | t2 t i
        lua_setmetatable(L,-2); // t2 x -- x       | t i
        lua_toclose(L,-1); // --              | t i
        lua_remove(L,-2); // ? -- ?          | t

  When lua_tclose() was called, the stack looked like:

                -1 table marked as to-close
                -2 integer

  The lua_remove(L,-2) is removing the integer, not the variable marked as
"to-close".  It's *moved*, not *removed*, unless the act of "moving" is the
same as "remove, then insert".  

  -spc

Reply | Threaded
Open this post in threaded view
|

Re: [Lua5.4] lua_toclose will close the wrong value

Sean Conner
It was thus said that the Great Sean Conner once stated:

> It was thus said that the Great Roberto Ierusalimschy once stated:
> > >   The manual states for lua_toclose():
> > >
> > > [...] AN INDEX MARKED AS TO-BE-CLOSED SHOULD NOT BE REMOVED FROM
> > > THE STACK BY ANY OTHER FUNCTION IN THE API EXCEPT LUA_SETTOP OR
> > > LUA_POP.
> > >
> > > [...]
> > >
> > >   [...] It might be that moving the item to be
> > > cleaned is disallowed as well and the manual doesn't mention it.
> >                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > It seems it does.
>
>   No, it wasn't removed, it was *moved*.  

  I've played around with the code a bit more.  This code:

        static int close(lua_State *L)
        {
          (void)L;
          printf("CLOSING!\n");
          return 0;
        }
       
        static const luaL_Reg mt[] =
        {
          { "__close" , close } ,
          { NULL      , NULL  }
        };
       
        int luaopen_toclose(lua_State *L)
        {
                                        // slot 1 - string "toclose"
                                        // slot 2 - string "./toclose"
            lua_newtable(L); // slot three - table
            luaL_newlib(L,mt);
            lua_setmetatable(L,-2);
            lua_toclose(L, -1);
            lua_pushinteger(L,1); // slot four - integer
            lua_insert(L,1); // stack now 1)int 2)str 3)str 4)table
            return 1;
        }

results in:

        [spc]lucy:/tmp>~/apps/lua-5.4/lua
        Lua 5.4.0  Copyright (C) 1994-2019 Lua.org, PUC-Rio
        > require "toclose"
        attempt to close non-closable variable '(C temporary)'
        stack traceback:
                [C]: in function 'require'
                stdin:1: in main chunk
                [C]: in ?

  I'm thinking the manual needs to state, "an index marked as 'to-be-closed'
should not be moved, nor removed by any other function in the API except
lua_settop() or lua_pop() ..."

  -spc (Would have thought the value would be marked, not the slot ... )


Reply | Threaded
Open this post in threaded view
|

Re: [Lua5.4] lua_toclose will close the wrong value

Roberto Ierusalimschy
In reply to this post by Sean Conner
> It was thus said that the Great Roberto Ierusalimschy once stated:
> > >   The manual states for lua_toclose():
> > >
> > > [...] AN INDEX MARKED AS TO-BE-CLOSED SHOULD NOT BE REMOVED FROM
> > > THE STACK BY ANY OTHER FUNCTION IN THE API EXCEPT LUA_SETTOP OR
> > > LUA_POP.
> > >
> > > [...]
> > >
> > >   [...] It might be that moving the item to be
> > > cleaned is disallowed as well and the manual doesn't mention it.
> >                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > It seems it does.
>
>   No, it wasn't removed, it was *moved*.  As I stated in the email
> (switching the comments to use a Forth-like stack notation):
>
> // before -- after | stack
> lua_pushinteger(L,1); // -- i           | i
> lua_newtable(L); // -- t            | t i
> luaL_newlib(L,mt); // -- t            | t2 t i
> lua_setmetatable(L,-2); // t2 x -- x       | t i
> lua_toclose(L,-1); // --              | t i
> lua_remove(L,-2); // ? -- ?          | t
>
>   When lua_tclose() was called, the stack looked like:
>
> -1 table marked as to-close
> -2 integer
>
>   The lua_remove(L,-2) is removing the integer, not the variable marked as
> "to-close".  It's *moved*, not *removed*, unless the act of "moving" is the
> same as "remove, then insert".  

What is marked to be closed is the index, not its value (see manual).
An index cannot be moved.

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: [Lua5.4] lua_toclose will close the wrong value

actboy168@gmail.com
My confusion comes from luaL_addlstring, a code that works fine for lua53. luaL_addlstring may create a value of toclose, which is throw error when I try to remove a value on the stack after call luaL_addlstring.
Maybe it should be added in manual.  

On Wed, May 22, 2019 at 9:09 PM Roberto Ierusalimschy <[hidden email]> wrote:
> It was thus said that the Great Roberto Ierusalimschy once stated:
> > >   The manual states for lua_toclose():
> > >
> > >   [...] AN INDEX MARKED AS TO-BE-CLOSED SHOULD NOT BE REMOVED FROM
> > >   THE STACK BY ANY OTHER FUNCTION IN THE API EXCEPT LUA_SETTOP OR
> > >   LUA_POP.
> > >
> > >   [...]
> > >
> > >   [...] It might be that moving the item to be
> > > cleaned is disallowed as well and the manual doesn't mention it.
> >                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > It seems it does.
>
>   No, it wasn't removed, it was *moved*.  As I stated in the email
> (switching the comments to use a Forth-like stack notation):
>
>                               // before -- after | stack
>       lua_pushinteger(L,1);   // -- i            | i
>       lua_newtable(L);        // -- t            | t i
>       luaL_newlib(L,mt);      // -- t            | t2 t i
>       lua_setmetatable(L,-2); // t2 x -- x       | t i
>       lua_toclose(L,-1);      // --              | t i
>       lua_remove(L,-2);       // ? -- ?          | t
>
>   When lua_tclose() was called, the stack looked like:
>
>               -1      table marked as to-close
>               -2      integer
>
>   The lua_remove(L,-2) is removing the integer, not the variable marked as
> "to-close".  It's *moved*, not *removed*, unless the act of "moving" is the
> same as "remove, then insert". 

What is marked to be closed is the index, not its value (see manual).
An index cannot be moved.

-- Roberto



--
-- actboy168