memerr.lua 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. -- test memory errors; increase limit for maximum memory by steps,
  31. -- o that we get memory errors in all allocations of a given
  32. -- task, until there is enough memory to complete the task without
  33. -- errors.
  34. local function testbytes (s, f)
  35. collectgarbage()
  36. local M = T.totalmem()
  37. local oldM = M
  38. local a,b = nil
  39. while true do
  40. collectgarbage(); collectgarbage()
  41. T.totalmem(M)
  42. a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
  43. T.totalmem(0) -- remove limit
  44. if a and b == "OK" then break end -- stop when no more errors
  45. if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
  46. error(a, 0) -- propagate it
  47. end
  48. M = M + 7 -- increase memory limit
  49. end
  50. print(string.format("minimum memory for %s: %d bytes", s, M - oldM))
  51. return a
  52. end
  53. -- test memory errors; increase limit for number of allocations one
  54. -- by one, so that we get memory errors in all allocations of a given
  55. -- task, until there is enough allocations to complete the task without
  56. -- errors.
  57. local function testalloc (s, f)
  58. collectgarbage()
  59. local M = 0
  60. local a,b = nil
  61. while true do
  62. collectgarbage(); collectgarbage()
  63. T.alloccount(M)
  64. a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
  65. T.alloccount() -- remove limit
  66. if a and b == "OK" then break end -- stop when no more errors
  67. if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
  68. error(a, 0) -- propagate it
  69. end
  70. M = M + 1 -- increase allocation limit
  71. end
  72. print(string.format("minimum allocations for %s: %d allocations", s, M))
  73. return a
  74. end
  75. local function testamem (s, f)
  76. testalloc(s, f)
  77. return testbytes(s, f)
  78. end
  79. -- doing nothing
  80. b = testamem("doing nothing", function () return 10 end)
  81. assert(b == 10)
  82. -- testing memory errors when creating a new state
  83. testamem("state creation", function ()
  84. local st = T.newstate()
  85. if st then T.closestate(st) end -- close new state
  86. return st
  87. end)
  88. testamem("empty-table creation", function ()
  89. return {}
  90. end)
  91. testamem("string creation", function ()
  92. return "XXX" .. "YYY"
  93. end)
  94. testamem("coroutine creation", function()
  95. return coroutine.create(print)
  96. end)
  97. -- testing to-be-closed variables
  98. testamem("to-be-closed variables", function()
  99. local flag
  100. do
  101. local x <close> =
  102. setmetatable({}, {__close = function () flag = true end})
  103. flag = false
  104. local x = {}
  105. end
  106. return flag
  107. end)
  108. -- testing threads
  109. -- get main thread from registry
  110. local mt = T.testC("rawgeti R !M; return 1")
  111. assert(type(mt) == "thread" and coroutine.running() == mt)
  112. local function expand (n,s)
  113. if n==0 then return "" end
  114. local e = string.rep("=", n)
  115. return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
  116. e, s, expand(n-1,s), e)
  117. end
  118. G=0; collectgarbage(); a =collectgarbage("count")
  119. load(expand(20,"G=G+1"))()
  120. assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1)
  121. G = nil
  122. testamem("running code on new thread", function ()
  123. return T.doonnewstack("local x=1") == 0 -- try to create thread
  124. end)
  125. -- testing memory x compiler
  126. testamem("loadstring", function ()
  127. return load("x=1") -- try to do load a string
  128. end)
  129. local testprog = [[
  130. local function foo () return end
  131. local t = {"x"}
  132. AA = "aaa"
  133. for i = 1, #t do AA = AA .. t[i] end
  134. return true
  135. ]]
  136. -- testing memory x dofile
  137. _G.AA = nil
  138. local t =os.tmpname()
  139. local f = assert(io.open(t, "w"))
  140. f:write(testprog)
  141. f:close()
  142. testamem("dofile", function ()
  143. local a = loadfile(t)
  144. return a and a()
  145. end)
  146. assert(os.remove(t))
  147. assert(_G.AA == "aaax")
  148. -- other generic tests
  149. testamem("gsub", function ()
  150. local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end)
  151. return (a == 'ablo ablo')
  152. end)
  153. testamem("dump/undump", function ()
  154. local a = load(testprog)
  155. local b = a and string.dump(a)
  156. a = b and load(b)
  157. return a and a()
  158. end)
  159. _G.AA = nil
  160. local t = os.tmpname()
  161. testamem("file creation", function ()
  162. local f = assert(io.open(t, 'w'))
  163. assert (not io.open"nomenaoexistente")
  164. io.close(f);
  165. return not loadfile'nomenaoexistente'
  166. end)
  167. assert(os.remove(t))
  168. testamem("table creation", function ()
  169. local a, lim = {}, 10
  170. for i=1,lim do a[i] = i; a[i..'a'] = {} end
  171. return (type(a[lim..'a']) == 'table' and a[lim] == lim)
  172. end)
  173. testamem("constructors", function ()
  174. local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5}
  175. return (type(a) == 'table' and a.e == 5)
  176. end)
  177. local a = 1
  178. local close = nil
  179. testamem("closure creation", function ()
  180. function close (b)
  181. return function (x) return b + x end
  182. end
  183. return (close(2)(4) == 6)
  184. end)
  185. testamem("using coroutines", function ()
  186. local a = coroutine.wrap(function ()
  187. coroutine.yield(string.rep("a", 10))
  188. return {}
  189. end)
  190. assert(string.len(a()) == 10)
  191. return a()
  192. end)
  193. do -- auxiliary buffer
  194. local lim = 100
  195. local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end
  196. testamem("auxiliary buffer", function ()
  197. return (#table.concat(a, ",") == 20*lim + lim - 1)
  198. end)
  199. end
  200. testamem("growing stack", function ()
  201. local function foo (n)
  202. if n == 0 then return 1 else return 1 + foo(n - 1) end
  203. end
  204. return foo(100)
  205. end)
  206. -- }==================================================================
  207. print "Ok"