cstack.lua 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. -- $Id: testes/cstack.lua $
  2. -- See Copyright Notice in file all.lua
  3. print"testing stack overflow detection"
  4. -- Segmentation faults in these tests probably result from a C-stack
  5. -- overflow. To avoid these errors, you should set a smaller limit for
  6. -- the use of C stack by Lua, by changing the constant 'LUAI_MAXCCALLS'.
  7. -- Alternatively, you can ensure a larger stack for the program.
  8. local function checkerror (msg, f, ...)
  9. local s, err = pcall(f, ...)
  10. assert(not s and string.find(err, msg))
  11. end
  12. do print("testing stack overflow in message handling")
  13. local count = 0
  14. local function loop (x, y, z)
  15. count = count + 1
  16. return 1 + loop(x, y, z)
  17. end
  18. local res, msg = xpcall(loop, loop)
  19. assert(msg == "error in error handling")
  20. print("final count: ", count)
  21. end
  22. -- bug since 2.5 (C-stack overflow in recursion inside pattern matching)
  23. do print("testing recursion inside pattern matching")
  24. local function f (size)
  25. local s = string.rep("a", size)
  26. local p = string.rep(".?", size)
  27. return string.match(s, p)
  28. end
  29. local m = f(80)
  30. assert(#m == 80)
  31. checkerror("too complex", f, 2000)
  32. end
  33. do print("testing stack-overflow in recursive 'gsub'")
  34. local count = 0
  35. local function foo ()
  36. count = count + 1
  37. string.gsub("a", ".", foo)
  38. end
  39. checkerror("stack overflow", foo)
  40. print("final count: ", count)
  41. print("testing stack-overflow in recursive 'gsub' with metatables")
  42. local count = 0
  43. local t = setmetatable({}, {__index = foo})
  44. foo = function ()
  45. count = count + 1
  46. string.gsub("a", ".", t)
  47. end
  48. checkerror("stack overflow", foo)
  49. print("final count: ", count)
  50. end
  51. do -- bug in 5.4.0
  52. print("testing limits in coroutines inside deep calls")
  53. local count = 0
  54. local lim = 1000
  55. local function stack (n)
  56. if n > 0 then return stack(n - 1) + 1
  57. else coroutine.wrap(function ()
  58. count = count + 1
  59. stack(lim)
  60. end)()
  61. end
  62. end
  63. local st, msg = xpcall(stack, function () return "ok" end, lim)
  64. assert(not st and msg == "ok")
  65. print("final count: ", count)
  66. end
  67. do
  68. print("nesting of resuming yielded coroutines")
  69. local count = 0
  70. local function body ()
  71. coroutine.yield()
  72. local f = coroutine.wrap(body)
  73. f(); -- start new coroutine (will stop in previous yield)
  74. count = count + 1
  75. f() -- call it recursively
  76. end
  77. local f = coroutine.wrap(body)
  78. f()
  79. assert(not pcall(f))
  80. print("final count: ", count)
  81. end
  82. if T then
  83. print("testing stack recovery")
  84. local N = 0 -- trace number of calls
  85. local LIM = -1 -- will store N just before stack overflow
  86. -- trace stack size; after stack overflow, it should be
  87. -- the maximum allowed stack size.
  88. local stack1
  89. local dummy
  90. local function err(msg)
  91. assert(string.find(msg, "stack overflow"))
  92. local _, stacknow = T.stacklevel()
  93. assert(stacknow == stack1 + 200)
  94. end
  95. -- When LIM==-1, the 'if' is not executed, so this function only
  96. -- counts and stores the stack limits up to overflow. Then, LIM
  97. -- becomes N, and then the 'if' code is run when the stack is
  98. -- full. Then, there is a stack overflow inside 'xpcall', after which
  99. -- the stack must have been restored back to its maximum normal size.
  100. local function f()
  101. dummy, stack1 = T.stacklevel()
  102. if N == LIM then
  103. xpcall(f, err)
  104. local _, stacknow = T.stacklevel()
  105. assert(stacknow == stack1)
  106. return
  107. end
  108. N = N + 1
  109. f()
  110. end
  111. local topB, sizeB -- top and size Before overflow
  112. local topA, sizeA -- top and size After overflow
  113. topB, sizeB = T.stacklevel()
  114. xpcall(f, err)
  115. topA, sizeA = T.stacklevel()
  116. -- sizes should be comparable
  117. assert(topA == topB and sizeA < sizeB * 2)
  118. print(string.format("maximum stack size: %d", stack1))
  119. LIM = N -- will stop recursion at maximum level
  120. N = 0 -- to count again
  121. f()
  122. print"+"
  123. end
  124. print'OK'