// TOP of special stack for handling stack overflow
volatile void* g_stackOverflowHandlerStack = NULL;
+
+// Flag that is or-ed with SIGSEGV to indicate that the SIGSEGV was a stack overflow
+const int StackOverflowFlag = 0x40000000;
+
#endif // !HAVE_MACH_EXCEPTIONS
/* public function definitions ************************************************/
}
}
- if (SwitchStackAndExecuteHandler(code, siginfo, context, (size_t)handlerStackTop))
+ if (SwitchStackAndExecuteHandler(code | StackOverflowFlag, siginfo, context, (size_t)handlerStackTop))
{
PROCAbort();
}
ucontext = (native_context_t *)sigcontext;
g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0));
- exceptionRecord.ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
+ if (code == (SIGSEGV | StackOverflowFlag))
+ {
+ exceptionRecord.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
+ code &= ~StackOverflowFlag;
+ }
+ else
+ {
+ exceptionRecord.ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
+ }
exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL;
exceptionRecord.ExceptionRecord = NULL;
exceptionRecord.ExceptionAddress = GetNativeContextPC(ucontext);
--- /dev/null
+using System;
+using System.Threading;
+
+namespace TestStackOverflow
+{
+ struct LargeStruct256
+ {
+ Guid g0;
+ Guid g1;
+ Guid g2;
+ Guid g3;
+ Guid g4;
+ Guid g5;
+ Guid g6;
+ Guid g7;
+ Guid g8;
+ Guid g9;
+ Guid ga;
+ Guid gb;
+ Guid gc;
+ Guid gd;
+ Guid ge;
+ Guid gf;
+ }
+
+ struct LargeStruct4096
+ {
+ LargeStruct256 s0;
+ LargeStruct256 s1;
+ LargeStruct256 s2;
+ LargeStruct256 s3;
+ LargeStruct256 s4;
+ LargeStruct256 s5;
+ LargeStruct256 s6;
+ LargeStruct256 s7;
+ LargeStruct256 s8;
+ LargeStruct256 s9;
+ LargeStruct256 sa;
+ LargeStruct256 sb;
+ LargeStruct256 sc;
+ LargeStruct256 sd;
+ LargeStruct256 se;
+ LargeStruct256 sf;
+ }
+
+ struct LargeStruct65536
+ {
+ LargeStruct4096 s0;
+ LargeStruct4096 s1;
+ LargeStruct4096 s2;
+ LargeStruct4096 s3;
+ LargeStruct4096 s4;
+ LargeStruct4096 s5;
+ LargeStruct4096 s6;
+ LargeStruct4096 s7;
+ LargeStruct4096 s8;
+ LargeStruct4096 s9;
+ LargeStruct4096 sa;
+ LargeStruct4096 sb;
+ LargeStruct4096 sc;
+ LargeStruct4096 sd;
+ LargeStruct4096 se;
+ LargeStruct4096 sf;
+ }
+ class Program
+ {
+ static void InfiniteRecursionA()
+ {
+ InfiniteRecursionB();
+ }
+
+ static void InfiniteRecursionB()
+ {
+ InfiniteRecursionC();
+ }
+ static void InfiniteRecursionC()
+ {
+ InfiniteRecursionA();
+ }
+
+ static void InfiniteRecursionA2()
+ {
+ LargeStruct65536 s;
+ InfiniteRecursionB2();
+ }
+
+ static void InfiniteRecursionB2()
+ {
+ LargeStruct65536 s;
+ InfiniteRecursionC2();
+ }
+
+ static void InfiniteRecursionC2()
+ {
+ LargeStruct65536 s;
+ InfiniteRecursionA2();
+ }
+
+ static void MainThreadTest(bool smallframe)
+ {
+ if (smallframe)
+ {
+ InfiniteRecursionA();
+ }
+ else
+ {
+ InfiniteRecursionA2();
+ }
+ }
+
+ static void SecondaryThreadsTest(bool smallframe)
+ {
+ Thread[] threads = new Thread[32];
+ for (int i = 0; i < threads.Length; i++)
+ {
+ threads[i] = new Thread(() => {
+ if (smallframe)
+ {
+ InfiniteRecursionA();
+ }
+ else
+ {
+ InfiniteRecursionA2();
+ }
+ });
+ threads[i].Start();
+ }
+
+ for (int i = 0; i < threads.Length; i++)
+ {
+ threads[i].Join();
+ }
+ }
+
+ static void Main(string[] args)
+ {
+ bool smallframe = (args[0] == "smallframe");
+ if (args[1] == "secondary")
+ {
+ SecondaryThreadsTest(smallframe);
+ }
+ else if (args[1] == "main")
+ {
+ MainThreadTest(smallframe);
+ }
+ }
+ }
+}
+
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+
+namespace TestStackOverflow
+{
+ class Program
+ {
+ static string s_corerunPath;
+ static string s_currentPath;
+
+ static bool TestStackOverflow(string testName, string testArgs, out List<string> stderrLines)
+ {
+ Console.WriteLine($"Running {testName} test({testArgs})");
+ List<string> lines = new List<string>();
+
+ Process testProcess = new Process();
+
+ testProcess.StartInfo.FileName = s_corerunPath;
+ testProcess.StartInfo.Arguments = $"{Path.Combine(s_currentPath, "..", testName, $"{testName}.dll")} {testArgs}";
+ testProcess.StartInfo.UseShellExecute = false;
+ testProcess.StartInfo.RedirectStandardError = true;
+ testProcess.ErrorDataReceived += (sender, line) =>
+ {
+ Console.WriteLine($"\"{line.Data}\"");
+ if (!string.IsNullOrEmpty(line.Data))
+ {
+ lines.Add(line.Data);
+ }
+ };
+
+ testProcess.Start();
+ testProcess.BeginErrorReadLine();
+ testProcess.WaitForExit();
+ testProcess.CancelErrorRead();
+
+ stderrLines = lines;
+
+ int expectedExitCode;
+ if ((Environment.OSVersion.Platform == PlatformID.Unix) || (Environment.OSVersion.Platform == PlatformID.MacOSX))
+ {
+ expectedExitCode = 128 + 6;
+ }
+ else
+ {
+ expectedExitCode = unchecked((int)0xC00000FD);
+ }
+
+ if (testProcess.ExitCode != expectedExitCode)
+ {
+ Console.WriteLine($"Exit code: 0x{testProcess.ExitCode:X8}, expected 0x{expectedExitCode:X8}");
+ return false;
+ }
+
+ if (lines[0] != "Stack overflow.")
+ {
+ Console.WriteLine("Missing \"Stack overflow.\" at the first line");
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool TestStackOverflowSmallFrameMainThread()
+ {
+ List<string> lines;
+ if (TestStackOverflow("stackoverflow", "smallframe main", out lines))
+ {
+ if (!lines[lines.Count - 1].EndsWith("at TestStackOverflow.Program.Main(System.String[])"))
+ {
+ Console.WriteLine("Missing \"Main\" method frame at the last line");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionA()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionA\" method frame");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionB()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionB\" method frame");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionC()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionC\" method frame");
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool TestStackOverflowLargeFrameMainThread()
+ {
+ List<string> lines;
+ if (TestStackOverflow("stackoverflow", "largeframe main", out lines))
+ {
+ if (!lines[lines.Count - 1].EndsWith("at TestStackOverflow.Program.Main(System.String[])"))
+ {
+ Console.WriteLine("Missing \"Main\" method frame at the last line");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("TestStackOverflow.Program.MainThreadTest(Boolean)")))
+ {
+ Console.WriteLine("Missing \"MainThreadTest\" method frame");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionA2()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionA2\" method frame");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionB2()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionB2\" method frame");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionC2()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionC2\" method frame");
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool TestStackOverflowSmallFrameSecondaryThread()
+ {
+ List<string> lines;
+ if (TestStackOverflow("stackoverflow", "smallframe secondary", out lines))
+ {
+ if (!lines[lines.Count - 1].EndsWith("at System.Threading.ThreadHelper.ThreadStart()"))
+ {
+ Console.WriteLine("Missing \"System.Threading.ThreadHelper.ThreadStart\" method frame at the last line");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionA()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionA\" method frame");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionB()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionB\" method frame");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionC()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionC\" method frame");
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool TestStackOverflowLargeFrameSecondaryThread()
+ {
+ List<string> lines;
+ if (TestStackOverflow("stackoverflow", "largeframe secondary", out lines))
+ {
+ if (!lines[lines.Count - 1].EndsWith("at System.Threading.ThreadHelper.ThreadStart()"))
+ {
+ Console.WriteLine("Missing \"System.Threading.ThreadHelper.ThreadStart\" method frame at the last line");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionA2()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionA2\" method frame");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("TestStackOverflow.Program.InfiniteRecursionB2()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionB2\" method frame");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("TestStackOverflow.Program.InfiniteRecursionC2()")))
+ {
+ Console.WriteLine("Missing \"InfiniteRecursionC2\" method frame");
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool TestStackOverflow3()
+ {
+ List<string> lines;
+ if (TestStackOverflow("stackoverflow3", "", out lines))
+ {
+ if (!lines[lines.Count - 1].EndsWith("at TestStackOverflow3.Program.Main()"))
+ {
+ Console.WriteLine("Missing \"Main\" method frame at the last line");
+ return false;
+ }
+
+ if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow3.Program.Execute(System.String)")))
+ {
+ Console.WriteLine("Missing \"Execute\" method frame");
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ static int Main(string[] args)
+ {
+ s_currentPath = Directory.GetCurrentDirectory();
+ s_corerunPath = Path.Combine(Environment.GetEnvironmentVariable("CORE_ROOT"), "corerun");
+
+ if (!TestStackOverflowSmallFrameMainThread())
+ {
+ return 101;
+ }
+
+ if (!TestStackOverflowLargeFrameMainThread())
+ {
+ return 102;
+ }
+
+ if (!TestStackOverflowSmallFrameSecondaryThread())
+ {
+ return 103;
+ }
+
+ if (!TestStackOverflowLargeFrameSecondaryThread())
+ {
+ return 104;
+ }
+
+ if (!TestStackOverflow3())
+ {
+ return 105;
+ }
+
+ return 100;
+ }
+ }
+}