[2019-12] [threads] Add back mono_threads_attach_tools_thread as a public API (#18074)
[mono-project.git] / mono / tests / merp-crash-test.cs
blobd04f814e31830cb0ada8c51b6ffd9b8ff0c0f129
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Runtime.CompilerServices;
5 using System.Reflection;
6 using System.Web.Script.Serialization;
7 using Diag = System.Diagnostics;
8 using System.Runtime.InteropServices;
10 class C
12 class CrasherClass
14 public static List<Tuple<String, Action>> Crashers;
15 public static int StresserIndex;
17 static CrasherClass ()
19 Crashers = new List<Tuple<String, Action>> ();
21 // Basic functionality
22 Crashers.Add(new Tuple<String, Action> ("MerpCrashManaged", MerpCrashManaged));
23 // Run this test for stress tests
25 // I've ran a burn-in with all of them of
26 // 1,000 - 10,000 runs already.
28 // Feel free to change by moving this line.
29 StresserIndex = Crashers.Count - 1;
31 Crashers.Add(new Tuple<String, Action> ("MerpCrashMalloc", MerpCrashMalloc));
33 Crashers.Add(new Tuple<String, Action> ("MerpCrashNullFp", MerpCrashNullFp));
34 Crashers.Add(new Tuple<String, Action> ("MerpCrashExceptionHook", MerpCrashUnhandledExceptionHook));
36 // Specific Edge Cases
37 Crashers.Add(new Tuple<String, Action> ("MerpCrashDladdr", MerpCrashDladdr));
38 Crashers.Add(new Tuple<String, Action> ("MerpCrashSnprintf", MerpCrashSnprintf));
39 Crashers.Add(new Tuple<String, Action> ("MerpCrashDomainUnload", MerpCrashDomainUnload));
40 Crashers.Add(new Tuple<String, Action> ("MerpCrashUnbalancedGCSafe", MerpCrashUnbalancedGCSafe));
43 public static void
44 MerpCrashManaged ()
46 unsafe { Console.WriteLine("{0}", *(int*) -1); }
49 [DllImport("libtest")]
50 public static extern void mono_test_MerpCrashSnprintf ();
52 // This test tries to test the writer's reentrancy
53 public static void
54 MerpCrashSnprintf ()
56 mono_test_MerpCrashSnprintf ();
59 [DllImport("libtest")]
60 public static extern void mono_test_MerpCrashDladdr ();
62 public static void
63 MerpCrashDladdr ()
65 mono_test_MerpCrashDladdr ();
68 [DllImport("libtest")]
69 public static extern void mono_test_MerpCrashMalloc ();
71 public static void
72 MerpCrashMalloc ()
74 mono_test_MerpCrashMalloc ();
77 [DllImport("libtest")]
78 public static extern void mono_test_MerpCrashLoaderLock ();
80 public static void
81 MerpCrashLoaderLock ()
83 mono_test_MerpCrashLoaderLock ();
86 [DllImport("libtest")]
87 public static extern void mono_test_MerpCrashDomainUnload ();
89 public static void
90 MerpCrashDomainUnload ()
92 mono_test_MerpCrashDomainUnload ();
95 [DllImport("libtest")]
96 public static extern void mono_test_MerpCrashUnbalancedGCSafe ();
98 public static void
99 MerpCrashUnbalancedGCSafe ()
101 mono_test_MerpCrashUnbalancedGCSafe ();
104 [DllImport("libtest")]
105 public static extern void mono_test_MerpCrashNullFp ();
107 public static void
108 MerpCrashNullFp ()
110 mono_test_MerpCrashNullFp ();
113 [DllImport("libtest")]
114 public static extern void mono_test_MerpCrashUnhandledExceptionHook ();
116 public static void
117 MerpCrashUnhandledExceptionHook ()
119 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(HandleException);
120 throw new Exception ("This is Unhandled");
123 public static void HandleException (object sender, UnhandledExceptionEventArgs e)
125 Console.WriteLine ("And now to crash inside the hook");
126 mono_test_MerpCrashUnhandledExceptionHook ();
130 static string configDir = "./merp-crash-test/";
132 public static void
133 CrashWithMerp (int testNum)
135 SetupCrash (configDir);
136 CrasherClass.Crashers [Convert.ToInt32 (testNum)].Item2 ();
139 public static string env = Environment.GetEnvironmentVariable ("MONO_PATH");
140 public static string this_assembly_path = Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location);
142 public static void
143 SetupCrash (string configDir)
145 var monoType = Type.GetType ("Mono.Runtime", false);
146 var m = monoType.GetMethod("EnableMicrosoftTelemetry", BindingFlags.NonPublic | BindingFlags.Static);
148 // This leads to open -a /bin/cat, which errors out, but errors
149 // in invoking merp are only logged errors, not fatal assertions.
150 var merpGUIPath = "/bin/cat";
151 var appBundleId = "com.xam.Minimal";
152 var appSignature = "Test.Xam.Minimal";
153 var appVersion = "123456";
154 var eventType = "AppleAppCrash";
155 var appPath = "/where/mono/lives";
156 var m_params = new object[] { appBundleId, appSignature, appVersion, merpGUIPath, eventType, appPath, configDir };
158 m.Invoke(null, m_params);
160 DumpLogSet ();
163 public static void
164 TestValidate (string configDir, bool silent)
166 DumpLogCheck ();
168 var xmlFilePath = String.Format("{0}CustomLogsMetadata.xml", configDir);
169 var paramsFilePath = String.Format("{0}MERP.uploadparams.txt", configDir);
170 var crashFilePath = String.Format("{0}lastcrashlog.txt", configDir);
172 // Fixme: Maybe parse these json files rather than
173 // just checking they exist
174 var xmlFileExists = File.Exists (xmlFilePath);
175 var paramsFileExists = File.Exists (paramsFilePath);
176 var crashFileExists = File.Exists (crashFilePath);
178 if (xmlFileExists) {
179 var text = File.ReadAllText (xmlFilePath);
180 if (!silent)
181 Console.WriteLine ("Xml file {0}", text);
182 File.Delete (xmlFilePath);
183 } else {
184 Console.WriteLine ("Xml file {0} missing", xmlFilePath);
187 if (paramsFileExists) {
188 var text = File.ReadAllText (paramsFilePath);
189 if (!silent)
190 Console.WriteLine ("Params file {0}", text);
191 File.Delete (paramsFilePath);
192 } else {
193 Console.WriteLine ("Params file {0} missing", paramsFilePath);
196 if (crashFileExists) {
197 var crashFile = File.ReadAllText (crashFilePath);
198 File.Delete (crashFilePath);
200 var checker = new JavaScriptSerializer ();
202 // Throws if invalid json
203 if (!silent)
204 Console.WriteLine("Validating: {0}", crashFile);
205 try {
206 var obj = checker.DeserializeObject (crashFile);
207 } catch (Exception e) {
208 throw new Exception (String.Format ("Invalid json: {0}", crashFile));
211 File.Delete (crashFilePath);
212 // Assert it has the required merp fields
213 } else {
214 Console.WriteLine ("Crash file {0} missing", crashFilePath);
217 if (!xmlFileExists)
218 throw new Exception (String.Format ("Did not produce {0}", xmlFilePath));
220 if (!paramsFileExists)
221 throw new Exception (String.Format ("Did not produce {0}", paramsFilePath));
223 if (!crashFileExists)
224 throw new Exception (String.Format ("Did not produce {0}", crashFilePath));
227 public static void
228 Cleanup (string configDir)
230 Directory.Delete (configDir, true);
233 static void DumpLogSet ()
235 var monoType = Type.GetType ("Mono.Runtime", false);
236 var convert = monoType.GetMethod("EnableCrashReportLog", BindingFlags.NonPublic | BindingFlags.Static);
237 convert.Invoke(null, new object[] { "./" });
240 static void DumpLogUnset ()
242 var monoType = Type.GetType ("Mono.Runtime", false);
243 var convert = monoType.GetMethod("EnableCrashReportLog", BindingFlags.NonPublic | BindingFlags.Static);
244 convert.Invoke(null, new object[] { null });
247 static void DumpLogCheck ()
249 var monoType = Type.GetType ("Mono.Runtime", false);
250 var convert = monoType.GetMethod("CheckCrashReportLog", BindingFlags.NonPublic | BindingFlags.Static);
251 var result = (int) convert.Invoke(null, new object[] { "./", true });
252 // Value of enum
253 string [] levels = new string [] { "None", "Setup", "SuspendHandshake", "UnmanagedStacks", "ManagedStacks", "StateWriter", "StateWriterDone", "MerpWriter", "MerpInvoke", "Cleanup", "Done", "DoubleFault" };
255 if ("MerpInvoke" == levels [result]) {
256 Console.WriteLine ("Merp invoke command failed, expected failure?");
257 } else if ("Done" != levels [result]) {
258 throw new Exception (String.Format ("Crash level not done, failed in stage: {0}", levels [result]));
263 public static void
264 SpawnCrashingRuntime (string runtime, int testNum, bool silent)
266 var asm = "merp-crash-test.exe";
267 var pi = new Diag.ProcessStartInfo ();
268 pi.UseShellExecute = false;
269 pi.FileName = runtime;
270 pi.Arguments = String.Format ("{0} {1}", asm, testNum);;
271 pi.Environment ["MONO_PATH"] = env;
273 if (!silent) {
274 Console.WriteLine ("Running {0}", CrasherClass.Crashers [testNum].Item1);
275 Console.WriteLine ("MONO_PATH={0} {1} {2} {3}", env, runtime, asm, testNum);
278 if (Directory.Exists (configDir)) {
279 Console.WriteLine ("Cleaning up left over configDir {0}", configDir);
280 Cleanup (configDir);
283 Directory.CreateDirectory (configDir);
285 try {
286 var process = Diag.Process.Start (pi);
287 process.WaitForExit ();
289 TestValidate (configDir, silent);
290 } finally {
291 Cleanup (configDir);
295 public static int Main (string [] args)
297 if (args.Length == 0) {
298 string processExe = Diag.Process.GetCurrentProcess ().MainModule.FileName;
299 if (processExe == null)
300 throw new ArgumentException ("Couldn't get name of running file");
301 else if (string.IsNullOrEmpty (processExe))
302 throw new ArgumentException ("Couldn't find mono runtime.");
303 else if (!Path.GetFileName (processExe).StartsWith ("mono"))
304 throw new ArgumentException (String.Format("Running native app {0} isn't 'mono'"));
306 var failures = new Exception [CrasherClass.Crashers.Count];
307 int failure_count = 0;
308 for (int i=0; i < CrasherClass.Crashers.Count; i++) {
309 try {
310 SpawnCrashingRuntime (processExe, i, false);
311 } catch (Exception e) {
312 failures [i] = e;
313 if (e.InnerException != null)
314 failures [i] = e.InnerException;
315 failure_count++;
319 Console.WriteLine ("\n\n##################");
320 Console.WriteLine ("Merp Test Results:");
321 Console.WriteLine ("##################\n\n");
323 if (failure_count > 0) {
324 for (int i=0; i < CrasherClass.Crashers.Count; i++) {
325 if (failures [i] != null) {
326 Console.WriteLine ("Crash reporter failed test {0}", CrasherClass.Crashers [i].Item1);
327 Console.WriteLine ("Cause: {0}\n{1}\n", failures [i].Message, failures [i].StackTrace);
332 if (failure_count > 0)
333 return 1;
335 Console.WriteLine ("\n\n##################");
336 Console.WriteLine ("Merp Stress Test:");
337 Console.WriteLine ("##################\n\n");
339 Console.WriteLine ("Starting crash stress test\n");
340 int iter = 0;
341 for (iter=0; iter < 20; iter++) {
342 Console.WriteLine ("\n#############################################");
343 Console.WriteLine ("\tMerp Stress Test Iteration {0}", iter);
344 Console.WriteLine ("#############################################\n");
345 try {
346 SpawnCrashingRuntime (processExe, CrasherClass.StresserIndex, true);
347 } catch (Exception e) {
348 Console.WriteLine ("Stress test caught failure. Shutting down after {1} iterations.\n {0} \n\n", e.InnerException, iter);
349 throw;
352 Console.WriteLine ("Ending crash stress test. No failures caught.\n");
354 return 0;
355 } else {
356 CrashWithMerp (Convert.ToInt32 (args [0]));
357 return 0;