locals.lua 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  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 (...t)
  249. assert(select("#", ...) == n)
  250. assert(t.n == n and t[1] == ca and (t.n < 2 or t[2] == obj))
  251. ca = 15 -- final value to be returned if howtoclose=="scope"
  252. end)
  253. ca = a
  254. if howtoclose == "ret" then return obj -- 'a' closed by return
  255. elseif howtoclose == "err" then error(obj) -- 'a' closed by error
  256. end
  257. end -- 'a' closed by end of scope
  258. return ca -- ca now should be 15
  259. end
  260. -- with no errors, closing methods receive no extra argument
  261. assert(foo("scope", nil, 1) == 15) -- close by end of scope
  262. assert(foo("ret", 32, 1) == 32) -- close by return
  263. -- with errors, they do
  264. local st, msg = pcall(foo, "err", 23, 2) -- close by error
  265. assert(not st and msg == 23)
  266. end
  267. -- testing to-be-closed x compile-time constants
  268. -- (there were some bugs here in Lua 5.4-rc3, due to a confusion
  269. -- between compile levels and stack levels of variables)
  270. do
  271. local flag = false
  272. local x = setmetatable({},
  273. {__close = function() assert(flag == false); flag = true end})
  274. local y <const> = nil
  275. local z <const> = nil
  276. do
  277. local a <close> = x
  278. end
  279. assert(flag) -- 'x' must be closed here
  280. end
  281. do
  282. -- similar problem, but with implicit close in for loops
  283. local flag = false
  284. local x = setmetatable({},
  285. {__close = function () assert(flag == false); flag = true end})
  286. -- return an empty iterator, nil, nil, and 'x' to be closed
  287. local function a ()
  288. return (function () return nil end), nil, nil, x
  289. end
  290. local v <const> = 1
  291. local w <const> = 1
  292. local x <const> = 1
  293. local y <const> = 1
  294. local z <const> = 1
  295. for k in a() do
  296. a = k
  297. end -- ending the loop must close 'x'
  298. assert(flag) -- 'x' must be closed here
  299. end
  300. do
  301. -- calls cannot be tail in the scope of to-be-closed variables
  302. local X, Y
  303. local function foo ()
  304. local _ <close> = func2close(function () Y = 10 end)
  305. assert(X == true and Y == nil) -- 'X' not closed yet
  306. return 1,2,3
  307. end
  308. local function bar ()
  309. local _ <close> = func2close(function () X = false end)
  310. X = true
  311. do
  312. return foo() -- not a tail call!
  313. end
  314. end
  315. local a, b, c, d = bar()
  316. assert(a == 1 and b == 2 and c == 3 and X == false and Y == 10 and d == nil)
  317. end
  318. do
  319. -- bug in 5.4.3: previous condition (calls cannot be tail in the
  320. -- scope of to-be-closed variables) must be valid for tbc variables
  321. -- created by 'for' loops.
  322. local closed = false
  323. local function foo ()
  324. return function () return true end, 0, 0,
  325. func2close(function () closed = true end)
  326. end
  327. local function tail() return closed end
  328. local function foo1 ()
  329. for k in foo() do return tail() end
  330. end
  331. assert(foo1() == false)
  332. assert(closed == true)
  333. end
  334. do
  335. -- bug in 5.4.4: 'break' may generate wrong 'close' instruction when
  336. -- leaving a loop block.
  337. local closed = false
  338. local o1 = setmetatable({}, {__close=function() closed = true end})
  339. local function test()
  340. for k, v in next, {}, nil, o1 do
  341. local function f() return k end -- create an upvalue
  342. break
  343. end
  344. assert(closed)
  345. end
  346. test()
  347. end
  348. do print("testing errors in __close")
  349. -- original error is in __close
  350. local function foo ()
  351. local x <close> =
  352. func2close(function (self, msg)
  353. assert(string.find(msg, "@y"))
  354. error("@x")
  355. end)
  356. local x1 <close> =
  357. func2close(function (self, msg)
  358. assert(string.find(msg, "@y"))
  359. end)
  360. local gc <close> = func2close(function () collectgarbage() end)
  361. local y <close> =
  362. func2close(function (self, msg)
  363. assert(string.find(msg, "@z")) -- error in 'z'
  364. error("@y")
  365. end)
  366. local z <close> =
  367. func2close(function (self, msg)
  368. assert(msg == nil)
  369. error("@z")
  370. end)
  371. return 200
  372. end
  373. local stat, msg = pcall(foo, false)
  374. assert(string.find(msg, "@x"))
  375. -- original error not in __close
  376. local function foo ()
  377. local x <close> =
  378. func2close(function (self, msg)
  379. -- after error, 'foo' was discarded, so caller now
  380. -- must be 'pcall'
  381. assert(debug.getinfo(2).name == "pcall")
  382. assert(string.find(msg, "@x1"))
  383. end)
  384. local x1 <close> =
  385. func2close(function (self, msg)
  386. assert(debug.getinfo(2).name == "pcall")
  387. assert(string.find(msg, "@y"))
  388. error("@x1")
  389. end)
  390. local gc <close> = func2close(function () collectgarbage() end)
  391. local y <close> =
  392. func2close(function (self, msg)
  393. assert(debug.getinfo(2).name == "pcall")
  394. assert(string.find(msg, "@z"))
  395. error("@y")
  396. end)
  397. local first = true
  398. local z <close> =
  399. func2close(function (self, msg)
  400. assert(debug.getinfo(2).name == "pcall")
  401. -- 'z' close is called once
  402. assert(first and msg == 4)
  403. first = false
  404. error("@z")
  405. end)
  406. error(4) -- original error
  407. end
  408. local stat, msg = pcall(foo, true)
  409. assert(string.find(msg, "@x1"))
  410. -- error leaving a block
  411. local function foo (...)
  412. do
  413. local x1 <close> =
  414. func2close(function (self, msg)
  415. assert(string.find(msg, "@X"))
  416. error("@Y")
  417. end)
  418. local x123 <close> =
  419. func2close(function (_, msg)
  420. assert(msg == nil)
  421. error("@X")
  422. end)
  423. end
  424. os.exit(false) -- should not run
  425. end
  426. local st, msg = xpcall(foo, debug.traceback)
  427. assert(string.match(msg, "^[^ ]* @Y"))
  428. -- error in toclose in vararg function
  429. local function foo (...)
  430. local x123 <close> = func2close(function () error("@x123") end)
  431. end
  432. local st, msg = xpcall(foo, debug.traceback)
  433. assert(string.match(msg, "^[^ ]* @x123"))
  434. assert(string.find(msg, "in metamethod 'close'"))
  435. end
  436. do -- errors due to non-closable values
  437. local function foo ()
  438. local x <close> = {}
  439. os.exit(false) -- should not run
  440. end
  441. local stat, msg = pcall(foo)
  442. assert(not stat and
  443. string.find(msg, "variable 'x' got a non%-closable value"))
  444. local function foo ()
  445. local xyz <close> = setmetatable({}, {__close = print})
  446. getmetatable(xyz).__close = nil -- remove metamethod
  447. end
  448. local stat, msg = pcall(foo)
  449. assert(not stat and string.find(msg, "metamethod 'close'"))
  450. local function foo ()
  451. local a1 <close> = func2close(function (_, msg)
  452. assert(string.find(msg, "number value"))
  453. error(12)
  454. end)
  455. local a2 <close> = setmetatable({}, {__close = print})
  456. local a3 <close> = func2close(function (_, msg)
  457. assert(msg == nil)
  458. error(123)
  459. end)
  460. getmetatable(a2).__close = 4 -- invalidate metamethod
  461. end
  462. local stat, msg = pcall(foo)
  463. assert(not stat and msg == 12)
  464. end
  465. do -- tbc inside close methods
  466. local track = {}
  467. local function foo ()
  468. local x <close> = func2close(function ()
  469. local xx <close> = func2close(function (_, msg)
  470. assert(msg == nil)
  471. track[#track + 1] = "xx"
  472. end)
  473. track[#track + 1] = "x"
  474. end)
  475. track[#track + 1] = "foo"
  476. return 20, 30, 40
  477. end
  478. local a, b, c, d = foo()
  479. assert(a == 20 and b == 30 and c == 40 and d == nil)
  480. assert(track[1] == "foo" and track[2] == "x" and track[3] == "xx")
  481. -- again, with errors
  482. local track = {}
  483. local function foo ()
  484. local x0 <close> = func2close(function (_, msg)
  485. assert(msg == 202)
  486. track[#track + 1] = "x0"
  487. end)
  488. local x <close> = func2close(function ()
  489. local xx <close> = func2close(function (_, msg)
  490. assert(msg == 101)
  491. track[#track + 1] = "xx"
  492. error(202)
  493. end)
  494. track[#track + 1] = "x"
  495. error(101)
  496. end)
  497. track[#track + 1] = "foo"
  498. return 20, 30, 40
  499. end
  500. local st, msg = pcall(foo)
  501. assert(not st and msg == 202)
  502. assert(track[1] == "foo" and track[2] == "x" and track[3] == "xx" and
  503. track[4] == "x0")
  504. end
  505. local function checktable (t1, t2)
  506. assert(#t1 == #t2)
  507. for i = 1, #t1 do
  508. assert(t1[i] == t2[i])
  509. end
  510. end
  511. do -- test for tbc variable high in the stack
  512. -- function to force a stack overflow
  513. local function overflow (n)
  514. overflow(n + 1)
  515. end
  516. -- error handler will create tbc variable handling a stack overflow,
  517. -- high in the stack
  518. local function errorh (m)
  519. assert(string.find(m, "stack overflow"))
  520. local x <close> = func2close(function (o) o[1] = 10 end)
  521. return x
  522. end
  523. local flag
  524. local st, obj
  525. -- run test in a coroutine so as not to swell the main stack
  526. local co = coroutine.wrap(function ()
  527. -- tbc variable down the stack
  528. local y <close> = func2close(function (obj, msg)
  529. assert(msg == nil)
  530. obj[1] = 100
  531. flag = obj
  532. end)
  533. tracegc.stop()
  534. st, obj = xpcall(overflow, errorh, 0)
  535. tracegc.start()
  536. end)
  537. co()
  538. assert(not st and obj[1] == 10 and flag[1] == 100)
  539. end
  540. if rawget(_G, "T") then
  541. do
  542. -- bug in 5.4.3
  543. -- 'lua_settop' may use a pointer to stack invalidated by 'luaF_close'
  544. -- reduce stack size
  545. collectgarbage(); collectgarbage(); collectgarbage()
  546. -- force a stack reallocation
  547. local function loop (n)
  548. if n < 400 then loop(n + 1) end
  549. end
  550. -- close metamethod will reallocate the stack
  551. local o = setmetatable({}, {__close = function () loop(0) end})
  552. local script = [[toclose 2; settop 1; return 1]]
  553. assert(T.testC(script, o) == script)
  554. end
  555. -- memory error inside closing function
  556. local function foo ()
  557. local y <close> = func2close(function () T.alloccount() end)
  558. local x <close> = setmetatable({}, {__close = function ()
  559. T.alloccount(0); local x = {} -- force a memory error
  560. end})
  561. error(1000) -- common error inside the function's body
  562. end
  563. stack(5) -- ensure a minimal number of CI structures
  564. -- despite memory error, 'y' will be executed and
  565. -- memory limit will be lifted
  566. local _, msg = pcall(foo)
  567. assert(msg == "not enough memory")
  568. local closemsg
  569. local close = func2close(function (self, msg)
  570. T.alloccount()
  571. closemsg = msg
  572. end)
  573. -- set a memory limit and return a closing object to remove the limit
  574. local function enter (count)
  575. stack(10) -- reserve some stack space
  576. T.alloccount(count)
  577. closemsg = nil
  578. return close
  579. end
  580. local function test ()
  581. local x <close> = enter(0) -- set a memory limit
  582. local y = {} -- raise a memory error
  583. end
  584. local _, msg = pcall(test)
  585. assert(msg == "not enough memory" and closemsg == "not enough memory")
  586. -- repeat test with extra closing upvalues
  587. local function test ()
  588. local xxx <close> = func2close(function (self, msg)
  589. assert(msg == "not enough memory");
  590. error(1000) -- raise another error
  591. end)
  592. local xx <close> = func2close(function (self, msg)
  593. assert(msg == "not enough memory");
  594. end)
  595. local x <close> = enter(0) -- set a memory limit
  596. local y = {} -- raise a memory error
  597. end
  598. local _, msg = pcall(test)
  599. assert(msg == 1000 and closemsg == "not enough memory")
  600. do -- testing 'toclose' in C string buffer
  601. collectgarbage()
  602. local s = string.rep('a', 10000) -- large string
  603. local m = T.totalmem()
  604. collectgarbage("stop")
  605. s = string.upper(s) -- allocate buffer + new string (10K each)
  606. -- ensure buffer was deallocated
  607. assert(T.totalmem() - m <= 11000)
  608. collectgarbage("restart")
  609. end
  610. do -- now some tests for freeing buffer in case of errors
  611. local lim = 10000 -- some size larger than the static buffer
  612. local extra = 2000 -- some extra memory (for callinfo, etc.)
  613. local s = string.rep("a", lim)
  614. -- concat this table needs two buffer resizes (one for each 's')
  615. local a = {s, s}
  616. collectgarbage(); collectgarbage()
  617. local m = T.totalmem()
  618. collectgarbage("stop")
  619. -- error in the first buffer allocation
  620. T. totalmem(m + extra)
  621. assert(not pcall(table.concat, a))
  622. -- first buffer was not even allocated
  623. assert(T.totalmem() - m <= extra)
  624. -- error in the second buffer allocation
  625. T. totalmem(m + lim + extra)
  626. assert(not pcall(table.concat, a))
  627. -- first buffer was released by 'toclose'
  628. assert(T.totalmem() - m <= extra)
  629. -- userdata, buffer, final string
  630. T.totalmem(m + 2*lim + extra)
  631. assert(#table.concat(a) == 2*lim)
  632. T.totalmem(0) -- remove memory limit
  633. collectgarbage("restart")
  634. print'+'
  635. end
  636. do
  637. -- '__close' vs. return hooks in C functions
  638. local trace = {}
  639. local function hook (event)
  640. trace[#trace + 1] = event .. " " .. (debug.getinfo(2).name or "?")
  641. end
  642. -- create tbc variables to be used by C function
  643. local x = func2close(function (_,msg)
  644. trace[#trace + 1] = "x"
  645. end)
  646. local y = func2close(function (_,msg)
  647. trace[#trace + 1] = "y"
  648. end)
  649. debug.sethook(hook, "r")
  650. local t = {T.testC([[
  651. toclose 2 # x
  652. pushnum 10
  653. pushint 20
  654. toclose 3 # y
  655. return 2
  656. ]], x, y)}
  657. debug.sethook()
  658. -- hooks ran before return hook from 'testC'
  659. checktable(trace,
  660. {"return sethook", "y", "return ?", "x", "return ?", "return testC"})
  661. -- results are correct
  662. checktable(t, {10, 20})
  663. end
  664. end
  665. do -- '__close' vs. return hooks in Lua functions
  666. local trace = {}
  667. local function hook (event)
  668. trace[#trace + 1] = event .. " " .. debug.getinfo(2).name
  669. end
  670. local function foo (...)
  671. local x <close> = func2close(function (_,msg)
  672. trace[#trace + 1] = "x"
  673. end)
  674. local y <close> = func2close(function (_,msg)
  675. debug.sethook(hook, "r")
  676. end)
  677. return ...
  678. end
  679. local t = {foo(10,20,30)}
  680. debug.sethook()
  681. checktable(t, {10, 20, 30})
  682. checktable(trace,
  683. {"return sethook", "return close", "x", "return close", "return foo"})
  684. end
  685. print "to-be-closed variables in coroutines"
  686. do
  687. -- yielding inside closing metamethods
  688. local trace = {}
  689. local co = coroutine.wrap(function ()
  690. trace[#trace + 1] = "nowX"
  691. -- will be closed after 'y'
  692. local x <close> = func2close(function (_, msg)
  693. assert(msg == nil)
  694. trace[#trace + 1] = "x1"
  695. coroutine.yield("x")
  696. trace[#trace + 1] = "x2"
  697. end)
  698. return pcall(function ()
  699. do -- 'z' will be closed first
  700. local z <close> = func2close(function (_, msg)
  701. assert(msg == nil)
  702. trace[#trace + 1] = "z1"
  703. coroutine.yield("z")
  704. trace[#trace + 1] = "z2"
  705. end)
  706. end
  707. trace[#trace + 1] = "nowY"
  708. -- will be closed after 'z'
  709. local y <close> = func2close(function(_, msg)
  710. assert(msg == nil)
  711. trace[#trace + 1] = "y1"
  712. coroutine.yield("y")
  713. trace[#trace + 1] = "y2"
  714. end)
  715. return 10, 20, 30
  716. end)
  717. end)
  718. assert(co() == "z")
  719. assert(co() == "y")
  720. assert(co() == "x")
  721. checktable({co()}, {true, 10, 20, 30})
  722. checktable(trace, {"nowX", "z1", "z2", "nowY", "y1", "y2", "x1", "x2"})
  723. end
  724. do
  725. -- yielding inside closing metamethods while returning
  726. -- (bug in 5.4.3)
  727. local extrares -- result from extra yield (if any)
  728. local function check (body, extra, ...t)
  729. local co = coroutine.wrap(body)
  730. if extra then
  731. extrares = co() -- runs until first (extra) yield
  732. end
  733. local res = table.pack(co()) -- runs until "regular" yield
  734. -- regular yield will yield all values passed to the close function;
  735. -- without errors, that is only the object being closed.
  736. assert(res.n == 1 and type(res[1]) == "table")
  737. local res2 = table.pack(co()) -- runs until end of function
  738. assert(res2.n == t.n)
  739. for i = 1, #t do
  740. if t[i] == "x" then
  741. assert(res2[i] == res[1]) -- value that was closed
  742. else
  743. assert(res2[i] == t[i])
  744. end
  745. end
  746. end
  747. local function foo ()
  748. local x <close> = func2close(coroutine.yield) -- "regular" yield
  749. local extra <close> = func2close(function (self)
  750. assert(self == extrares)
  751. coroutine.yield(100) -- first (extra) yield
  752. end)
  753. extrares = extra
  754. return table.unpack{10, x, 30}
  755. end
  756. check(foo, true, 10, "x", 30)
  757. assert(extrares == 100)
  758. local function foo ()
  759. local x <close> = func2close(coroutine.yield) -- "regular" yield
  760. return
  761. end
  762. check(foo, false)
  763. local function foo ()
  764. local x <close> = func2close(coroutine.yield) -- "regular" yield
  765. local y, z = 20, 30
  766. return x
  767. end
  768. check(foo, false, "x")
  769. local function foo ()
  770. local x <close> = func2close(coroutine.yield) -- "regular" yield
  771. local extra <close> = func2close(coroutine.yield) -- extra yield
  772. return table.unpack({}, 1, 100) -- 100 nils
  773. end
  774. check(foo, true, table.unpack({}, 1, 100))
  775. end
  776. do
  777. -- yielding inside closing metamethods after an error
  778. local co = coroutine.wrap(function ()
  779. local function foo (err)
  780. local z <close> = func2close(function(_, msg)
  781. assert(msg == nil or msg == err + 20)
  782. coroutine.yield("z")
  783. return 100, 200
  784. end)
  785. local y <close> = func2close(function(_, msg)
  786. -- still gets the original error (if any)
  787. assert(msg == err or (msg == nil and err == 1))
  788. coroutine.yield("y")
  789. if err then error(err + 20) end -- creates or changes the error
  790. end)
  791. local x <close> = func2close(function(_, msg)
  792. assert(msg == err or (msg == nil and err == 1))
  793. coroutine.yield("x")
  794. return 100, 200
  795. end)
  796. if err == 10 then error(err) else return 10, 20 end
  797. end
  798. coroutine.yield(pcall(foo, nil)) -- no error
  799. coroutine.yield(pcall(foo, 1)) -- error in __close
  800. return pcall(foo, 10) -- 'foo' will raise an error
  801. end)
  802. local a, b = co() -- first foo: no error
  803. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  804. a, b = co()
  805. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  806. a, b = co()
  807. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  808. local a, b, c = co()
  809. assert(a and b == 10 and c == 20) -- returns from 'pcall(foo, nil)'
  810. local a, b = co() -- second foo: error in __close
  811. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  812. a, b = co()
  813. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  814. a, b = co()
  815. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  816. local st, msg = co() -- reports the error in 'y'
  817. assert(not st and msg == 21)
  818. local a, b = co() -- third foo: error in function body
  819. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  820. a, b = co()
  821. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  822. a, b = co()
  823. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  824. local st, msg = co() -- gets final error
  825. assert(not st and msg == 10 + 20)
  826. end
  827. do
  828. -- an error in a wrapped coroutine closes variables
  829. local x = false
  830. local y = false
  831. local co = coroutine.wrap(function ()
  832. local xv <close> = func2close(function () x = true end)
  833. do
  834. local yv <close> = func2close(function () y = true end)
  835. coroutine.yield(100) -- yield doesn't close variable
  836. end
  837. coroutine.yield(200) -- yield doesn't close variable
  838. error(23) -- error does
  839. end)
  840. local b = co()
  841. assert(b == 100 and not x and not y)
  842. b = co()
  843. assert(b == 200 and not x and y)
  844. local a, b = pcall(co)
  845. assert(not a and b == 23 and x and y)
  846. end
  847. do
  848. -- error in a wrapped coroutine raising errors when closing a variable
  849. local x = 0
  850. local co = coroutine.wrap(function ()
  851. local xx <close> = func2close(function (_, msg)
  852. x = x + 1;
  853. assert(string.find(msg, "@XXX"))
  854. error("@YYY")
  855. end)
  856. local xv <close> = func2close(function () x = x + 1; error("@XXX") end)
  857. coroutine.yield(100)
  858. error(200)
  859. end)
  860. assert(co() == 100); assert(x == 0)
  861. local st, msg = pcall(co); assert(x == 2)
  862. assert(not st and string.find(msg, "@YYY")) -- should get error raised
  863. local x = 0
  864. local y = 0
  865. co = coroutine.wrap(function ()
  866. local xx <close> = func2close(function (_, err)
  867. y = y + 1;
  868. assert(string.find(err, "XXX"))
  869. error("YYY")
  870. end)
  871. local xv <close> = func2close(function ()
  872. x = x + 1; error("XXX")
  873. end)
  874. coroutine.yield(100)
  875. return 200
  876. end)
  877. assert(co() == 100); assert(x == 0)
  878. local st, msg = pcall(co)
  879. assert(x == 1 and y == 1)
  880. -- should get first error raised
  881. assert(not st and string.find(msg, "%w+%.%w+:%d+: YYY"))
  882. end
  883. -- a suspended coroutine should not close its variables when collected
  884. local co
  885. co = coroutine.wrap(function()
  886. -- should not run
  887. local x <close> = func2close(function () os.exit(false) end)
  888. co = nil
  889. coroutine.yield()
  890. end)
  891. co() -- start coroutine
  892. assert(co == nil) -- eventually it will be collected
  893. collectgarbage()
  894. if rawget(_G, "T") then
  895. print("to-be-closed variables x coroutines in C")
  896. do
  897. local token = 0
  898. local count = 0
  899. local f = T.makeCfunc[[
  900. toclose 1
  901. toclose 2
  902. return .
  903. ]]
  904. local obj = func2close(function (_, msg)
  905. count = count + 1
  906. token = coroutine.yield(count, token)
  907. end)
  908. local co = coroutine.wrap(f)
  909. local ct, res = co(obj, obj, 10, 20, 30, 3) -- will return 10, 20, 30
  910. -- initial token value, after closing 2nd obj
  911. assert(ct == 1 and res == 0)
  912. -- run until yield when closing 1st obj
  913. ct, res = co(100)
  914. assert(ct == 2 and res == 100)
  915. res = {co(200)} -- run until end
  916. assert(res[1] == 10 and res[2] == 20 and res[3] == 30 and res[4] == nil)
  917. assert(token == 200)
  918. end
  919. do
  920. local f = T.makeCfunc[[
  921. toclose 1
  922. return .
  923. ]]
  924. local obj = func2close(function ()
  925. local temp
  926. local x <close> = func2close(function ()
  927. coroutine.yield(temp)
  928. return 1,2,3 -- to be ignored
  929. end)
  930. temp = coroutine.yield("closing obj")
  931. return 1,2,3 -- to be ignored
  932. end)
  933. local co = coroutine.wrap(f)
  934. local res = co(obj, 10, 30, 1) -- will return only 30
  935. assert(res == "closing obj")
  936. res = co("closing x")
  937. assert(res == "closing x")
  938. res = {co()}
  939. assert(res[1] == 30 and res[2] == nil)
  940. end
  941. do
  942. -- still cannot yield inside 'closeslot'
  943. local f = T.makeCfunc[[
  944. toclose 1
  945. closeslot 1
  946. ]]
  947. local obj = func2close(coroutine.yield)
  948. local co = coroutine.create(f)
  949. local st, msg = coroutine.resume(co, obj)
  950. assert(not st and string.find(msg, "attempt to yield across"))
  951. -- nor outside a coroutine
  952. local f = T.makeCfunc[[
  953. toclose 1
  954. ]]
  955. local st, msg = pcall(f, obj)
  956. assert(not st and string.find(msg, "attempt to yield from outside"))
  957. end
  958. end
  959. -- to-be-closed variables in generic for loops
  960. do
  961. local numopen = 0
  962. local function open (x)
  963. numopen = numopen + 1
  964. return
  965. function () -- iteration function
  966. x = x - 1
  967. if x > 0 then return x end
  968. end,
  969. nil, -- state
  970. nil, -- control variable
  971. func2close(function () numopen = numopen - 1 end) -- closing function
  972. end
  973. local s = 0
  974. for i in open(10) do
  975. s = s + i
  976. end
  977. assert(s == 45 and numopen == 0)
  978. local s = 0
  979. for i in open(10) do
  980. if i < 5 then break end
  981. s = s + i
  982. end
  983. assert(s == 35 and numopen == 0)
  984. local s = 0
  985. for i in open(10) do
  986. for j in open(10) do
  987. if i + j < 5 then goto endloop end
  988. s = s + i
  989. end
  990. end
  991. ::endloop::
  992. assert(s == 375 and numopen == 0)
  993. end
  994. print('OK')
  995. return 5,f
  996. end -- }