locals.lua 30 KB

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