lua-users home
lua-l archive

Re: Call to __len metamethod has userdata/table twice on stack

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On 16/02/17 07:28 PM, tobias@justdreams.de wrote:
Hi,
I came across an odd behaviour where the call to a __len function has 2 identical stack items. I also tested __tostring and it does have only one item. Test code:
len_fail.c
// vim: ts=4 sw=4 st=4 sta tw=80 list
#include <stdio.h>
#include <string.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#define FOO_TYPE "TYPE_OF_FOO"
// compile:
// gcc -O3 -Wall -Werror -I/usr/include len_fail.c -o len_fail -llua
lua_State *L;
typedef struct Foo {
 size_t len;
} Foo;
const char luascript [] = {
 "print( uservalue ) -- invokes tostring\n"
 "print( type( uservalue ) )\n"
 "print( 'Length:', #uservalue )\n"
};
// meta function
static int f__len( lua_State *L )
{
 printf( "STACKSIZE SHOULD BE 1 but is %d\n", lua_gettop( L ) );
 Foo *foo1 = (Foo *) luaL_checkudata( L, 1, FOO_TYPE );
 // this prooves the second stack item is the same as the first
 Foo *foo2 = (Foo *) luaL_checkudata( L, 2, FOO_TYPE );
 printf( "Found items: 1[%p] 2[%p]\n", foo1, foo2 );
 lua_pushinteger( L, foo1->len );
 return 1;
}
static int f__tostring( lua_State *L )
{
 printf( "STACKSIZE SHOULD BE 1 and is %d\n", lua_gettop( L ) );
 Foo *foo = (Foo *) luaL_checkudata( L, 1, FOO_TYPE );
 lua_pushfstring( L, FOO_TYPE"[%d]: %p", foo->len, foo );
 return 1;
}
static const luaL_Reg foo_m [] = {
 { "__len" , f__len }
 , { "__tostring" , f__tostring }
 , { NULL , NULL}
};
int main ( int argc, char *argv[] )
{
 argc=argc;
 argv[0]=argv[0]; // make -Wall -Werror happy
 L = luaL_newstate();
 luaL_openlibs(L);
 Foo *foo = (Foo *) lua_newuserdata(L, sizeof (Foo));
 foo->len = 12;
 luaL_newmetatable( L, FOO_TYPE );
 luaL_setfuncs( L, foo_m, 0 );
 lua_setmetatable( L, -2 );
 lua_setglobal( L, "uservalue" );
 luaL_loadstring( L, luascript );
 if (lua_pcall( L, 0, LUA_MULTRET, 0 ))
 printf( "%s\n", lua_tostring(L, -1) );
 // cleanup Lua
 lua_close(L);
 return 0;
}
And here is the output:
[arch@tk lua_sample]$ ./len_fail
STACKSIZE SHOULD BE 1 but is 1
TYPE_OF_FOO[12]: 0xcbebc8
userdata
STACKSIZE SHOULD BE 1 but is 2
Found items: 1[0xcbebc8] 2[0xcbebc8]
Length: 12
[arch@tk lua_sample]$
Thoughts?
 -Tobias
Also with unm and bnot:
"For the unary operators (negation, length, and bitwise NOT), the metamethod is computed and called with a dummy second operand, equal to the first one. This extra operand is only to simplify Lua's internals (by making these operators behave like a binary operation) and may be removed in future versions. (For most uses this extra operand is irrelevant.)"
--
Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.

AltStyle によって変換されたページ (->オリジナル) /