Access to a Lua variable in a function environment from C ++

This is probably a simple question, but I'm at a standstill. This is for Lua 5.1.

I have a script that works in my environment. In this environment, I have a variable called a β€œplugin” that I installed from C ++, for example:

lua_getfield(L, LUA_REGISTRYINDEX, getScriptId()); // Put script env table onto the stack -- env_table lua_pushstring(L, "plugin"); // -- env_table, "plugin" luaW_push(L, this); // -- env_table, "plugin", *this lua_rawset(L, -3); // env_table["plugin"] = *this -- env_table lua_pop(L, -1); // Cleanup -- <<empty stack>> 

Before running my Lua script, I installed the following functional environment:

  lua_getfield(L, LUA_REGISTRYINDEX, getScriptId()); // Push REGISTRY[scriptId] onto stack -- function, table lua_setfenv(L, -2); // Set that table to be the env for function -- function 

When my script works, it can see and interact with the plugin variable, as expected. So far, so good.

At some point, the Lua script calls the C ++ function, and in this function I want to find out if the plugin variable is set.

I have tried many things and I can not see the plugin variable. Here are just 4 things I've tried:

 lua_getfield(L, LUA_ENVIRONINDEX, "plugin"); bool isPlugin = !lua_isnil(L, -1); lua_pop(L, 1); // Remove the value we just added from the stack lua_getfield(L, LUA_GLOBALSINDEX, "plugin"); bool isPlugin2 = !lua_isnil(L, -1); lua_pop(L, 1); // Remove the value we just added from the stack lua_getglobal(L, "plugin"); bool isPlugin3 = !lua_isnil(L, -1); lua_pop(L, 1); // Remove the value we just added from the stack lua_pushstring(L, "plugin"); bool isPlugin4 = lua_isuserdata(L, -1); lua_pop(L, 1); 

Unfortunately, all isPlugin variables return false. It is as if the C ++ function called from Lua cannot see the variable set in the Lua environment.

Any idea how I can see the plugin variable from C ++?

Thanks!

+4
source share
2 answers

Each function in Lua has its own environment. They do not inherit the environment of those who call them. Therefore, if your C ++ function does not use the environment with this plugin variable, it will not see it.

+2
source

You can pass the environment to the C function as part of the closure (see lua_pushcclosure ). I don’t know what your setup is, but I see three ways this can unfold:

1) Your C function is registered in the same environment as the function - good, it will work.
2) The C function is registered in the global environment, but the Lua functions that will call it all in one particular environment will work if the environment exists when the function is registered (therefore, it can be added to closure). <w> 3) Your C function is registered in the global environment and can be called by various Lua functions working in different environments - will no longer work.

If it's 2 or 3, there might be flaws if you change the implementation to use option 1.

Edit: Good, so this will not work. There is a way to get information under the hood if you want to stray a bit from the Lua API. DISCLAIMER: I work with 5.2, so I'm trying to adapt my methods to 5.1. I could not verify this, and this may not work.

First you need #include "lstate.h"

This is the lua_State structure in 5.1 format:

 struct lua_State { CommonHeader; lu_byte status; StkId top; /* first free slot in the stack */ StkId base; /* base of current function */ global_State *l_G; CallInfo *ci; /* call info for current function */ const Instruction *savedpc; /* `savedpc' of current function */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ CallInfo *end_ci; /* points after end of ci array*/ CallInfo *base_ci; /* array of CallInfo */ int stacksize; int size_ci; /* size of array `base_ci' */ unsigned short nCcalls; /* number of nested C calls */ lu_byte hookmask; lu_byte allowhook; int basehookcount; int hookcount; lua_Hook hook; TValue l_gt; /* table of globals */ TValue env; /* temporary place for environments */ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ ptrdiff_t errfunc; /* current error handling function (stack index) */ }; 

Suppose L is your lua_State* . As you can see, L->ci contains the current callinfo, and the callinfo array is between L->base_ci and L->end_ci .

So the Lua function that called your C function is in (L->end_ci-2) (which should be the same as (L->ci-1) ) and its stack id (StkId) is (L->end_ci-2)->func . We can trick the Lua API so that you can work with stack identifiers that are below the current call function by doing something like this:

 StkId saved = L->base; L->base = L->base_ci->base; int idx = (L->end_ci-2)->func - L->base+1; lua_getfenv(L, idx); L->base = saved; 

Now the environment table should be on top of the stack.

Edit: The Lua API validates a valid index, a little complicated. This should trick them.

0
source

Source: https://habr.com/ru/post/1444698/


All Articles