Lua stack clean

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

Lua stack clean

Ranier Vilela-2
Hi Hackers,
How should the stack look after the calls below?

    lua_pushinteger(L, p1);
    lua_pushinteger(L, p2);
    lua_pushinteger(L, p3);
    lua_pushnumber(L, p4);
    lua_call(L, 4, 1);
    if (lua_isuserdata(L, -1)) {
        value = lua_tonumber(L, -1);
        lua_pop(L, 1);
    }
    lua_pop(L, lua_gettop(L));

What is the correct way to clean the stack?

regards,
Ranier Vilela
Reply | Threaded
Open this post in threaded view
|

Re: Lua stack clean

Tim McCracken
Why do you want to “clean” the stack? You may be making things harder than they are. Lua manages the “stack” for you.



Sent from my iPhone

On Feb 24, 2021, at 7:26 PM, Ranier Vilela <[hidden email]> wrote:


Hi Hackers,
How should the stack look after the calls below?

    lua_pushinteger(L, p1);
    lua_pushinteger(L, p2);
    lua_pushinteger(L, p3);
    lua_pushnumber(L, p4);
    lua_call(L, 4, 1);
    if (lua_isuserdata(L, -1)) {
        value = lua_tonumber(L, -1);
        lua_pop(L, 1);
    }
    lua_pop(L, lua_gettop(L));

What is the correct way to clean the stack?

regards,
Ranier Vilela
Reply | Threaded
Open this post in threaded view
|

Re: Lua stack clean

Ranier Vilela-2
You mean don't have to call lua_pop?
I have a bug reading an invalid pointer, in an adjacent library, which I'm not sure is caused by Lua gc.

regards,
Ranier Vilela

Em qua, 24 de fev de 2021 10:36 PM, Tim McCracken <[hidden email]> escreveu:
Why do you want to “clean” the stack? You may be making things harder than they are. Lua manages the “stack” for you.



Sent from my iPhone

On Feb 24, 2021, at 7:26 PM, Ranier Vilela <[hidden email]> wrote:


Hi Hackers,
How should the stack look after the calls below?

    lua_pushinteger(L, p1);
    lua_pushinteger(L, p2);
    lua_pushinteger(L, p3);
    lua_pushnumber(L, p4);
    lua_call(L, 4, 1);
    if (lua_isuserdata(L, -1)) {
        value = lua_tonumber(L, -1);
        lua_pop(L, 1);
    }
    lua_pop(L, lua_gettop(L));

What is the correct way to clean the stack?

regards,
Ranier Vilela
Reply | Threaded
Open this post in threaded view
|

Re: Lua stack clean

Sean Conner
In reply to this post by Ranier Vilela-2
It was thus said that the Great Ranier Vilela once stated:

> Hi Hackers,
> How should the stack look after the calls below?
>
>     lua_pushinteger(L, p1);
>     lua_pushinteger(L, p2);
>     lua_pushinteger(L, p3);
>     lua_pushnumber(L, p4);
>     lua_call(L, 4, 1);
>     if (lua_isuserdata(L, -1)) {
>         value = lua_tonumber(L, -1);
>         lua_pop(L, 1);
>     }
>     lua_pop(L, lua_gettop(L));
>
> What is the correct way to clean the stack?

  The lua_call() function is defined as:

        void lua_call(lua_State *L,int nargs,int nresults);

The manual states that lua_call() will remove nargs+1 items from the stack,
and push nresults on the stack.  So for your example:

        lua_pushcfunction(L,myfunc);
        lua_pushinteger(L,p1);
        lua_pushinteger(L,p2);
        lua_pushinteger(L,p3);
        lua_pushinteger(L,p4); /* [1] */
        lua_call(L,4,1);       /* [2] */

At point [1], the stack looks like:

        +index -index value
        ----------------------
        n-1 -6 previous entries...
        n -5 myfunc
        n+1 -4 p1
        n+2 -3 p2
        n+3 -2 p3
        n+4 -1 p4

At point [2], the stack will look like:

        +index -index value
        ----------------------
        n-1 -2 previous entries...
        n -1 result

In your example, the code should be:

        if (lua_is<type>(L,-1))
        {
          value = lua_to<type>(L,-1);
          /* use the value */
        }
        lua_pop(L,1); /* remove result from stack */

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

Re: Lua stack clean

Ranier Vilela-2
Thanks, I will test like this.

regards,
Ranier Vilela

Em qua, 24 de fev de 2021 10:47 PM, Sean Conner <[hidden email]> escreveu:
It was thus said that the Great Ranier Vilela once stated:
> Hi Hackers,
> How should the stack look after the calls below?
>
>     lua_pushinteger(L, p1);
>     lua_pushinteger(L, p2);
>     lua_pushinteger(L, p3);
>     lua_pushnumber(L, p4);
>     lua_call(L, 4, 1);
>     if (lua_isuserdata(L, -1)) {
>         value = lua_tonumber(L, -1);
>         lua_pop(L, 1);
>     }
>     lua_pop(L, lua_gettop(L));
>
> What is the correct way to clean the stack?

  The lua_call() function is defined as:

        void lua_call(lua_State *L,int nargs,int nresults);

The manual states that lua_call() will remove nargs+1 items from the stack,
and push nresults on the stack.  So for your example:

        lua_pushcfunction(L,myfunc);
        lua_pushinteger(L,p1);
        lua_pushinteger(L,p2);
        lua_pushinteger(L,p3);
        lua_pushinteger(L,p4); /* [1] */
        lua_call(L,4,1);       /* [2] */

At point [1], the stack looks like:

        +index  -index  value
        ----------------------
        n-1     -6      previous entries...
        n       -5      myfunc
        n+1     -4      p1
        n+2     -3      p2
        n+3     -2      p3
        n+4     -1      p4

At point [2], the stack will look like:

        +index  -index  value
        ----------------------
        n-1     -2      previous entries...
        n       -1      result

In your example, the code should be:

        if (lua_is<type>(L,-1))
        {
          value = lua_to<type>(L,-1);
          /* use the value */
        }
        lua_pop(L,1);   /* remove result from stack */

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

Re: Lua stack clean

Sean Conner
In reply to this post by Ranier Vilela-2
It was thus said that the Great Ranier Vilela once stated:
> You mean don't have to call lua_pop?

  It depends upon the code.  

> I have a bug reading an invalid pointer, in an adjacent library, which I'm
> not sure is caused by Lua gc.

  It may be an issue over who owns the memory for the userdata, but without
knowing the exact error, it's hard to say.

  Here's a function (for Lua 5.2+) that I use to debug Lua stack issues:

static int cstack(lua_State *L)
{
  int max = lua_gettop(L);
 
  fprintf(stderr,"Stack dump\n");
 
  for (int i = 1 ; i <= max ; i++)
  {
    fprintf(
            stderr,
            "%d %d - %s %s\n",
            i,
            i - max - 1,
            luaL_typename(L,i),
            luaL_tolstring(L,i,NULL)
    );
    lua_pop(L,1);
  }
 
  fprintf(stderr,"Stack done\n");
  return max;
}

  I wil add calls to this funciton at points where I want to know what's on
the stack, and at what index (this will print both positive and negative
indecies).

  -spc (Hope this helps)
Reply | Threaded
Open this post in threaded view
|

Re: Lua stack clean

Ranier Vilela-2
Em qua., 24 de fev. de 2021 às 22:54, Sean Conner <[hidden email]> escreveu:
> I have a bug reading an invalid pointer, in an adjacent library, which I'm
> not sure is caused by Lua gc.

  It may be an issue over who owns the memory for the userdata, but without
knowing the exact error, it's hard to say.
Lua owns the pointer.
The code is run many times, then magically the "feeefeeefeeefeee" pointer appears.
I need to make sure that there are no mistakes part of Lua C api.

regards,
Ranier Vilela
Reply | Threaded
Open this post in threaded view
|

Re: Lua stack clean

Ranier Vilela-2
Em qua., 24 de fev. de 2021 às 23:17, Ranier Vilela <[hidden email]> escreveu:
Em qua., 24 de fev. de 2021 às 22:54, Sean Conner <[hidden email]> escreveu:
> I have a bug reading an invalid pointer, in an adjacent library, which I'm
> not sure is caused by Lua gc.

  It may be an issue over who owns the memory for the userdata, but without
knowing the exact error, it's hard to say.
Lua owns the pointer.
The code is run many times, then magically the "feeefeeefeeefeee" pointer appears.
I need to make sure that there are no mistakes part of Lua C api.
Regarding the problem, I can already say with certainty that it is the case of:
user-after-free

While I am fighting the problem, I have used some tools.
One of them is DrMemory (https://www.drmemory.org/)

With the latest Lua from git,
I have a report with a simple execution of Lua.exe.
msvc 2019 (64 bits) with Debug:

Dr. Memory version 2.3.18665 build 0 built on Feb 13 2021 02:29:43
Windows version: WinVer=105;Rel=2004;Build=19041;Edition=Core
Dr. Memory results for pid 5764: "lua.exe"
Application cmdline: "lua.exe test.lua"
Recorded 124 suppression(s) from default c:\DrMemory\bin64\suppress-default.txt

Error #1: UNINITIALIZED READ: reading register rbx
# 0 ntdll.dll!RtlLookupFunctionEntry    +0x33     (0x00007fffcce34163 <ntdll.dll+0x24163>)
# 1 luaM_free_                           [C:\dll\lua\lmem.c:135]
# 2 luaM_free_                           [C:\dll\lua\lmem.c:135]
# 3 ucrtbased.dll!recalloc              +0xa66    (0x00007fff958b6cf7 <ucrtbased.dll+0x56cf7>)
# 4 luaD_rawrunprotected                 [C:\dll\lua\ldo.c:144]
# 5 l_alloc                              [C:\dll\lua\lauxlib.c:1001]
# 6 luaM_free_                           [C:\dll\lua\lmem.c:135]
# 7 luaD_inctop                          [C:\dll\lua\ldo.c:275]
# 8 lua_pcallk                           [C:\dll\lua\lapi.c:1056]
# 9 luaB_pcall                           [C:\dll\lua\lbaselib.c:456]
#10 luaV_execute                         [C:\dll\lua\lvm.c:1618]
#11 ccall                                [C:\dll\lua\ldo.c:563]
#12 luaD_tryfuncTM                       [C:\dll\lua\ldo.c:581]
#13 lua_callk                            [C:\dll\lua\lapi.c:1012]
#14 ll_require                           [C:\dll\lua\loadlib.c:668]
#15 luaV_execute                         [C:\dll\lua\lvm.c:1618]
#16 ccall                                [C:\dll\lua\ldo.c:563]
#17 luaD_tryfuncTM                       [C:\dll\lua\ldo.c:581]
#18 f_call                               [C:\dll\lua\lapi.c:1030]
#19 luaD_rawrunprotected                 [C:\dll\lua\ldo.c:144]
Note: @0:00:25.836 in thread 7096
Note: instruction: cmp    %rbx %rcx

Error #2: UNINITIALIZED READ: reading register rbx
# 0 ntdll.dll!RtlVirtualUnwind        +0x184    (0x00007fffcce324b4 <ntdll.dll+0x224b4>)
# 1 luaM_free_                         [C:\dll\lua\lmem.c:135]
# 2 luaM_free_                         [C:\dll\lua\lmem.c:135]
# 3 luaM_free_                         [C:\dll\lua\lmem.c:135]
# 4 ucrtbased.dll!recalloc            +0xa66    (0x00007fff958b6cf7 <ucrtbased.dll+0x56cf7>)
# 5 luaD_rawrunprotected               [C:\dll\lua\ldo.c:144]
# 6 l_alloc                            [C:\dll\lua\lauxlib.c:1001]
# 7 luaM_free_                         [C:\dll\lua\lmem.c:135]
# 8 luaD_inctop                        [C:\dll\lua\ldo.c:275]
# 9 lua_pcallk                         [C:\dll\lua\lapi.c:1056]
#10 luaB_pcall                         [C:\dll\lua\lbaselib.c:456]
#11 luaV_execute                       [C:\dll\lua\lvm.c:1618]
#12 ccall                              [C:\dll\lua\ldo.c:563]
#13 luaD_tryfuncTM                     [C:\dll\lua\ldo.c:581]
#14 lua_callk                          [C:\dll\lua\lapi.c:1012]
#15 ll_require                         [C:\dll\lua\loadlib.c:668]
#16 luaV_execute                       [C:\dll\lua\lvm.c:1618]
#17 ccall                              [C:\dll\lua\ldo.c:563]
#18 luaD_tryfuncTM                     [C:\dll\lua\ldo.c:581]
#19 f_call                             [C:\dll\lua\lapi.c:1030]
Note: @0:00:25.836 in thread 7096
Note: instruction: movzx  (%rbx) -> %ecx

Error #3: UNINITIALIZED READ: reading register ecx
# 0 ucrtbased.dll!set_errno                            +0x91     (0x00007fff958cafe1 <ucrtbased.dll+0x6afe1>)
# 1 ucrtbased.dll!seh_filter_exe                       +0x3c     (0x00007fff958cb07d <ucrtbased.dll+0x6b07d>)
# 2 `__scrt_common_main_seh'::`1'::filt$0               [d:\agent\_work\63\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:304]
# 3 ntdll.dll!_chkstk                                  +0x11e    (0x00007fffcceb197f <ntdll.dll+0xa197f>)
# 4 ntdll.dll!RtlRaiseException                        +0x433    (0x00007fffcce5b754 <ntdll.dll+0x4b754>)
# 5 ntdll.dll!KiUserExceptionDispatcher                +0x2d     (0x00007fffcceb04ae <ntdll.dll+0xa04ae>)
# 6 ucrtbased.dll!recalloc                             +0xa66    (0x00007fff958b6cf7 <ucrtbased.dll+0x56cf7>)
# 7 luaD_rawrunprotected                                [C:\dll\lua\ldo.c:144]
# 8 l_alloc                                             [C:\dll\lua\lauxlib.c:1001]
# 9 luaM_free_                                          [C:\dll\lua\lmem.c:135]
#10 luaD_inctop                                         [C:\dll\lua\ldo.c:275]
#11 lua_pcallk                                          [C:\dll\lua\lapi.c:1056]
#12 luaB_pcall                                          [C:\dll\lua\lbaselib.c:456]
#13 luaV_execute                                        [C:\dll\lua\lvm.c:1618]
#14 ccall                                               [C:\dll\lua\ldo.c:563]
#15 luaD_tryfuncTM                                      [C:\dll\lua\ldo.c:581]
#16 lua_callk                                           [C:\dll\lua\lapi.c:1012]
#17 ll_require                                          [C:\dll\lua\loadlib.c:668]
#18 luaV_execute                                        [C:\dll\lua\lvm.c:1618]
#19 ccall                                               [C:\dll\lua\ldo.c:563]
Note: @0:00:25.856 in thread 7096
Note: instruction: cmp    (%rax) %ecx

Error #4: UNINITIALIZED READ: reading register rbx
# 0 ntdll.dll!RtlLookupFunctionEntry    +0x17b    (0x00007fffcce342ab <ntdll.dll+0x242ab>)
# 1 ntdll.dll!RtlUnwindEx               +0x1ee    (0x00007fffcce31d3f <ntdll.dll+0x21d3f>)
# 2 luaM_free_                           [C:\dll\lua\lmem.c:135]
# 3 luaM_free_                           [C:\dll\lua\lmem.c:135]
# 4 luaM_free_                           [C:\dll\lua\lmem.c:135]
# 5 ntdll.dll!_chkstk                   +0x11e    (0x00007fffcceb197f <ntdll.dll+0xa197f>)
# 6 ntdll.dll!RtlRaiseException         +0x433    (0x00007fffcce5b754 <ntdll.dll+0x4b754>)
# 7 l_alloc                              [C:\dll\lua\lauxlib.c:1001]
# 8 ntdll.dll!RtlUserThreadStart        +0x20     (0x00007fffcce5d241 <ntdll.dll+0x4d241>)
Note: @0:00:27.406 in thread 7096
Note: instruction: cmp    %rbx <rel> 0x00007fffccf90428

Error #5: UNINITIALIZED READ: reading register rbx
# 0 ntdll.dll!RtlVirtualUnwind      +0x184    (0x00007fffcce324b4 <ntdll.dll+0x224b4>)
# 1 luaM_free_                       [C:\dll\lua\lmem.c:135]
# 2 luaM_free_                       [C:\dll\lua\lmem.c:135]
# 3 luaM_free_                       [C:\dll\lua\lmem.c:135]
# 4 luaM_free_                       [C:\dll\lua\lmem.c:135]
# 5 ntdll.dll!_chkstk               +0x11e    (0x00007fffcceb197f <ntdll.dll+0xa197f>)
# 6 ntdll.dll!RtlRaiseException     +0x433    (0x00007fffcce5b754 <ntdll.dll+0x4b754>)
# 7 luaM_free_                       [C:\dll\lua\lmem.c:135]
# 8 ntdll.dll!RtlUserThreadStart    +0x20     (0x00007fffcce5d241 <ntdll.dll+0x4d241>)
Note: @0:00:27.406 in thread 7096
Note: instruction: movzx  (%rbx) -> %ecx

Error #6: UNINITIALIZED READ: reading 0x000000e5d797c0e0-0x000000e5d797c240 352 byte(s) within 0x000000e5d797c040-0x000000e5d797c240
# 0 ntdll.dll!RtlCaptureContext2    +0x2f0    (0x00007fffcceb0b50 <ntdll.dll+0xa0b50>)
# 1 ntdll.dll!RtlUnwindEx           +0x565    (0x00007fffcce320b6 <ntdll.dll+0x220b6>)
# 2 ntdll.dll!RtlUserThreadStart    +0x20     (0x00007fffcce5d241 <ntdll.dll+0x4d241>)
Note: @0:00:27.446 in thread 7096
Note: instruction: fxrstor 0x00000100(%rcx)

Error #7: UNINITIALIZED READ: reading 0x000000e5d797beaa-0x000000e5d797beb0 6 byte(s) within 0x000000e5d797bea0-0x000000e5d797bec8
# 0 ntdll.dll!RtlCaptureContext2    +0x409    (0x00007fffcceb0c69 <ntdll.dll+0xa0c69>)
# 1 ntdll.dll!RtlUnwindEx           +0x565    (0x00007fffcce320b6 <ntdll.dll+0x220b6>)
# 2 ntdll.dll!RtlUserThreadStart    +0x20     (0x00007fffcce5d241 <ntdll.dll+0x4d241>)
Note: @0:00:27.446 in thread 7096
Note: instruction: iret   %rsp (%rsp) -> %rsp

Error #8: POSSIBLE LEAK 1624 direct bytes 0x000002e234ae07e0-0x000002e234ae0e38 + 14973 indirect bytes
# 0 replace_realloc               [d:\a\drmemory\drmemory\common\alloc_replace.c:2672]
# 1 l_alloc                       [C:\dll\lua\lauxlib.c:1005]
# 2 luaL_newstate                 [C:\dll\lua\lauxlib.c:1076]
# 3 main                          [C:\dll\lua\lua.c:645]

===========================================================================
FINAL SUMMARY:

DUPLICATE ERROR COUNTS:
Error #   3:     12
Error #   7:      3

SUPPRESSIONS USED:

ERRORS FOUND:
      0 unique,     0 total unaddressable access(es)
      7 unique,    20 total uninitialized access(es)
      0 unique,     0 total invalid heap argument(s)
      0 unique,     0 total GDI usage error(s)
      0 unique,     0 total handle leak(s)
      0 unique,     0 total warning(s)
      0 unique,     0 total,      0 byte(s) of leak(s)
      1 unique,     1 total,  16597 byte(s) of possible leak(s)
ERRORS IGNORED:
   3621 potential error(s) (suspected false positives)
         (details: c:\tmp\DrMemory-lua.exe.5764.000\potential_errors.txt)
     14 potential leak(s) (suspected false positives)
         (details: c:\tmp\DrMemory-lua.exe.5764.000\potential_errors.txt)
    600 unique,  1671 total, 155269 byte(s) of still-reachable allocation(s)
         (re-run with "-show_reachable" for details)
Details: c:\tmp\DrMemory-lua.exe.5764.000\results.txt
 
I am not saying that there is a problem with Lua, it may be a defect in the tool.
Can anyone else confirm?

regards,
Ranier Vilela
Reply | Threaded
Open this post in threaded view
|

Re: Lua stack clean

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

> Em qua., 24 de fev. de 2021 às 23:17, Ranier Vilela <[hidden email]>
> escreveu:
>
> > Em qua., 24 de fev. de 2021 às 22:54, Sean Conner <[hidden email]>
> > escreveu:
> >
> >> > I have a bug reading an invalid pointer, in an adjacent library, which
> >> I'm
> >> > not sure is caused by Lua gc.
> >>
> >>   It may be an issue over who owns the memory for the userdata, but
> >> without
> >> knowing the exact error, it's hard to say.
> >>
> > Lua owns the pointer.
> > The code is run many times, then magically the "feeefeeefeeefeee" pointer
> > appears.
> > I need to make sure that there are no mistakes part of Lua C api.
> >
> Regarding the problem, I can already say with certainty that it is the case
> of:
> user-after-free
> https://stackoverflow.com/questions/2436020/detecting-use-after-free-on-windows-dangling-pointers

  I don't use Windows so I can't check this, but it sounds like the
following might be happening:

        * There is a userdata on the stack (either as a parameter to the C
          based function, or via calling a Lua function from C).

        * You grab the pointer to the user data.

        * You cleanup the stack, thus removing the stack entry with the
          userdata.

        * A GC is triggered and the userdata has no hard reference in the
          Lua state, so the __gc() method is called.

        * The pointer is then used, thus triggering the issue.

  -spc (Just a thought ... )
Reply | Threaded
Open this post in threaded view
|

Re: Lua stack clean

Ranier Vilela-2
Em sex., 26 de fev. de 2021 às 22:25, Sean Conner <[hidden email]> escreveu:
It was thus said that the Great Ranier Vilela once stated:
> Em qua., 24 de fev. de 2021 às 23:17, Ranier Vilela <[hidden email]>
> escreveu:
>
> > Em qua., 24 de fev. de 2021 às 22:54, Sean Conner <[hidden email]>
> > escreveu:
> >
> >> > I have a bug reading an invalid pointer, in an adjacent library, which
> >> I'm
> >> > not sure is caused by Lua gc.
> >>
> >>   It may be an issue over who owns the memory for the userdata, but
> >> without
> >> knowing the exact error, it's hard to say.
> >>
> > Lua owns the pointer.
> > The code is run many times, then magically the "feeefeeefeeefeee" pointer
> > appears.
> > I need to make sure that there are no mistakes part of Lua C api.
> >
> Regarding the problem, I can already say with certainty that it is the case
> of:
> user-after-free
> https://stackoverflow.com/questions/2436020/detecting-use-after-free-on-windows-dangling-pointers

  I don't use Windows so I can't check this, but it sounds like the
following might be happening:

        * There is a userdata on the stack (either as a parameter to the C
          based function, or via calling a Lua function from C).
Yes correct.


        * You grab the pointer to the user data.
Again, that's right.


        * You cleanup the stack, thus removing the stack entry with the
          userdata.
I'm not sure. It has occurred and corrects this type of problem before. Now it looks different.
No Lua code releases the "userdata" variable.
No C code releases the variable, at least intentionally.
Only a few lua_pop remain, carefully placed, following your recommendations.


        * A GC is triggered and the userdata has no hard reference in the
          Lua state, so the __gc() method is called.
I'm not sure.
Put "breakpoints" and printfs on all relevant __gc, none were triggered.
 

        * The pointer is then used, thus triggering the issue.
This case looks different, the affected pointer is part of a structure (the userdata), which looks intact.
It seems that the adjacent library itself is releasing it.
But I still haven't managed to debug it correctly.

When I go to the DrMemory tool, which could help,
it stops and complains about the Lua C code, even before executing the main routines.
DrMemory already pointed out some real problems on other occasions.
 
regards,
Ranier Vilela
Reply | Threaded
Open this post in threaded view
|

Re: Lua stack clean

Ranier Vilela-2
In reply to this post by Sean Conner
Em sex., 26 de fev. de 2021 às 22:25, Sean Conner <[hidden email]> escreveu:
        * You cleanup the stack, thus removing the stack entry with the
          userdata.
In your opinion, this code is correct?

if (lua_getmetatable(L, 2)) {
    lua_getfield(L, -1, "namefield");
    if (lua_isuserdata(L, -1)) {
         MyCtype func = (MyCtype) lua_touserdata(L, -1);
          int n = 1;

          if (func != NULL) {
              void * child = lua_touserdata(L, 2);

              control = (*func)(child);
              ++n; /* pop child */
          }
          lua_pop(L, n); /* pop child and MyCType */
     }
}
 
regards,
Ranier Vilela
Reply | Threaded
Open this post in threaded view
|

Re: Lua stack clean

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

> Em sex., 26 de fev. de 2021 às 22:25, Sean Conner <[hidden email]>
> escreveu:
>
> >         * You cleanup the stack, thus removing the stack entry with the
> >           userdata.
> >
> In your opinion, this code is correct?
>
> if (lua_getmetatable(L, 2)) {
>     lua_getfield(L, -1, "namefield");
>     if (lua_isuserdata(L, -1)) {
>          MyCtype func = (MyCtype) lua_touserdata(L, -1);
>           int n = 1;
>
>           if (func != NULL) {
>               void * child = lua_touserdata(L, 2);
>
>               control = (*func)(child);
>               ++n; /* pop child */
>           }
>           lua_pop(L, n); /* pop child and MyCType */
>      }
> }

  I would write this as:

        int mylua_func(lua_State *L)
        {
          MyCtype func = luaL_checkudata(L,2,"MyCtype");
         
          /*-------------------------------------------------------------
          ; func will NOT be null, if the stack item isn't a userdata or
          ; have the proper metatable, luaL_checkudata() will throw an
          ; error.  You also do NOT need the casts if you writing in C.  If
          ; this is C++, then yes, you will need the cast.
          ;--------------------------------------------------------------*/
         
          if (luaL_getmetafield(L,2,"namefield"))
          {
            /*-----------------------------------------------------------
            ; luaL_getmetafield() will return 1 if there is a field of the
            ; given name in the metatable, and push the item on the stack.
            ; It will return 0 and NOT push any data if the field doesn't
            ; exist.
            ;-------------------------------------------------------------*/
           
            (*func)(luaL_checkudata(L,-1,"myothertype"));
            lua_pop(L,1);
          }
        }

  The auxilary library has a lot of convenience functions.
 
  -spc
Reply | Threaded
Open this post in threaded view
|

Re: Lua stack clean

Ranier Vilela-2
Em dom., 28 de fev. de 2021 às 22:11, Sean Conner <[hidden email]> escreveu:
It was thus said that the Great Ranier Vilela once stated:
> Em sex., 26 de fev. de 2021 às 22:25, Sean Conner <[hidden email]>
> escreveu:
>
> >         * You cleanup the stack, thus removing the stack entry with the
> >           userdata.
> >
> In your opinion, this code is correct?
>
> if (lua_getmetatable(L, 2)) {
>     lua_getfield(L, -1, "namefield");
>     if (lua_isuserdata(L, -1)) {
>          MyCtype func = (MyCtype) lua_touserdata(L, -1);
>           int n = 1;
>
>           if (func != NULL) {
>               void * child = lua_touserdata(L, 2);
>
>               control = (*func)(child);
>               ++n; /* pop child */
>           }
>           lua_pop(L, n); /* pop child and MyCType */
>      }
> }

  I would write this as:

        int mylua_func(lua_State *L)
        {
          MyCtype func = luaL_checkudata(L,2,"MyCtype");

          /*-------------------------------------------------------------
          ; func will NOT be null, if the stack item isn't a userdata or
          ; have the proper metatable, luaL_checkudata() will throw an
          ; error.  You also do NOT need the casts if you writing in C.  If
          ; this is C++, then yes, you will need the cast.
          ;--------------------------------------------------------------*/

          if (luaL_getmetafield(L,2,"namefield"))
          {
            /*-----------------------------------------------------------
            ; luaL_getmetafield() will return 1 if there is a field of the
            ; given name in the metatable, and push the item on the stack.
            ; It will return 0 and NOT push any data if the field doesn't
            ; exist.
            ;-------------------------------------------------------------*/

            (*func)(luaL_checkudata(L,-1,"myothertype"));
            lua_pop(L,1);
          }
        }

  The auxilary library has a lot of convenience functions.
Thanks for the answer, I will try.

regards,
Ranier Vilela
Reply | Threaded
Open this post in threaded view
|

Re: Lua stack clean

Ranier Vilela-2
In reply to this post by Sean Conner
Em dom., 28 de fev. de 2021 às 22:11, Sean Conner <[hidden email]> escreveu:
It was thus said that the Great Ranier Vilela once stated:
> Em sex., 26 de fev. de 2021 às 22:25, Sean Conner <[hidden email]>
> escreveu:
>
> >         * You cleanup the stack, thus removing the stack entry with the
> >           userdata.
> >
> In your opinion, this code is correct?
>
> if (lua_getmetatable(L, 2)) {
>     lua_getfield(L, -1, "namefield");
>     if (lua_isuserdata(L, -1)) {
>          MyCtype func = (MyCtype) lua_touserdata(L, -1);
>           int n = 1;
>
>           if (func != NULL) {
>               void * child = lua_touserdata(L, 2);
>
>               control = (*func)(child);
>               ++n; /* pop child */
>           }
>           lua_pop(L, n); /* pop child and MyCType */
>      }
> }

  I would write this as:

        int mylua_func(lua_State *L)
        {
          MyCtype func = luaL_checkudata(L,2,"MyCtype");

          /*-------------------------------------------------------------
          ; func will NOT be null, if the stack item isn't a userdata or
          ; have the proper metatable, luaL_checkudata() will throw an
          ; error.  You also do NOT need the casts if you writing in C.  If
          ; this is C++, then yes, you will need the cast.
          ;--------------------------------------------------------------*/

          if (luaL_getmetafield(L,2,"namefield"))
          {
            /*-----------------------------------------------------------
            ; luaL_getmetafield() will return 1 if there is a field of the
            ; given name in the metatable, and push the item on the stack.
            ; It will return 0 and NOT push any data if the field doesn't
            ; exist.
            ;-------------------------------------------------------------*/

            (*func)(luaL_checkudata(L,-1,"myothertype"));
            lua_pop(L,1);
          }
        }

  The auxilary library has a lot of convenience functions.
Hi Sean Conner,
The code stayed like this:

    if (luaL_callmeta(L, 3, "__tocontrol")) {  /* metafield? */
        control = lua_touserdata(L, -1);
        lua_pop(L, 1);
    }
 
Thanks to your tips, the solution was similar to tostring.

regards,
Ranier Vilela