2
0

locals.lua 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  1. -- $Id: testes/locals.lua $
  2. -- See Copyright Notice in file lua.h
  3. print('testing local variables and environments')
  4. local debug = require"debug"
  5. local tracegc = require"tracegc"
  6. -- bug in 5.1:
  7. local function f(x) x = nil; return x end
  8. assert(f(10) == nil)
  9. local function f() local x; return x end
  10. assert(f(10) == nil)
  11. local function f(x) x = nil; local y; return x, y end
  12. assert(f(10) == nil and select(2, f(20)) == nil)
  13. do
  14. local i = 10
  15. do local i = 100; assert(i==100) end
  16. do local i = 1000; assert(i==1000) end
  17. assert(i == 10)
  18. if i ~= 10 then
  19. local i = 20
  20. else
  21. local i = 30
  22. assert(i == 30)
  23. end
  24. end
  25. f = nil
  26. local f
  27. local x = 1
  28. a = nil
  29. load('local a = {}')()
  30. assert(a == nil)
  31. function f (a)
  32. local _1, _2, _3, _4, _5
  33. local _6, _7, _8, _9, _10
  34. local x = 3
  35. local b = a
  36. local c,d = a,b
  37. if (d == b) then
  38. local x = 'q'
  39. x = b
  40. assert(x == 2)
  41. else
  42. assert(nil)
  43. end
  44. assert(x == 3)
  45. local f = 10
  46. end
  47. local b=10
  48. local a; repeat local b; a,b=1,2; assert(a+1==b); until a+b==3
  49. assert(x == 1)
  50. f(2)
  51. assert(type(f) == 'function')
  52. local function getenv (f)
  53. local a,b = debug.getupvalue(f, 1)
  54. assert(a == '_ENV')
  55. return b
  56. end
  57. -- test for global table of loaded chunks
  58. assert(getenv(load"a=3") == _G)
  59. local c = {}; local f = load("a = 3", nil, nil, c)
  60. assert(getenv(f) == c)
  61. assert(c.a == nil)
  62. f()
  63. assert(c.a == 3)
  64. -- old test for limits for special instructions
  65. do
  66. local i = 2
  67. local p = 4 -- p == 2^i
  68. repeat
  69. for j=-3,3 do
  70. assert(load(string.format([[local a=%s;
  71. a=a+%s;
  72. assert(a ==2^%s)]], j, p-j, i), '')) ()
  73. assert(load(string.format([[local a=%s;
  74. a=a-%s;
  75. assert(a==-2^%s)]], -j, p-j, i), '')) ()
  76. assert(load(string.format([[local a,b=0,%s;
  77. a=b-%s;
  78. assert(a==-2^%s)]], -j, p-j, i), '')) ()
  79. end
  80. p = 2 * p; i = i + 1
  81. until p <= 0
  82. end
  83. print'+'
  84. if rawget(_G, "T") then
  85. -- testing clearing of dead elements from tables
  86. collectgarbage("stop") -- stop GC
  87. local a = {[{}] = 4, [3] = 0, alo = 1,
  88. a1234567890123456789012345678901234567890 = 10}
  89. local t = T.querytab(a)
  90. for k,_ in pairs(a) do a[k] = undef end
  91. collectgarbage() -- restore GC and collect dead fields in 'a'
  92. for i=0,t-1 do
  93. local k = querytab(a, i)
  94. assert(k == nil or type(k) == 'number' or k == 'alo')
  95. end
  96. -- testing allocation errors during table insertions
  97. local a = {}
  98. local function additems ()
  99. a.x = true; a.y = true; a.z = true
  100. a[1] = true
  101. a[2] = true
  102. end
  103. for i = 1, math.huge do
  104. T.alloccount(i)
  105. local st, msg = pcall(additems)
  106. T.alloccount()
  107. local count = 0
  108. for k, v in pairs(a) do
  109. assert(a[k] == v)
  110. count = count + 1
  111. end
  112. if st then assert(count == 5); break end
  113. end
  114. end
  115. -- testing lexical environments
  116. assert(_ENV == _G)
  117. do
  118. local dummy
  119. local _ENV = (function (...) return ... end)(_G, dummy) -- {
  120. do local _ENV = {assert=assert}; assert(true) end
  121. local mt = {_G = _G}
  122. local foo,x
  123. A = false -- "declare" A
  124. do local _ENV = mt
  125. function foo (x)
  126. A = x
  127. do local _ENV = _G; A = 1000 end
  128. return function (x) return A .. x end
  129. end
  130. end
  131. assert(getenv(foo) == mt)
  132. x = foo('hi'); assert(mt.A == 'hi' and A == 1000)
  133. assert(x('*') == mt.A .. '*')
  134. do local _ENV = {assert=assert, A=10};
  135. do local _ENV = {assert=assert, A=20};
  136. assert(A==20);x=A
  137. end
  138. assert(A==10 and x==20)
  139. end
  140. assert(x==20)
  141. A = nil
  142. do -- constants
  143. global assert<const>, load, string, X
  144. X = 1 -- not a constant
  145. local a<const>, b, c<const> = 10, 20, 30
  146. b = a + c + b -- 'b' is not constant
  147. assert(a == 10 and b == 60 and c == 30)
  148. local function checkro (name, code)
  149. local st, msg = load(code)
  150. local gab = string.format("attempt to assign to const variable '%s'", name)
  151. assert(not st and string.find(msg, gab))
  152. end
  153. checkro("y", "local x, y <const>, z = 10, 20, 30; x = 11; y = 12")
  154. checkro("x", "local x <const>, y, z <const> = 10, 20, 30; x = 11")
  155. checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
  156. checkro("foo", "local foo <const> = 10; function foo() end")
  157. checkro("foo", "local foo <const> = {}; function foo() end")
  158. checkro("foo", "global foo <const>; function foo() end")
  159. checkro("XX", "global XX <const>; XX = 10")
  160. checkro("XX", "local _ENV; global XX <const>; XX = 10")
  161. checkro("z", [[
  162. local a, z <const>, b = 10;
  163. function foo() a = 20; z = 32; end
  164. ]])
  165. checkro("var1", [[
  166. local a, var1 <const> = 10;
  167. function foo() a = 20; z = function () var1 = 12; end end
  168. ]])
  169. checkro("var1", [[
  170. global a, var1 <const>, z;
  171. local function foo() a = 20; z = function () var1 = 12; end end
  172. ]])
  173. end
  174. print"testing to-be-closed variables"
  175. local function stack(n) n = ((n == 0) or stack(n - 1)) end
  176. local function func2close (f, x, y)
  177. local obj = setmetatable({}, {__close = f})
  178. if x then
  179. return x, obj, y
  180. else
  181. return obj
  182. end
  183. end
  184. do
  185. local a = {}
  186. do
  187. local b <close> = false -- not to be closed
  188. local x <close> = setmetatable({"x"}, {__close = function (self)
  189. a[#a + 1] = self[1] end})
  190. local w, y <close>, z = func2close(function (self, err)
  191. assert(err == nil); a[#a + 1] = "y"
  192. end, 10, 20)
  193. local c <close> = nil -- not to be closed
  194. a[#a + 1] = "in"
  195. assert(w == 10 and z == 20)
  196. end
  197. a[#a + 1] = "out"
  198. assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out")
  199. end
  200. do
  201. local X = false
  202. local x, closescope = func2close(function (_, msg)
  203. stack(10);
  204. assert(msg == nil)
  205. X = true
  206. end, 100)
  207. assert(x == 100); x = 101; -- 'x' is not read-only
  208. -- closing functions do not corrupt returning values
  209. local function foo (x)
  210. local _ <close> = closescope
  211. return x, X, 23
  212. end
  213. local a, b, c = foo(1.5)
  214. assert(a == 1.5 and b == false and c == 23 and X == true)
  215. X = false
  216. foo = function (x)
  217. local _<close> = func2close(function (_, msg)
  218. -- without errors, enclosing function should be still active when
  219. -- __close is called
  220. assert(debug.getinfo(2).name == "foo")
  221. assert(msg == nil)
  222. end)
  223. local _<close> = closescope
  224. local y = 15
  225. return y
  226. end
  227. assert(foo() == 15 and X == true)
  228. X = false
  229. foo = function ()
  230. local x <close> = closescope
  231. return x
  232. end
  233. assert(foo() == closescope and X == true)
  234. end
  235. do -- testing presence of second argument
  236. local function foo (howtoclose, obj, n)
  237. local ca -- copy of 'a' visible inside its close metamethod
  238. do
  239. local a <close> = func2close(function (...)
  240. local t = table.pack(...)
  241. assert(select("#", ...) == n)
  242. assert(t.n == n and t[1] == ca and (t.n < 2 or t[2] == obj))
  243. ca = 15 -- final value to be returned if howtoclose=="scope"
  244. end)
  245. ca = a
  246. if howtoclose == "ret" then return obj -- 'a' closed by return
  247. elseif howtoclose == "err" then error(obj) -- 'a' closed by error
  248. end
  249. end -- 'a' closed by end of scope
  250. return ca -- ca now should be 15
  251. end
  252. -- with no errors, closing methods receive no extra argument
  253. assert(foo("scope", nil, 1) == 15) -- close by end of scope
  254. assert(foo("ret", 32, 1) == 32) -- close by return
  255. -- with errors, they do
  256. local st, msg = pcall(foo, "err", 23, 2) -- close by error
  257. assert(not st and msg == 23)
  258. end
  259. -- testing to-be-closed x compile-time constants
  260. -- (there were some bugs here in Lua 5.4-rc3, due to a confusion
  261. -- between compile levels and stack levels of variables)
  262. do
  263. local flag = false
  264. local x = setmetatable({},
  265. {__close = function() assert(flag == false); flag = true end})
  266. local y <const> = nil
  267. local z <const> = nil
  268. do
  269. local a <close> = x
  270. end
  271. assert(flag) -- 'x' must be closed here
  272. end
  273. do
  274. -- similar problem, but with implicit close in for loops
  275. local flag = false
  276. local x = setmetatable({},
  277. {__close = function () assert(flag == false); flag = true end})
  278. -- return an empty iterator, nil, nil, and 'x' to be closed
  279. local function a ()
  280. return (function () return nil end), nil, nil, x
  281. end
  282. local v <const> = 1
  283. local w <const> = 1
  284. local x <const> = 1
  285. local y <const> = 1
  286. local z <const> = 1
  287. for k in a() do
  288. a = k
  289. end -- ending the loop must close 'x'
  290. assert(flag) -- 'x' must be closed here
  291. end
  292. do
  293. -- calls cannot be tail in the scope of to-be-closed variables
  294. local X, Y
  295. local function foo ()
  296. local _ <close> = func2close(function () Y = 10 end)
  297. assert(X == true and Y == nil) -- 'X' not closed yet
  298. return 1,2,3
  299. end
  300. local function bar ()
  301. local _ <close> = func2close(function () X = false end)
  302. X = true
  303. do
  304. return foo() -- not a tail call!
  305. end
  306. end
  307. local a, b, c, d = bar()
  308. assert(a == 1 and b == 2 and c == 3 and X == false and Y == 10 and d == nil)
  309. end
  310. do
  311. -- bug in 5.4.3: previous condition (calls cannot be tail in the
  312. -- scope of to-be-closed variables) must be valid for tbc variables
  313. -- created by 'for' loops.
  314. local closed = false
  315. local function foo ()
  316. return function () return true end, 0, 0,
  317. func2close(function () closed = true end)
  318. end
  319. local function tail() return closed end
  320. local function foo1 ()
  321. for k in foo() do return tail() end
  322. end
  323. assert(foo1() == false)
  324. assert(closed == true)
  325. end
  326. do
  327. -- bug in 5.4.4: 'break' may generate wrong 'close' instruction when
  328. -- leaving a loop block.
  329. local closed = false
  330. local o1 = setmetatable({}, {__close=function() closed = true end})
  331. local function test()
  332. for k, v in next, {}, nil, o1 do
  333. local function f() return k end -- create an upvalue
  334. break
  335. end
  336. assert(closed)
  337. end
  338. test()
  339. end
  340. do print("testing errors in __close")
  341. -- original error is in __close
  342. local function foo ()
  343. local x <close> =
  344. func2close(function (self, msg)
  345. assert(string.find(msg, "@y"))
  346. error("@x")
  347. end)
  348. local x1 <close> =
  349. func2close(function (self, msg)
  350. assert(string.find(msg, "@y"))
  351. end)
  352. local gc <close> = func2close(function () collectgarbage() end)
  353. local y <close> =
  354. func2close(function (self, msg)
  355. assert(string.find(msg, "@z")) -- error in 'z'
  356. error("@y")
  357. end)
  358. local z <close> =
  359. func2close(function (self, msg)
  360. assert(msg == nil)
  361. error("@z")
  362. end)
  363. return 200
  364. end
  365. local stat, msg = pcall(foo, false)
  366. assert(string.find(msg, "@x"))
  367. -- original error not in __close
  368. local function foo ()
  369. local x <close> =
  370. func2close(function (self, msg)
  371. -- after error, 'foo' was discarded, so caller now
  372. -- must be 'pcall'
  373. assert(debug.getinfo(2).name == "pcall")
  374. assert(string.find(msg, "@x1"))
  375. end)
  376. local x1 <close> =
  377. func2close(function (self, msg)
  378. assert(debug.getinfo(2).name == "pcall")
  379. assert(string.find(msg, "@y"))
  380. error("@x1")
  381. end)
  382. local gc <close> = func2close(function () collectgarbage() end)
  383. local y <close> =
  384. func2close(function (self, msg)
  385. assert(debug.getinfo(2).name == "pcall")
  386. assert(string.find(msg, "@z"))
  387. error("@y")
  388. end)
  389. local first = true
  390. local z <close> =
  391. func2close(function (self, msg)
  392. assert(debug.getinfo(2).name == "pcall")
  393. -- 'z' close is called once
  394. assert(first and msg == 4)
  395. first = false
  396. error("@z")
  397. end)
  398. error(4) -- original error
  399. end
  400. local stat, msg = pcall(foo, true)
  401. assert(string.find(msg, "@x1"))
  402. -- error leaving a block
  403. local function foo (...)
  404. do
  405. local x1 <close> =
  406. func2close(function (self, msg)
  407. assert(string.find(msg, "@X"))
  408. error("@Y")
  409. end)
  410. local x123 <close> =
  411. func2close(function (_, msg)
  412. assert(msg == nil)
  413. error("@X")
  414. end)
  415. end
  416. os.exit(false) -- should not run
  417. end
  418. local st, msg = xpcall(foo, debug.traceback)
  419. assert(string.match(msg, "^[^ ]* @Y"))
  420. -- error in toclose in vararg function
  421. local function foo (...)
  422. local x123 <close> = func2close(function () error("@x123") end)
  423. end
  424. local st, msg = xpcall(foo, debug.traceback)
  425. assert(string.match(msg, "^[^ ]* @x123"))
  426. assert(string.find(msg, "in metamethod 'close'"))
  427. end
  428. do -- errors due to non-closable values
  429. local function foo ()
  430. local x <close> = {}
  431. os.exit(false) -- should not run
  432. end
  433. local stat, msg = pcall(foo)
  434. assert(not stat and
  435. string.find(msg, "variable 'x' got a non%-closable value"))
  436. local function foo ()
  437. local xyz <close> = setmetatable({}, {__close = print})
  438. getmetatable(xyz).__close = nil -- remove metamethod
  439. end
  440. local stat, msg = pcall(foo)
  441. assert(not stat and string.find(msg, "metamethod 'close'"))
  442. local function foo ()
  443. local a1 <close> = func2close(function (_, msg)
  444. assert(string.find(msg, "number value"))
  445. error(12)
  446. end)
  447. local a2 <close> = setmetatable({}, {__close = print})
  448. local a3 <close> = func2close(function (_, msg)
  449. assert(msg == nil)
  450. error(123)
  451. end)
  452. getmetatable(a2).__close = 4 -- invalidate metamethod
  453. end
  454. local stat, msg = pcall(foo)
  455. assert(not stat and msg == 12)
  456. end
  457. do -- tbc inside close methods
  458. local track = {}
  459. local function foo ()
  460. local x <close> = func2close(function ()
  461. local xx <close> = func2close(function (_, msg)
  462. assert(msg == nil)
  463. track[#track + 1] = "xx"
  464. end)
  465. track[#track + 1] = "x"
  466. end)
  467. track[#track + 1] = "foo"
  468. return 20, 30, 40
  469. end
  470. local a, b, c, d = foo()
  471. assert(a == 20 and b == 30 and c == 40 and d == nil)
  472. assert(track[1] == "foo" and track[2] == "x" and track[3] == "xx")
  473. -- again, with errors
  474. local track = {}
  475. local function foo ()
  476. local x0 <close> = func2close(function (_, msg)
  477. assert(msg == 202)
  478. track[#track + 1] = "x0"
  479. end)
  480. local x <close> = func2close(function ()
  481. local xx <close> = func2close(function (_, msg)
  482. assert(msg == 101)
  483. track[#track + 1] = "xx"
  484. error(202)
  485. end)
  486. track[#track + 1] = "x"
  487. error(101)
  488. end)
  489. track[#track + 1] = "foo"
  490. return 20, 30, 40
  491. end
  492. local st, msg = pcall(foo)
  493. assert(not st and msg == 202)
  494. assert(track[1] == "foo" and track[2] == "x" and track[3] == "xx" and
  495. track[4] == "x0")
  496. end
  497. local function checktable (t1, t2)
  498. assert(#t1 == #t2)
  499. for i = 1, #t1 do
  500. assert(t1[i] == t2[i])
  501. end
  502. end
  503. do -- test for tbc variable high in the stack
  504. -- function to force a stack overflow
  505. local function overflow (n)
  506. overflow(n + 1)
  507. end
  508. -- error handler will create tbc variable handling a stack overflow,
  509. -- high in the stack
  510. local function errorh (m)
  511. assert(string.find(m, "stack overflow"))
  512. local x <close> = func2close(function (o) o[1] = 10 end)
  513. return x
  514. end
  515. local flag
  516. local st, obj
  517. -- run test in a coroutine so as not to swell the main stack
  518. local co = coroutine.wrap(function ()
  519. -- tbc variable down the stack
  520. local y <close> = func2close(function (obj, msg)
  521. assert(msg == nil)
  522. obj[1] = 100
  523. flag = obj
  524. end)
  525. tracegc.stop()
  526. st, obj = xpcall(overflow, errorh, 0)
  527. tracegc.start()
  528. end)
  529. co()
  530. assert(not st and obj[1] == 10 and flag[1] == 100)
  531. end
  532. if rawget(_G, "T") then
  533. do
  534. -- bug in 5.4.3
  535. -- 'lua_settop' may use a pointer to stack invalidated by 'luaF_close'
  536. -- reduce stack size
  537. collectgarbage(); collectgarbage(); collectgarbage()
  538. -- force a stack reallocation
  539. local function loop (n)
  540. if n < 400 then loop(n + 1) end
  541. end
  542. -- close metamethod will reallocate the stack
  543. local o = setmetatable({}, {__close = function () loop(0) end})
  544. local script = [[toclose 2; settop 1; return 1]]
  545. assert(T.testC(script, o) == script)
  546. end
  547. -- memory error inside closing function
  548. local function foo ()
  549. local y <close> = func2close(function () T.alloccount() end)
  550. local x <close> = setmetatable({}, {__close = function ()
  551. T.alloccount(0); local x = {} -- force a memory error
  552. end})
  553. error(1000) -- common error inside the function's body
  554. end
  555. stack(5) -- ensure a minimal number of CI structures
  556. -- despite memory error, 'y' will be executed and
  557. -- memory limit will be lifted
  558. local _, msg = pcall(foo)
  559. assert(msg == "not enough memory")
  560. local closemsg
  561. local close = func2close(function (self, msg)
  562. T.alloccount()
  563. closemsg = msg
  564. end)
  565. -- set a memory limit and return a closing object to remove the limit
  566. local function enter (count)
  567. stack(10) -- reserve some stack space
  568. T.alloccount(count)
  569. closemsg = nil
  570. return close
  571. end
  572. local function test ()
  573. local x <close> = enter(0) -- set a memory limit
  574. local y = {} -- raise a memory error
  575. end
  576. local _, msg = pcall(test)
  577. assert(msg == "not enough memory" and closemsg == "not enough memory")
  578. -- repeat test with extra closing upvalues
  579. local function test ()
  580. local xxx <close> = func2close(function (self, msg)
  581. assert(msg == "not enough memory");
  582. error(1000) -- raise another error
  583. end)
  584. local xx <close> = func2close(function (self, msg)
  585. assert(msg == "not enough memory");
  586. end)
  587. local x <close> = enter(0) -- set a memory limit
  588. local y = {} -- raise a memory error
  589. end
  590. local _, msg = pcall(test)
  591. assert(msg == 1000 and closemsg == "not enough memory")
  592. do -- testing 'toclose' in C string buffer
  593. collectgarbage()
  594. local s = string.rep('a', 10000) -- large string
  595. local m = T.totalmem()
  596. collectgarbage("stop")
  597. s = string.upper(s) -- allocate buffer + new string (10K each)
  598. -- ensure buffer was deallocated
  599. assert(T.totalmem() - m <= 11000)
  600. collectgarbage("restart")
  601. end
  602. do -- now some tests for freeing buffer in case of errors
  603. local lim = 10000 -- some size larger than the static buffer
  604. local extra = 2000 -- some extra memory (for callinfo, etc.)
  605. local s = string.rep("a", lim)
  606. -- concat this table needs two buffer resizes (one for each 's')
  607. local a = {s, s}
  608. collectgarbage(); collectgarbage()
  609. local m = T.totalmem()
  610. collectgarbage("stop")
  611. -- error in the first buffer allocation
  612. T. totalmem(m + extra)
  613. assert(not pcall(table.concat, a))
  614. -- first buffer was not even allocated
  615. assert(T.totalmem() - m <= extra)
  616. -- error in the second buffer allocation
  617. T. totalmem(m + lim + extra)
  618. assert(not pcall(table.concat, a))
  619. -- first buffer was released by 'toclose'
  620. assert(T.totalmem() - m <= extra)
  621. -- userdata, buffer, final string
  622. T.totalmem(m + 2*lim + extra)
  623. assert(#table.concat(a) == 2*lim)
  624. T.totalmem(0) -- remove memory limit
  625. collectgarbage("restart")
  626. print'+'
  627. end
  628. do
  629. -- '__close' vs. return hooks in C functions
  630. local trace = {}
  631. local function hook (event)
  632. trace[#trace + 1] = event .. " " .. (debug.getinfo(2).name or "?")
  633. end
  634. -- create tbc variables to be used by C function
  635. local x = func2close(function (_,msg)
  636. trace[#trace + 1] = "x"
  637. end)
  638. local y = func2close(function (_,msg)
  639. trace[#trace + 1] = "y"
  640. end)
  641. debug.sethook(hook, "r")
  642. local t = {T.testC([[
  643. toclose 2 # x
  644. pushnum 10
  645. pushint 20
  646. toclose 3 # y
  647. return 2
  648. ]], x, y)}
  649. debug.sethook()
  650. -- hooks ran before return hook from 'testC'
  651. checktable(trace,
  652. {"return sethook", "y", "return ?", "x", "return ?", "return testC"})
  653. -- results are correct
  654. checktable(t, {10, 20})
  655. end
  656. end
  657. do -- '__close' vs. return hooks in Lua functions
  658. local trace = {}
  659. local function hook (event)
  660. trace[#trace + 1] = event .. " " .. debug.getinfo(2).name
  661. end
  662. local function foo (...)
  663. local x <close> = func2close(function (_,msg)
  664. trace[#trace + 1] = "x"
  665. end)
  666. local y <close> = func2close(function (_,msg)
  667. debug.sethook(hook, "r")
  668. end)
  669. return ...
  670. end
  671. local t = {foo(10,20,30)}
  672. debug.sethook()
  673. checktable(t, {10, 20, 30})
  674. checktable(trace,
  675. {"return sethook", "return close", "x", "return close", "return foo"})
  676. end
  677. print "to-be-closed variables in coroutines"
  678. do
  679. -- yielding inside closing metamethods
  680. local trace = {}
  681. local co = coroutine.wrap(function ()
  682. trace[#trace + 1] = "nowX"
  683. -- will be closed after 'y'
  684. local x <close> = func2close(function (_, msg)
  685. assert(msg == nil)
  686. trace[#trace + 1] = "x1"
  687. coroutine.yield("x")
  688. trace[#trace + 1] = "x2"
  689. end)
  690. return pcall(function ()
  691. do -- 'z' will be closed first
  692. local z <close> = func2close(function (_, msg)
  693. assert(msg == nil)
  694. trace[#trace + 1] = "z1"
  695. coroutine.yield("z")
  696. trace[#trace + 1] = "z2"
  697. end)
  698. end
  699. trace[#trace + 1] = "nowY"
  700. -- will be closed after 'z'
  701. local y <close> = func2close(function(_, msg)
  702. assert(msg == nil)
  703. trace[#trace + 1] = "y1"
  704. coroutine.yield("y")
  705. trace[#trace + 1] = "y2"
  706. end)
  707. return 10, 20, 30
  708. end)
  709. end)
  710. assert(co() == "z")
  711. assert(co() == "y")
  712. assert(co() == "x")
  713. checktable({co()}, {true, 10, 20, 30})
  714. checktable(trace, {"nowX", "z1", "z2", "nowY", "y1", "y2", "x1", "x2"})
  715. end
  716. do
  717. -- yielding inside closing metamethods while returning
  718. -- (bug in 5.4.3)
  719. local extrares -- result from extra yield (if any)
  720. local function check (body, extra, ...)
  721. local t = table.pack(...) -- expected returns
  722. local co = coroutine.wrap(body)
  723. if extra then
  724. extrares = co() -- runs until first (extra) yield
  725. end
  726. local res = table.pack(co()) -- runs until "regular" yield
  727. -- regular yield will yield all values passed to the close function;
  728. -- without errors, that is only the object being closed.
  729. assert(res.n == 1 and type(res[1]) == "table")
  730. local res2 = table.pack(co()) -- runs until end of function
  731. assert(res2.n == t.n)
  732. for i = 1, #t do
  733. if t[i] == "x" then
  734. assert(res2[i] == res[1]) -- value that was closed
  735. else
  736. assert(res2[i] == t[i])
  737. end
  738. end
  739. end
  740. local function foo ()
  741. local x <close> = func2close(coroutine.yield) -- "regular" yield
  742. local extra <close> = func2close(function (self)
  743. assert(self == extrares)
  744. coroutine.yield(100) -- first (extra) yield
  745. end)
  746. extrares = extra
  747. return table.unpack{10, x, 30}
  748. end
  749. check(foo, true, 10, "x", 30)
  750. assert(extrares == 100)
  751. local function foo ()
  752. local x <close> = func2close(coroutine.yield) -- "regular" yield
  753. return
  754. end
  755. check(foo, false)
  756. local function foo ()
  757. local x <close> = func2close(coroutine.yield) -- "regular" yield
  758. local y, z = 20, 30
  759. return x
  760. end
  761. check(foo, false, "x")
  762. local function foo ()
  763. local x <close> = func2close(coroutine.yield) -- "regular" yield
  764. local extra <close> = func2close(coroutine.yield) -- extra yield
  765. return table.unpack({}, 1, 100) -- 100 nils
  766. end
  767. check(foo, true, table.unpack({}, 1, 100))
  768. end
  769. do
  770. -- yielding inside closing metamethods after an error
  771. local co = coroutine.wrap(function ()
  772. local function foo (err)
  773. local z <close> = func2close(function(_, msg)
  774. assert(msg == nil or msg == err + 20)
  775. coroutine.yield("z")
  776. return 100, 200
  777. end)
  778. local y <close> = func2close(function(_, msg)
  779. -- still gets the original error (if any)
  780. assert(msg == err or (msg == nil and err == 1))
  781. coroutine.yield("y")
  782. if err then error(err + 20) end -- creates or changes the error
  783. end)
  784. local x <close> = func2close(function(_, msg)
  785. assert(msg == err or (msg == nil and err == 1))
  786. coroutine.yield("x")
  787. return 100, 200
  788. end)
  789. if err == 10 then error(err) else return 10, 20 end
  790. end
  791. coroutine.yield(pcall(foo, nil)) -- no error
  792. coroutine.yield(pcall(foo, 1)) -- error in __close
  793. return pcall(foo, 10) -- 'foo' will raise an error
  794. end)
  795. local a, b = co() -- first foo: no error
  796. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  797. a, b = co()
  798. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  799. a, b = co()
  800. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  801. local a, b, c = co()
  802. assert(a and b == 10 and c == 20) -- returns from 'pcall(foo, nil)'
  803. local a, b = co() -- second foo: error in __close
  804. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  805. a, b = co()
  806. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  807. a, b = co()
  808. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  809. local st, msg = co() -- reports the error in 'y'
  810. assert(not st and msg == 21)
  811. local a, b = co() -- third foo: error in function body
  812. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  813. a, b = co()
  814. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  815. a, b = co()
  816. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  817. local st, msg = co() -- gets final error
  818. assert(not st and msg == 10 + 20)
  819. end
  820. do
  821. -- an error in a wrapped coroutine closes variables
  822. local x = false
  823. local y = false
  824. local co = coroutine.wrap(function ()
  825. local xv <close> = func2close(function () x = true end)
  826. do
  827. local yv <close> = func2close(function () y = true end)
  828. coroutine.yield(100) -- yield doesn't close variable
  829. end
  830. coroutine.yield(200) -- yield doesn't close variable
  831. error(23) -- error does
  832. end)
  833. local b = co()
  834. assert(b == 100 and not x and not y)
  835. b = co()
  836. assert(b == 200 and not x and y)
  837. local a, b = pcall(co)
  838. assert(not a and b == 23 and x and y)
  839. end
  840. do
  841. -- error in a wrapped coroutine raising errors when closing a variable
  842. local x = 0
  843. local co = coroutine.wrap(function ()
  844. local xx <close> = func2close(function (_, msg)
  845. x = x + 1;
  846. assert(string.find(msg, "@XXX"))
  847. error("@YYY")
  848. end)
  849. local xv <close> = func2close(function () x = x + 1; error("@XXX") end)
  850. coroutine.yield(100)
  851. error(200)
  852. end)
  853. assert(co() == 100); assert(x == 0)
  854. local st, msg = pcall(co); assert(x == 2)
  855. assert(not st and string.find(msg, "@YYY")) -- should get error raised
  856. local x = 0
  857. local y = 0
  858. co = coroutine.wrap(function ()
  859. local xx <close> = func2close(function (_, err)
  860. y = y + 1;
  861. assert(string.find(err, "XXX"))
  862. error("YYY")
  863. end)
  864. local xv <close> = func2close(function ()
  865. x = x + 1; error("XXX")
  866. end)
  867. coroutine.yield(100)
  868. return 200
  869. end)
  870. assert(co() == 100); assert(x == 0)
  871. local st, msg = pcall(co)
  872. assert(x == 1 and y == 1)
  873. -- should get first error raised
  874. assert(not st and string.find(msg, "%w+%.%w+:%d+: YYY"))
  875. end
  876. -- a suspended coroutine should not close its variables when collected
  877. local co
  878. co = coroutine.wrap(function()
  879. -- should not run
  880. local x <close> = func2close(function () os.exit(false) end)
  881. co = nil
  882. coroutine.yield()
  883. end)
  884. co() -- start coroutine
  885. assert(co == nil) -- eventually it will be collected
  886. collectgarbage()
  887. if rawget(_G, "T") then
  888. print("to-be-closed variables x coroutines in C")
  889. do
  890. local token = 0
  891. local count = 0
  892. local f = T.makeCfunc[[
  893. toclose 1
  894. toclose 2
  895. return .
  896. ]]
  897. local obj = func2close(function (_, msg)
  898. count = count + 1
  899. token = coroutine.yield(count, token)
  900. end)
  901. local co = coroutine.wrap(f)
  902. local ct, res = co(obj, obj, 10, 20, 30, 3) -- will return 10, 20, 30
  903. -- initial token value, after closing 2nd obj
  904. assert(ct == 1 and res == 0)
  905. -- run until yield when closing 1st obj
  906. ct, res = co(100)
  907. assert(ct == 2 and res == 100)
  908. res = {co(200)} -- run until end
  909. assert(res[1] == 10 and res[2] == 20 and res[3] == 30 and res[4] == nil)
  910. assert(token == 200)
  911. end
  912. do
  913. local f = T.makeCfunc[[
  914. toclose 1
  915. return .
  916. ]]
  917. local obj = func2close(function ()
  918. local temp
  919. local x <close> = func2close(function ()
  920. coroutine.yield(temp)
  921. return 1,2,3 -- to be ignored
  922. end)
  923. temp = coroutine.yield("closing obj")
  924. return 1,2,3 -- to be ignored
  925. end)
  926. local co = coroutine.wrap(f)
  927. local res = co(obj, 10, 30, 1) -- will return only 30
  928. assert(res == "closing obj")
  929. res = co("closing x")
  930. assert(res == "closing x")
  931. res = {co()}
  932. assert(res[1] == 30 and res[2] == nil)
  933. end
  934. do
  935. -- still cannot yield inside 'closeslot'
  936. local f = T.makeCfunc[[
  937. toclose 1
  938. closeslot 1
  939. ]]
  940. local obj = func2close(coroutine.yield)
  941. local co = coroutine.create(f)
  942. local st, msg = coroutine.resume(co, obj)
  943. assert(not st and string.find(msg, "attempt to yield across"))
  944. -- nor outside a coroutine
  945. local f = T.makeCfunc[[
  946. toclose 1
  947. ]]
  948. local st, msg = pcall(f, obj)
  949. assert(not st and string.find(msg, "attempt to yield from outside"))
  950. end
  951. end
  952. -- to-be-closed variables in generic for loops
  953. do
  954. local numopen = 0
  955. local function open (x)
  956. numopen = numopen + 1
  957. return
  958. function () -- iteration function
  959. x = x - 1
  960. if x > 0 then return x end
  961. end,
  962. nil, -- state
  963. nil, -- control variable
  964. func2close(function () numopen = numopen - 1 end) -- closing function
  965. end
  966. local s = 0
  967. for i in open(10) do
  968. s = s + i
  969. end
  970. assert(s == 45 and numopen == 0)
  971. local s = 0
  972. for i in open(10) do
  973. if i < 5 then break end
  974. s = s + i
  975. end
  976. assert(s == 35 and numopen == 0)
  977. local s = 0
  978. for i in open(10) do
  979. for j in open(10) do
  980. if i + j < 5 then goto endloop end
  981. s = s + i
  982. end
  983. end
  984. ::endloop::
  985. assert(s == 375 and numopen == 0)
  986. end
  987. print('OK')
  988. return 5,f
  989. end -- }