memerr.lua 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. -- $Id: testes/memerr.lua $
  2. -- See Copyright Notice in file lua.h
  3. local function checkerr (msg, f, ...)
  4. local stat, err = pcall(f, ...)
  5. assert(not stat and string.find(err, msg))
  6. end
  7. if T==nil then
  8. (Message or print)
  9. ('\n >>> testC not active: skipping memory error tests <<<\n')
  10. return
  11. end
  12. print("testing memory-allocation errors")
  13. local debug = require "debug"
  14. local pack = table.pack
  15. -- standard error message for memory errors
  16. local MEMERRMSG = "not enough memory"
  17. -- memory error in panic function
  18. T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k)
  19. assert(T.checkpanic("newuserdata 20000") == MEMERRMSG)
  20. T.totalmem(0) -- restore high limit
  21. -- {==================================================================
  22. -- Testing memory limits
  23. -- ===================================================================
  24. checkerr("block too big", T.newuserdata, math.maxinteger)
  25. collectgarbage()
  26. local f = load"local a={}; for i=1,100000 do a[i]=i end"
  27. T.alloccount(10)
  28. checkerr(MEMERRMSG, f)
  29. T.alloccount() -- remove limit
  30. -- preallocate stack space
  31. local function deep (n) if n > 0 then deep(n - 1) end end
  32. -- test memory errors; increase limit for maximum memory by steps,
  33. -- so that we get memory errors in all allocations of a given
  34. -- task, until there is enough memory to complete the task without
  35. -- errors.
  36. local function testbytes (s, f)
  37. collectgarbage()
  38. local M = T.totalmem()
  39. local oldM = M
  40. local a,b = nil
  41. while true do
  42. collectgarbage(); collectgarbage()
  43. deep(4)
  44. T.totalmem(M)
  45. a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
  46. T.totalmem(0) -- remove limit
  47. if a and b == "OK" then break end -- stop when no more errors
  48. if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
  49. error(a, 0) -- propagate it
  50. end
  51. M = M + 7 -- increase memory limit
  52. end
  53. print(string.format("minimum memory for %s: %d bytes", s, M - oldM))
  54. return a
  55. end
  56. -- test memory errors; increase limit for number of allocations one
  57. -- by one, so that we get memory errors in all allocations of a given
  58. -- task, until there is enough allocations to complete the task without
  59. -- errors.
  60. local function testalloc (s, f)
  61. collectgarbage()
  62. local M = 0
  63. local a,b = nil
  64. while true do
  65. collectgarbage(); collectgarbage()
  66. deep(4)
  67. T.alloccount(M)
  68. a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
  69. T.alloccount() -- remove limit
  70. if a and b == "OK" then break end -- stop when no more errors
  71. if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
  72. error(a, 0) -- propagate it
  73. end
  74. M = M + 1 -- increase allocation limit
  75. end
  76. print(string.format("minimum allocations for %s: %d allocations", s, M))
  77. return M
  78. end
  79. local function testamem (s, f)
  80. local aloc = testalloc(s, f)
  81. local res = testbytes(s, f)
  82. return {aloc = aloc, res = res}
  83. end
  84. local b = testamem("function call", function () return 10 end)
  85. assert(b.res == 10 and b.aloc == 0)
  86. testamem("state creation", function ()
  87. local st = T.newstate()
  88. if st then T.closestate(st) end -- close new state
  89. return st
  90. end)
  91. testamem("empty-table creation", function ()
  92. return {}
  93. end)
  94. testamem("string creation", function ()
  95. return "XXX" .. "YYY"
  96. end)
  97. testamem("coroutine creation", function()
  98. return coroutine.create(print)
  99. end)
  100. do -- vararg tables
  101. local function pack (...t) return t end
  102. local b = testamem("vararg table", function ()
  103. return pack(10, 20, 30, 40, "hello")
  104. end)
  105. assert(b.aloc == 3) -- new table uses three memory blocks
  106. -- table optimized away
  107. local function sel (n, ...arg) return arg[n] + arg.n end
  108. local b = testamem("optimized vararg table",
  109. function () return sel(2.0, 20, 30) end)
  110. assert(b.res == 32 and b.aloc == 0) -- no memory needed for this case
  111. end
  112. -- testing to-be-closed variables
  113. testamem("to-be-closed variables", function()
  114. local flag
  115. do
  116. local x <close> =
  117. setmetatable({}, {__close = function () flag = true end})
  118. flag = false
  119. local x = {}
  120. end
  121. return flag
  122. end)
  123. -- testing threads
  124. -- get main thread from registry
  125. local mt = T.testC("rawgeti R !M; return 1")
  126. assert(type(mt) == "thread" and coroutine.running() == mt)
  127. local function expand (n,s)
  128. if n==0 then return "" end
  129. local e = string.rep("=", n)
  130. return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
  131. e, s, expand(n-1,s), e)
  132. end
  133. G=0; collectgarbage()
  134. load(expand(20,"G=G+1"))()
  135. assert(G==20); collectgarbage()
  136. G = nil
  137. testamem("running code on new thread", function ()
  138. return T.doonnewstack("local x=1") == 0 -- try to create thread
  139. end)
  140. do -- external strings
  141. local str = string.rep("a", 100)
  142. testamem("creating external strings", function ()
  143. return T.externstr(str)
  144. end)
  145. end
  146. -- testing memory x compiler
  147. testamem("loadstring", function ()
  148. return load("x=1") -- try to do load a string
  149. end)
  150. local testprog = [[
  151. local function foo () return end
  152. local t = {"x"}
  153. AA = "aaa"
  154. for i = 1, #t do AA = AA .. t[i] end
  155. return true
  156. ]]
  157. -- testing memory x dofile
  158. _G.AA = nil
  159. local t =os.tmpname()
  160. local f = assert(io.open(t, "w"))
  161. f:write(testprog)
  162. f:close()
  163. testamem("dofile", function ()
  164. local a = loadfile(t)
  165. return a and a()
  166. end)
  167. assert(os.remove(t))
  168. assert(_G.AA == "aaax")
  169. -- other generic tests
  170. testamem("gsub", function ()
  171. local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end)
  172. return (a == 'ablo ablo')
  173. end)
  174. testamem("dump/undump", function ()
  175. local a = load(testprog)
  176. local b = a and string.dump(a)
  177. a = b and load(b)
  178. return a and a()
  179. end)
  180. _G.AA = nil
  181. local t = os.tmpname()
  182. testamem("file creation", function ()
  183. local f = assert(io.open(t, 'w'))
  184. assert (not io.open"nomenaoexistente")
  185. io.close(f);
  186. return not loadfile'nomenaoexistente'
  187. end)
  188. assert(os.remove(t))
  189. testamem("table creation", function ()
  190. local a, lim = {}, 10
  191. for i=1,lim do a[i] = i; a[i..'a'] = {} end
  192. return (type(a[lim..'a']) == 'table' and a[lim] == lim)
  193. end)
  194. testamem("constructors", function ()
  195. local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5}
  196. return (type(a) == 'table' and a.e == 5)
  197. end)
  198. local a = 1
  199. local close = nil
  200. testamem("closure creation", function ()
  201. function close (b)
  202. return function (x) return b + x end
  203. end
  204. return (close(2)(4) == 6)
  205. end)
  206. testamem("using coroutines", function ()
  207. local a = coroutine.wrap(function ()
  208. coroutine.yield(string.rep("a", 10))
  209. return {}
  210. end)
  211. assert(string.len(a()) == 10)
  212. return a()
  213. end)
  214. do -- auxiliary buffer
  215. local lim = 100
  216. local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end
  217. testamem("auxiliary buffer", function ()
  218. return (#table.concat(a, ",") == 20*lim + lim - 1)
  219. end)
  220. end
  221. testamem("growing stack", function ()
  222. local function foo (n)
  223. if n == 0 then return 1 else return 1 + foo(n - 1) end
  224. end
  225. return foo(100)
  226. end)
  227. -- }==================================================================
  228. print "Ok"