EngineLimitTests.cs 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #if !NETFRAMEWORK
  2. using System.Text;
  3. using Jint.Runtime;
  4. namespace Jint.Tests.Runtime;
  5. public class EngineLimitTests
  6. {
  7. #if RELEASE
  8. const int FunctionNestingCount = 990;
  9. #else
  10. const int FunctionNestingCount = 495;
  11. #endif
  12. [Fact]
  13. public void ShouldAllowReasonableCallStackDepth()
  14. {
  15. if (OperatingSystem.IsMacOS())
  16. {
  17. // stack limit differ quite a lot
  18. return;
  19. }
  20. var script = GenerateCallTree(FunctionNestingCount);
  21. var engine = new Engine();
  22. engine.Execute(script);
  23. Assert.Equal(123, engine.Evaluate("func1(123);").AsNumber());
  24. Assert.Equal(FunctionNestingCount, engine.Evaluate("x").AsNumber());
  25. }
  26. [Fact]
  27. public void ShouldNotStackoverflowWhenStackGuardEnable()
  28. {
  29. // Can be more than actual dotnet stacktrace count, It does not hit stackoverflow anymore.
  30. int functionNestingCount = FunctionNestingCount * 2;
  31. var script = GenerateCallTree(functionNestingCount);
  32. var engine = new Engine(option => option.Constraints.MaxExecutionStackCount = functionNestingCount);
  33. engine.Execute(script);
  34. Assert.Equal(123, engine.Evaluate("func1(123);").AsNumber());
  35. Assert.Equal(functionNestingCount, engine.Evaluate("x").AsNumber());
  36. }
  37. [Fact]
  38. public void ShouldThrowJavascriptExceptionWhenStackGuardExceed()
  39. {
  40. // Can be more than actual dotnet stacktrace count, It does not hit stackoverflow anymore.
  41. int functionNestingCount = FunctionNestingCount * 2;
  42. var script = GenerateCallTree(functionNestingCount);
  43. var engine = new Engine(option => option.Constraints.MaxExecutionStackCount = 500);
  44. try
  45. {
  46. engine.Execute(script);
  47. engine.Evaluate("func1(123);");
  48. }
  49. catch (JavaScriptException jsException)
  50. {
  51. Assert.Equal("Maximum call stack size exceeded", jsException.Message);
  52. }
  53. }
  54. private string GenerateCallTree(int functionNestingCount)
  55. {
  56. var sb = new StringBuilder();
  57. sb.AppendLine("var x = 1;");
  58. sb.AppendLine();
  59. for (var i = 1; i <= functionNestingCount; ++i)
  60. {
  61. sb.Append("function func").Append(i).Append("(func").Append(i).AppendLine("Param) {");
  62. sb.Append(" ");
  63. if (i != functionNestingCount)
  64. {
  65. // just to create a bit more nesting add some constructs
  66. sb.Append("return x++ >= 1 ? func").Append(i + 1).Append("(func").Append(i).AppendLine("Param): undefined;");
  67. }
  68. else
  69. {
  70. // use known CLR function to add breakpoint
  71. sb.Append("return Math.max(0, func").Append(i).AppendLine("Param);");
  72. }
  73. sb.AppendLine("}");
  74. sb.AppendLine();
  75. }
  76. return sb.ToString();
  77. }
  78. }
  79. #endif