diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-10-25 12:50:20 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-10-25 12:50:20 -0300 |
commit | 41c800b352149e037bdebd5f20d2f25ed2a0e2a5 (patch) | |
tree | 740a459fd69d687dfe200fc91762208079e0c25b /testes/locals.lua | |
parent | 0a9aca56caa925c42aaa683b43560357ab736ea4 (diff) | |
download | lua-41c800b352149e037bdebd5f20d2f25ed2a0e2a5.tar.gz lua-41c800b352149e037bdebd5f20d2f25ed2a0e2a5.tar.bz2 lua-41c800b352149e037bdebd5f20d2f25ed2a0e2a5.zip |
Closing methods should not interfere with returning values
A closing method cannot be called in its own stack slot, as there may
be returning values in the stack after that slot, and the call would
corrupt those values. Instead, the closing method must be copied to the
top of the stack to be called.
Moreover, even when a function returns no value, its return istruction
still has to have its position (which will set the stack top) after
the local variables, otherwise a closing method might corrupt another
not-yet-called closing method.
Diffstat (limited to 'testes/locals.lua')
-rw-r--r-- | testes/locals.lua | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/testes/locals.lua b/testes/locals.lua index f21fa2ec..65b145db 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -175,6 +175,9 @@ assert(x==20) | |||
175 | 175 | ||
176 | print"testing to-be-closed variables" | 176 | print"testing to-be-closed variables" |
177 | 177 | ||
178 | local function stack(n) n = ((n == 0) or stack(n - 1)) end | ||
179 | |||
180 | |||
178 | do | 181 | do |
179 | local a = {} | 182 | local a = {} |
180 | do | 183 | do |
@@ -187,6 +190,57 @@ do | |||
187 | assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out") | 190 | assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out") |
188 | end | 191 | end |
189 | 192 | ||
193 | do | ||
194 | local X = false | ||
195 | |||
196 | local function closescope () stack(10); X = true end | ||
197 | |||
198 | -- closing functions do not corrupt returning values | ||
199 | local function foo (x) | ||
200 | local scoped _ = closescope | ||
201 | return x, X, 23 | ||
202 | end | ||
203 | |||
204 | local a, b, c = foo(1.5) | ||
205 | assert(a == 1.5 and b == false and c == 23 and X == true) | ||
206 | |||
207 | X = false | ||
208 | foo = function (x) | ||
209 | local scoped _ = closescope | ||
210 | local y = 15 | ||
211 | return y | ||
212 | end | ||
213 | |||
214 | assert(foo() == 15 and X == true) | ||
215 | |||
216 | X = false | ||
217 | foo = function () | ||
218 | local scoped x = closescope | ||
219 | return x | ||
220 | end | ||
221 | |||
222 | assert(foo() == closescope and X == true) | ||
223 | |||
224 | end | ||
225 | |||
226 | |||
227 | do | ||
228 | -- to-be-closed variables must be closed in tail calls | ||
229 | local X, Y | ||
230 | local function foo () | ||
231 | local scoped _ = function () Y = 10 end | ||
232 | assert(X == 20 and Y == nil) | ||
233 | return 1,2,3 | ||
234 | end | ||
235 | |||
236 | local function bar () | ||
237 | local scoped _ = function () X = 20 end | ||
238 | return foo() | ||
239 | end | ||
240 | |||
241 | local a, b, c, d = bar() | ||
242 | assert(a == 1 and b == 2 and c == 3 and X == 20 and Y == 10 and d == nil) | ||
243 | end | ||
190 | 244 | ||
191 | do -- errors in __close | 245 | do -- errors in __close |
192 | local log = {} | 246 | local log = {} |
@@ -211,7 +265,6 @@ do -- errors in __close | |||
211 | end | 265 | end |
212 | 266 | ||
213 | if rawget(_G, "T") then | 267 | if rawget(_G, "T") then |
214 | local function stack(n) n = (n == 0) or stack(n - 1); end; | ||
215 | -- memory error inside closing function | 268 | -- memory error inside closing function |
216 | local function foo () | 269 | local function foo () |
217 | local scoped y = function () T.alloccount() end | 270 | local scoped y = function () T.alloccount() end |