Hide shell functions from _G using upvalues on the main chunk

Store __command, __interactive, __getenv, __setenv as upvalues
populated by lua_load() from the registry, keeping them invisible
to user code while accessible to the parser's codegen.
This commit is contained in:
Cormac Shannon
2026-03-12 22:46:56 +00:00
parent 34bfabccbd
commit f88b17959f
8 changed files with 134 additions and 77 deletions

44
linit.c
View File

@@ -43,41 +43,21 @@ static const luaL_Reg stdlibs[] = {
};
static int luaB_getenv (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
const char *val = getenv(name);
if (val == NULL)
lua_pushnil(L);
else
lua_pushstring(L, val);
return 1;
}
static int luaB_setenv (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
if (lua_isnoneornil(L, 2))
unsetenv(name);
else {
const char *val = luaL_tolstring(L, 2, NULL);
setenv(name, val, 1);
}
return 0;
}
/*
** Register shell built-in globals (called after standard libraries).
** Store shell functions in a registry table at LUA_RIDX_LUSH.
** These are populated as upvalues on the main chunk by lua_load().
*/
static void opencommand (lua_State *L) {
lua_pushcfunction(L, luaB_command);
lua_setglobal(L, "__command");
lua_pushcfunction(L, luaB_interactive);
lua_setglobal(L, "__interactive");
lua_pushcfunction(L, luaB_getenv);
lua_setglobal(L, "__getenv");
lua_pushcfunction(L, luaB_setenv);
lua_setglobal(L, "__setenv");
lua_createtable(L, 0, 5);
lua_pushcfunction(L, lushCmd_command);
lua_setfield(L, -2, "command");
lua_pushcfunction(L, lushCmd_interactive);
lua_setfield(L, -2, "interactive");
lua_pushcfunction(L, lushCmd_getenv);
lua_setfield(L, -2, "getenv");
lua_pushcfunction(L, lushCmd_setenv);
lua_setfield(L, -2, "setenv");
lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_LUSH);
}