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:
45
lparser.c
45
lparser.c
@@ -27,6 +27,7 @@
|
||||
#include "lstate.h"
|
||||
#include "lstring.h"
|
||||
#include "ltable.h"
|
||||
#include "lcmd.h"
|
||||
|
||||
|
||||
|
||||
@@ -499,6 +500,19 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Look up a lush shell function (e.g. __command) that is registered
|
||||
** as an upvalue on the main chunk. singlevaraux will find it directly
|
||||
** as VUPVAL, emitting OP_GETUPVAL instead of OP_GETTABUP.
|
||||
*/
|
||||
static void buildlushvar (LexState *ls, TString *varname, expdesc *var) {
|
||||
FuncState *fs = ls->fs;
|
||||
init_exp(var, VGLOBAL, -1);
|
||||
singlevaraux(fs, varname, var, 1);
|
||||
lua_assert(var->k == VUPVAL); /* must be found as upvalue */
|
||||
}
|
||||
|
||||
|
||||
static void buildglobal (LexState *ls, TString *varname, expdesc *var) {
|
||||
FuncState *fs = ls->fs;
|
||||
expdesc key;
|
||||
@@ -552,8 +566,8 @@ static void codecommand (LexState *ls, expdesc *v, expdesc *cmdstr) {
|
||||
expdesc func;
|
||||
TString *cmdname = luaX_newstring(ls, "__command", 9);
|
||||
line = ls->linenumber;
|
||||
/* look up __command as _ENV["__command"] */
|
||||
buildglobal(ls, cmdname, &func);
|
||||
/* look up __command as upvalue */
|
||||
buildlushvar(ls, cmdname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
base = func.u.info;
|
||||
/* push the command string argument */
|
||||
@@ -1243,7 +1257,7 @@ static void commandexp (LexState *ls, expdesc *v) {
|
||||
TString *cmdname = luaX_newstring(ls, "__command", 9);
|
||||
TString *tsname = luaX_newstring(ls, "tostring", 8);
|
||||
/* load __command function first so it occupies the base register */
|
||||
buildglobal(ls, cmdname, &func);
|
||||
buildlushvar(ls, cmdname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
base = func.u.info;
|
||||
/* load the first fragment */
|
||||
@@ -1308,7 +1322,7 @@ static void codeenvget (LexState *ls, expdesc *v, TString *name) {
|
||||
expdesc func, arg;
|
||||
TString *fname = luaX_newstring(ls, "__getenv", 8);
|
||||
line = ls->linenumber;
|
||||
buildglobal(ls, fname, &func);
|
||||
buildlushvar(ls, fname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
base = func.u.info;
|
||||
codestring(&arg, name);
|
||||
@@ -2193,7 +2207,7 @@ static void envstat (LexState *ls) {
|
||||
luaX_next(ls); /* skip TK_ENVVAR */
|
||||
checknext(ls, '=');
|
||||
fname = luaX_newstring(ls, "__setenv", 8);
|
||||
buildglobal(ls, fname, &func);
|
||||
buildlushvar(ls, fname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
base = func.u.info;
|
||||
codestring(&arg, name);
|
||||
@@ -2219,7 +2233,7 @@ static void interactivestat (LexState *ls) {
|
||||
expdesc func, cmdstr, v;
|
||||
TString *fname = luaX_newstring(ls, "__interactive", 13);
|
||||
line = ls->linenumber;
|
||||
buildglobal(ls, fname, &func);
|
||||
buildlushvar(ls, fname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
base = func.u.info;
|
||||
codestring(&cmdstr, ls->t.seminfo.ts);
|
||||
@@ -2236,7 +2250,7 @@ static void interactivestat (LexState *ls) {
|
||||
int line = ls->linenumber;
|
||||
TString *fname = luaX_newstring(ls, "__interactive", 13);
|
||||
TString *tsname = luaX_newstring(ls, "tostring", 8);
|
||||
buildglobal(ls, fname, &func);
|
||||
buildlushvar(ls, fname, &func);
|
||||
luaK_exp2nextreg(fs, &func);
|
||||
base = func.u.info;
|
||||
/* load the first fragment */
|
||||
@@ -2396,8 +2410,12 @@ static void statement (LexState *ls) {
|
||||
** upvalue named LUA_ENV
|
||||
*/
|
||||
static void mainfunc (LexState *ls, FuncState *fs) {
|
||||
static const char *const lush_upval_names[] = {
|
||||
"__command", "__interactive", "__getenv", "__setenv"
|
||||
};
|
||||
BlockCnt bl;
|
||||
Upvaldesc *env;
|
||||
int i;
|
||||
open_func(ls, fs, &bl);
|
||||
setvararg(fs, PF_ISVARARG); /* main function is always vararg */
|
||||
env = allocupvalue(fs); /* ...set environment upvalue */
|
||||
@@ -2406,6 +2424,15 @@ static void mainfunc (LexState *ls, FuncState *fs) {
|
||||
env->kind = VDKREG;
|
||||
env->name = ls->envn;
|
||||
luaC_objbarrier(ls->L, fs->f, env->name);
|
||||
/* allocate upvalues for lush shell functions */
|
||||
for (i = 0; i < 4; i++) {
|
||||
Upvaldesc *uv = allocupvalue(fs);
|
||||
uv->instack = 1;
|
||||
uv->idx = 0;
|
||||
uv->kind = VDKREG;
|
||||
uv->name = luaS_new(ls->L, lush_upval_names[i]);
|
||||
luaC_objbarrier(ls->L, fs->f, uv->name);
|
||||
}
|
||||
luaX_next(ls); /* read first token */
|
||||
statlist(ls); /* parse main body */
|
||||
check(ls, TK_EOS);
|
||||
@@ -2417,7 +2444,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||
Dyndata *dyd, const char *name, int firstchar) {
|
||||
LexState lexstate;
|
||||
FuncState funcstate;
|
||||
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
|
||||
LClosure *cl = luaF_newLclosure(L, LUSH_NUM_UPVALS); /* create main closure */
|
||||
setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
|
||||
luaD_inctop(L);
|
||||
lexstate.h = luaH_new(L); /* create table for scanner */
|
||||
@@ -2432,7 +2459,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
|
||||
luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar);
|
||||
mainfunc(&lexstate, &funcstate);
|
||||
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
|
||||
lua_assert(!funcstate.prev && funcstate.nups == LUSH_NUM_UPVALS && !lexstate.fs);
|
||||
/* all scopes should be correctly finished */
|
||||
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
|
||||
L->top.p--; /* remove scanner's table */
|
||||
|
||||
Reference in New Issue
Block a user