cstack.lua 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. -- $Id: testes/cstack.lua $
  2. -- See Copyright Notice in file all.lua
  3. local debug = require "debug"
  4. print"testing C-stack overflow detection"
  5. print"If this test craches, see its file ('cstack.lua')"
  6. -- Segmentation faults in these tests probably result from a C-stack
  7. -- overflow. To avoid these errors, you can use the function
  8. -- 'debug.setcstacklimit' to set a smaller limit for the use of
  9. -- C stack by Lua. After finding a reliable limit, you might want
  10. -- to recompile Lua with this limit as the value for
  11. -- the constant 'LUAI_MAXCCALLS', which defines the default limit.
  12. -- (The default limit is printed by this test.)
  13. -- Alternatively, you can ensure a larger stack for the program.
  14. -- For Linux, a limit up to 30_000 seems Ok. Windows cannot go much
  15. -- higher than 2_000.
  16. local origlimit = debug.setcstacklimit(400)
  17. print("default stack limit: " .. origlimit)
  18. -- change this value for different limits for this test suite
  19. local currentlimit = origlimit
  20. debug.setcstacklimit(currentlimit)
  21. print("current stack limit: " .. currentlimit)
  22. local function checkerror (msg, f, ...)
  23. local s, err = pcall(f, ...)
  24. assert(not s and string.find(err, msg))
  25. end
  26. local count
  27. local back = string.rep("\b", 8)
  28. local function progress ()
  29. count = count + 1
  30. local n = string.format("%-8d", count)
  31. io.stderr:write(back, n)
  32. end
  33. do print("testing simple recursion:")
  34. count = 0
  35. local function foo ()
  36. progress()
  37. foo()
  38. end
  39. checkerror("stack overflow", foo)
  40. print("\tfinal count: ", count)
  41. end
  42. do print("testing stack overflow in message handling")
  43. count = 0
  44. local function loop (x, y, z)
  45. progress()
  46. return 1 + loop(x, y, z)
  47. end
  48. local res, msg = xpcall(loop, loop)
  49. assert(msg == "error in error handling")
  50. print("\tfinal count: ", count)
  51. end
  52. -- bug since 2.5 (C-stack overflow in recursion inside pattern matching)
  53. do print("testing recursion inside pattern matching")
  54. local function f (size)
  55. local s = string.rep("a", size)
  56. local p = string.rep(".?", size)
  57. return string.match(s, p)
  58. end
  59. local m = f(80)
  60. assert(#m == 80)
  61. checkerror("too complex", f, 200000)
  62. end
  63. do print("testing stack-overflow in recursive 'gsub'")
  64. count = 0
  65. local function foo ()
  66. progress()
  67. string.gsub("a", ".", foo)
  68. end
  69. checkerror("stack overflow", foo)
  70. print("\tfinal count: ", count)
  71. print("testing stack-overflow in recursive 'gsub' with metatables")
  72. count = 0
  73. local t = setmetatable({}, {__index = foo})
  74. foo = function ()
  75. count = count + 1
  76. progress(count)
  77. string.gsub("a", ".", t)
  78. end
  79. checkerror("stack overflow", foo)
  80. print("\tfinal count: ", count)
  81. end
  82. do print("testing changes in C-stack limit")
  83. assert(not debug.setcstacklimit(0)) -- limit too small
  84. assert(not debug.setcstacklimit(50000)) -- limit too large
  85. local co = coroutine.wrap (function ()
  86. return debug.setcstacklimit(400)
  87. end)
  88. assert(co() == false) -- cannot change C stack inside coroutine
  89. local n
  90. local function foo () n = n + 1; foo () end
  91. local function check ()
  92. n = 0
  93. pcall(foo)
  94. return n
  95. end
  96. assert(debug.setcstacklimit(400) == currentlimit)
  97. local lim400 = check()
  98. -- a very low limit (given that the several calls to arive here)
  99. local lowlimit = 38
  100. assert(debug.setcstacklimit(lowlimit) == 400)
  101. assert(check() < lowlimit - 30)
  102. assert(debug.setcstacklimit(600) == lowlimit)
  103. local lim600 = check()
  104. assert(lim600 == lim400 + 200)
  105. -- 'setcstacklimit' works inside protected calls. (The new stack
  106. -- limit is kept when 'pcall' returns.)
  107. assert(pcall(function ()
  108. assert(debug.setcstacklimit(400) == 600)
  109. assert(check() <= lim400)
  110. end))
  111. assert(check() == lim400)
  112. assert(debug.setcstacklimit(origlimit) == 400) -- restore original limit
  113. end
  114. print'OK'