diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-31 10:43:51 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-31 10:43:51 -0300 |
commit | f645d3157372c73573dff221c5b26691cb0e7d56 (patch) | |
tree | 61adb1f332bbd8c0c0365b81cef8de47fa2ea06a /lfunc.c | |
parent | 35b4efc270db2418bc2cac6671575a45028061c3 (diff) | |
download | lua-f645d3157372c73573dff221c5b26691cb0e7d56.tar.gz lua-f645d3157372c73573dff221c5b26691cb0e7d56.tar.bz2 lua-f645d3157372c73573dff221c5b26691cb0e7d56.zip |
To-be-closed variables must be closed on initialization
When initializing a to-be-closed variable, check whether it has a
'__close' metamethod (or is a false value) and raise an error if
if it hasn't. This produces more accurate error messages. (The
check before closing still need to be done: in the C API, the value
is not constant; and the object may lose its '__close' metamethod
during the block.)
Diffstat (limited to 'lfunc.c')
-rw-r--r-- | lfunc.c | 49 |
1 files changed, 32 insertions, 17 deletions
@@ -124,11 +124,23 @@ static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { | |||
124 | 124 | ||
125 | 125 | ||
126 | /* | 126 | /* |
127 | ** Raise an error with message 'msg', inserting the name of the | ||
128 | ** local variable at position 'level' in the stack. | ||
129 | */ | ||
130 | static void varerror (lua_State *L, StkId level, const char *msg) { | ||
131 | int idx = cast_int(level - L->ci->func); | ||
132 | const char *vname = luaG_findlocal(L, L->ci, idx, NULL); | ||
133 | if (vname == NULL) vname = "?"; | ||
134 | luaG_runerror(L, msg, vname); | ||
135 | } | ||
136 | |||
137 | |||
138 | /* | ||
127 | ** Prepare and call a closing method. If status is OK, code is still | 139 | ** Prepare and call a closing method. If status is OK, code is still |
128 | ** inside the original protected call, and so any error will be handled | 140 | ** inside the original protected call, and so any error will be handled |
129 | ** there. Otherwise, a previous error already activated original | 141 | ** there. Otherwise, a previous error already activated the original |
130 | ** protected call, and so the call to the closing method must be | 142 | ** protected call, and so the call to the closing method must be |
131 | ** protected here. (A status = CLOSEPROTECT behaves like a previous | 143 | ** protected here. (A status == CLOSEPROTECT behaves like a previous |
132 | ** error, to also run the closing method in protected mode). | 144 | ** error, to also run the closing method in protected mode). |
133 | ** If status is OK, the call to the closing method will be pushed | 145 | ** If status is OK, the call to the closing method will be pushed |
134 | ** at the top of the stack. Otherwise, values are pushed after | 146 | ** at the top of the stack. Otherwise, values are pushed after |
@@ -140,12 +152,8 @@ static int callclosemth (lua_State *L, StkId level, int status) { | |||
140 | if (likely(status == LUA_OK)) { | 152 | if (likely(status == LUA_OK)) { |
141 | if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ | 153 | if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ |
142 | callclose(L, NULL); /* call closing method */ | 154 | callclose(L, NULL); /* call closing method */ |
143 | else if (!ttisnil(uv)) { /* non-closable non-nil value? */ | 155 | else if (!l_isfalse(uv)) /* non-closable non-false value? */ |
144 | int idx = cast_int(level - L->ci->func); | 156 | varerror(L, level, "attempt to close non-closable variable '%s'"); |
145 | const char *vname = luaG_findlocal(L, L->ci, idx, NULL); | ||
146 | if (vname == NULL) vname = "?"; | ||
147 | luaG_runerror(L, "attempt to close non-closable variable '%s'", vname); | ||
148 | } | ||
149 | } | 157 | } |
150 | else { /* must close the object in protected mode */ | 158 | else { /* must close the object in protected mode */ |
151 | ptrdiff_t oldtop; | 159 | ptrdiff_t oldtop; |
@@ -170,9 +178,7 @@ static int callclosemth (lua_State *L, StkId level, int status) { | |||
170 | ** (can raise a memory-allocation error) | 178 | ** (can raise a memory-allocation error) |
171 | */ | 179 | */ |
172 | static void trynewtbcupval (lua_State *L, void *ud) { | 180 | static void trynewtbcupval (lua_State *L, void *ud) { |
173 | StkId level = cast(StkId, ud); | 181 | newupval(L, 1, cast(StkId, ud), &L->openupval); |
174 | lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); | ||
175 | newupval(L, 1, level, &L->openupval); | ||
176 | } | 182 | } |
177 | 183 | ||
178 | 184 | ||
@@ -182,13 +188,22 @@ static void trynewtbcupval (lua_State *L, void *ud) { | |||
182 | ** as there is no upvalue to call it later. | 188 | ** as there is no upvalue to call it later. |
183 | */ | 189 | */ |
184 | void luaF_newtbcupval (lua_State *L, StkId level) { | 190 | void luaF_newtbcupval (lua_State *L, StkId level) { |
185 | int status = luaD_rawrunprotected(L, trynewtbcupval, level); | 191 | TValue *obj = s2v(level); |
186 | if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ | 192 | lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); |
187 | lua_assert(status == LUA_ERRMEM); | 193 | if (!l_isfalse(obj)) { /* false doesn't need to be closed */ |
188 | luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ | 194 | int status; |
189 | if (prepclosingmethod(L, s2v(level), s2v(level + 1))) | 195 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); |
196 | if (ttisnil(tm)) /* no metamethod? */ | ||
197 | varerror(L, level, "variable '%s' got a non-closable value"); | ||
198 | status = luaD_rawrunprotected(L, trynewtbcupval, level); | ||
199 | if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ | ||
200 | lua_assert(status == LUA_ERRMEM); | ||
201 | luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ | ||
202 | /* next call must succeed, as object is closable */ | ||
203 | prepclosingmethod(L, s2v(level), s2v(level + 1)); | ||
190 | callclose(L, NULL); /* call closing method */ | 204 | callclose(L, NULL); /* call closing method */ |
191 | luaD_throw(L, LUA_ERRMEM); /* throw memory error */ | 205 | luaD_throw(L, LUA_ERRMEM); /* throw memory error */ |
206 | } | ||
192 | } | 207 | } |
193 | } | 208 | } |
194 | 209 | ||