aboutsummaryrefslogtreecommitdiff
path: root/lfunc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-12-29 10:23:02 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-12-29 10:23:02 -0300
commit59e565d9555c07e82808d8c1db8f4f4d159b5e5c (patch)
tree7dced733d2e01a6060d656afad903539ac2fedc9 /lfunc.c
parent6188f3a654c0380db08eb40a5465ce8e71c784f5 (diff)
downloadlua-59e565d9555c07e82808d8c1db8f4f4d159b5e5c.tar.gz
lua-59e565d9555c07e82808d8c1db8f4f4d159b5e5c.tar.bz2
lua-59e565d9555c07e82808d8c1db8f4f4d159b5e5c.zip
No need to recheck close method before calling it
A to-be-closed variable is constant and it must have a close metamethod when it is created. A program has to go out of its way (e.g., by changing the variable's metamethod) to invalidate that check. So, it is not worth to test that again. If the program tampers with the metamethod, Lua will raise a regular error when attempting to call it.
Diffstat (limited to 'lfunc.c')
-rw-r--r--lfunc.c44
1 files changed, 19 insertions, 25 deletions
diff --git a/lfunc.c b/lfunc.c
index ae68487c..a8030afa 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -101,31 +101,32 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
101 101
102 102
103/* 103/*
104** Prepare closing method plus its arguments for object 'obj' with 104** Call closing method for object 'obj' with error message 'err'.
105** error message 'err'. (This function assumes EXTRA_STACK.) 105** (This function assumes EXTRA_STACK.)
106*/ 106*/
107static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { 107static void callclosemethod (lua_State *L, TValue *obj, TValue *err) {
108 StkId top = L->top; 108 StkId top = L->top;
109 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); 109 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
110 if (ttisnil(tm)) /* no metamethod? */
111 return 0; /* nothing to call */
112 setobj2s(L, top, tm); /* will call metamethod... */ 110 setobj2s(L, top, tm); /* will call metamethod... */
113 setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ 111 setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
114 setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ 112 setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
115 L->top = top + 3; /* add function and arguments */ 113 L->top = top + 3; /* add function and arguments */
116 return 1; 114 luaD_callnoyield(L, top, 0); /* call method */
117} 115}
118 116
119 117
120/* 118/*
121** Raise an error with message 'msg', inserting the name of the 119** Check whether 'obj' has a close metamethod and raise an error
122** local variable at position 'level' in the stack. 120** if not.
123*/ 121*/
124static void varerror (lua_State *L, StkId level, const char *msg) { 122static void checkclosemth (lua_State *L, StkId level, const TValue *obj) {
125 int idx = cast_int(level - L->ci->func); 123 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
126 const char *vname = luaG_findlocal(L, L->ci, idx, NULL); 124 if (ttisnil(tm)) { /* no metamethod? */
127 if (vname == NULL) vname = "?"; 125 int idx = cast_int(level - L->ci->func); /* variable index */
128 luaG_runerror(L, msg, vname); 126 const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
127 if (vname == NULL) vname = "?";
128 luaG_runerror(L, "variable '%s' got a non-closable value", vname);
129 }
129} 130}
130 131
131 132
@@ -136,7 +137,7 @@ static void varerror (lua_State *L, StkId level, const char *msg) {
136** the 'level' of the upvalue being closed, as everything after that 137** the 'level' of the upvalue being closed, as everything after that
137** won't be used again. 138** won't be used again.
138*/ 139*/
139static void callclosemth (lua_State *L, StkId level, int status) { 140static void prepcallclosemth (lua_State *L, StkId level, int status) {
140 TValue *uv = s2v(level); /* value being closed */ 141 TValue *uv = s2v(level); /* value being closed */
141 TValue *errobj; 142 TValue *errobj;
142 if (status == CLOSEKTOP) 143 if (status == CLOSEKTOP)
@@ -145,10 +146,7 @@ static void callclosemth (lua_State *L, StkId level, int status) {
145 errobj = s2v(level + 1); /* error object goes after 'uv' */ 146 errobj = s2v(level + 1); /* error object goes after 'uv' */
146 luaD_seterrorobj(L, status, level + 1); /* set error object */ 147 luaD_seterrorobj(L, status, level + 1); /* set error object */
147 } 148 }
148 if (prepclosingmethod(L, uv, errobj)) /* something to call? */ 149 callclosemethod(L, uv, errobj);
149 luaD_callnoyield(L, L->top - 3, 0); /* call method */
150 else if (!l_isfalse(uv)) /* non-closable non-false value? */
151 varerror(L, level, "attempt to close non-closable variable '%s'");
152} 150}
153 151
154 152
@@ -171,16 +169,12 @@ void luaF_newtbcupval (lua_State *L, StkId level) {
171 lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); 169 lua_assert(L->openupval == NULL || uplevel(L->openupval) < level);
172 if (!l_isfalse(obj)) { /* false doesn't need to be closed */ 170 if (!l_isfalse(obj)) { /* false doesn't need to be closed */
173 int status; 171 int status;
174 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); 172 checkclosemth(L, level, obj);
175 if (ttisnil(tm)) /* no metamethod? */
176 varerror(L, level, "variable '%s' got a non-closable value");
177 status = luaD_rawrunprotected(L, trynewtbcupval, level); 173 status = luaD_rawrunprotected(L, trynewtbcupval, level);
178 if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ 174 if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */
179 lua_assert(status == LUA_ERRMEM); 175 lua_assert(status == LUA_ERRMEM);
180 luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ 176 luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */
181 /* next call must succeed, as object is closable */ 177 callclosemethod(L, s2v(level), s2v(level + 1));
182 prepclosingmethod(L, s2v(level), s2v(level + 1));
183 luaD_callnoyield(L, L->top - 3, 0); /* call method */
184 luaD_throw(L, LUA_ERRMEM); /* throw memory error */ 178 luaD_throw(L, LUA_ERRMEM); /* throw memory error */
185 } 179 }
186 } 180 }
@@ -215,7 +209,7 @@ void luaF_close (lua_State *L, StkId level, int status) {
215 } 209 }
216 if (uv->tbc && status != NOCLOSINGMETH) { 210 if (uv->tbc && status != NOCLOSINGMETH) {
217 ptrdiff_t levelrel = savestack(L, level); 211 ptrdiff_t levelrel = savestack(L, level);
218 callclosemth(L, upl, status); /* may change the stack */ 212 prepcallclosemth(L, upl, status); /* may change the stack */
219 level = restorestack(L, levelrel); 213 level = restorestack(L, levelrel);
220 } 214 }
221 } 215 }