Add assert when dllmap is disabled and fix support build in netcore mode
[mono-project.git] / mono / tests / merp-crash-test.cs
blob82cc3513e2e8661ae8a40cc5c4021c176f1349b8
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 struct Crasher {
15 public string Name {get;}
16 public Action Action {get; }
18 public Action<object> Validator {get; }
20 public Crasher (string name, Action action, Action<object> validator = null)
22 Name = name;
23 Action = action;
24 Validator = validator;
28 public class ValidationException : Exception {
29 public ValidationException () : base () {}
30 public ValidationException (string msg) : base (msg) {}
31 public ValidationException (string msg, Exception inner) : base (msg, inner) {}
34 public static List<Crasher> Crashers;
35 public static int StresserIndex;
37 static CrasherClass ()
39 Crashers = new List<Crasher> ();
41 // Basic functionality
42 Crashers.Add(new Crasher ("MerpCrashManaged", MerpCrashManaged));
43 // Run this test for stress tests
45 // I've ran a burn-in with all of them of
46 // 1,000 - 10,000 runs already.
48 // Feel free to change by moving this line.
49 StresserIndex = Crashers.Count - 1;
51 Crashers.Add(new Crasher ("MerpCrashMalloc", MerpCrashMalloc));
52 Crashers.Add(new Crasher ("MerpCrashFailFast", MerpCrashFailFast, ValidateFailFastMsg));
54 Crashers.Add(new Crasher ("MerpCrashNullFp", MerpCrashNullFp));
55 Crashers.Add(new Crasher ("MerpCrashExceptionHook", MerpCrashUnhandledExceptionHook));
57 // Specific Edge Cases
58 Crashers.Add(new Crasher ("MerpCrashDladdr", MerpCrashDladdr));
59 Crashers.Add(new Crasher ("MerpCrashSnprintf", MerpCrashSnprintf));
60 Crashers.Add(new Crasher ("MerpCrashDomainUnload", MerpCrashDomainUnload));
61 Crashers.Add(new Crasher ("MerpCrashUnbalancedGCSafe", MerpCrashUnbalancedGCSafe));
62 Crashers.Add(new Crasher ("MerpCrashSignalTerm", MerpCrashSignalTerm));
63 Crashers.Add(new Crasher ("MerpCrashSignalTerm", MerpCrashSignalAbrt));
64 Crashers.Add(new Crasher ("MerpCrashSignalKill", MerpCrashSignalFpe));
65 Crashers.Add(new Crasher ("MerpCrashSignalKill", MerpCrashSignalBus));
66 Crashers.Add(new Crasher ("MerpCrashSignalSegv", MerpCrashSignalSegv));
67 Crashers.Add(new Crasher ("MerpCrashSignalIll", MerpCrashSignalIll));
70 public static void
71 MerpCrashManaged ()
73 unsafe { Console.WriteLine("{0}", *(int*) -1); }
76 const string failfastMsg = "abcd efgh";
78 public static void
79 MerpCrashFailFast ()
81 Environment.FailFast (failfastMsg);
84 public static void ValidateFailFastMsg (object json)
86 string s = jsonGetKeys (json, "payload", "failfast_message") as string;
87 if (s != failfastMsg)
88 throw new ValidationException (String.Format ("incorrect fail fast message (expected: {0}, got: {1})", failfastMsg, s));
91 [DllImport("libtest")]
92 public static extern void mono_test_MerpCrashSnprintf ();
94 // This test tries to test the writer's reentrancy
95 public static void
96 MerpCrashSnprintf ()
98 mono_test_MerpCrashSnprintf ();
101 [DllImport("libtest")]
102 public static extern void mono_test_MerpCrashDladdr ();
104 public static void
105 MerpCrashDladdr ()
107 mono_test_MerpCrashDladdr ();
110 [DllImport("libtest")]
111 public static extern void mono_test_MerpCrashMalloc ();
113 public static void
114 MerpCrashMalloc ()
116 mono_test_MerpCrashMalloc ();
119 [DllImport("libtest")]
120 public static extern void mono_test_MerpCrashLoaderLock ();
122 public static void
123 MerpCrashLoaderLock ()
125 mono_test_MerpCrashLoaderLock ();
128 [DllImport("libtest")]
129 public static extern void mono_test_MerpCrashDomainUnload ();
131 public static void
132 MerpCrashDomainUnload ()
134 mono_test_MerpCrashDomainUnload ();
137 [DllImport("libtest")]
138 public static extern void mono_test_MerpCrashUnbalancedGCSafe ();
140 public static void
141 MerpCrashUnbalancedGCSafe ()
143 mono_test_MerpCrashUnbalancedGCSafe ();
146 [DllImport("libtest")]
147 public static extern void mono_test_MerpCrashNullFp ();
149 public static void
150 MerpCrashNullFp ()
152 mono_test_MerpCrashNullFp ();
155 [DllImport("libtest")]
156 public static extern void mono_test_MerpCrashUnhandledExceptionHook ();
158 [DllImport("libtest")]
159 public static extern void mono_test_MerpCrashSignalTerm ();
161 public static void
162 MerpCrashSignalTerm ()
164 mono_test_MerpCrashSignalTerm ();
167 [DllImport("libtest")]
168 public static extern void mono_test_MerpCrashSignalAbrt ();
170 public static void
171 MerpCrashSignalAbrt ()
173 mono_test_MerpCrashSignalAbrt ();
176 [DllImport("libtest")]
177 public static extern void mono_test_MerpCrashSignalFpe ();
179 public static void
180 MerpCrashSignalFpe ()
182 mono_test_MerpCrashSignalFpe ();
185 [DllImport("libtest")]
186 public static extern void mono_test_MerpCrashSignalBus ();
188 public static void
189 MerpCrashSignalBus ()
191 mono_test_MerpCrashSignalBus ();
194 [DllImport("libtest")]
195 public static extern void mono_test_MerpCrashSignalSegv ();
197 public static void
198 MerpCrashSignalSegv ()
200 mono_test_MerpCrashSignalSegv ();
203 [DllImport("libtest")]
204 public static extern void mono_test_MerpCrashSignalIll ();
206 public static void
207 MerpCrashSignalIll ()
209 mono_test_MerpCrashSignalIll ();
212 public static void
213 MerpCrashUnhandledExceptionHook ()
215 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(HandleException);
216 throw new Exception ("This is Unhandled");
219 public static void HandleException (object sender, UnhandledExceptionEventArgs e)
221 Console.WriteLine ("And now to crash inside the hook");
222 mono_test_MerpCrashUnhandledExceptionHook ();
226 private static object jsonGetKey (object o, string key) => (o as Dictionary<string,object>)[key];
227 private static object jsonGetKeys (object o, params string[] keys) {
228 try {
229 foreach (var key in keys) {
230 o = jsonGetKey (o, key);
232 return o;
233 } catch (KeyNotFoundException e) {
234 throw new ValidationException (String.Format ("{0}, key not found, looking for key path [{1}]", e.ToString(), String.Join (", ", keys)));
240 static string configDir = "./merp-crash-test/";
242 public static void
243 CrashWithMerp (int testNum)
245 SetupCrash (configDir);
246 CrasherClass.Crashers [Convert.ToInt32 (testNum)].Action ();
249 public static string env = Environment.GetEnvironmentVariable ("MONO_PATH");
250 public static string this_assembly_path = Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location);
252 public static void
253 SetupCrash (string configDir)
255 var monoType = Type.GetType ("Mono.Runtime", false);
256 var m = monoType.GetMethod("EnableMicrosoftTelemetry", BindingFlags.NonPublic | BindingFlags.Static);
258 // This leads to open -a /bin/cat, which errors out, but errors
259 // in invoking merp are only logged errors, not fatal assertions.
260 var merpGUIPath = "/bin/cat";
261 var appBundleId = "com.xam.Minimal";
262 var appSignature = "Test.Xam.Minimal";
263 var appVersion = "123456";
264 var eventType = "AppleAppCrash";
265 var appPath = "/where/mono/lives";
266 var m_params = new object[] { appBundleId, appSignature, appVersion, merpGUIPath, eventType, appPath, configDir };
268 m.Invoke(null, m_params);
270 DumpLogSet ();
273 public static void
274 TestValidate (string configDir, bool silent, Action<object> validator = null)
276 DumpLogCheck (expected_level: "MerpInvoke"); // we are expecting merp invoke to fail
278 var xmlFilePath = String.Format("{0}CustomLogsMetadata.xml", configDir);
279 var paramsFilePath = String.Format("{0}MERP.uploadparams.txt", configDir);
280 var crashFilePath = String.Format("{0}lastcrashlog.txt", configDir);
282 // Fixme: Maybe parse these json files rather than
283 // just checking they exist
284 var xmlFileExists = File.Exists (xmlFilePath);
285 var paramsFileExists = File.Exists (paramsFilePath);
286 var crashFileExists = File.Exists (crashFilePath);
288 if (xmlFileExists) {
289 var text = File.ReadAllText (xmlFilePath);
290 if (!silent)
291 Console.WriteLine ("Xml file {0}", text);
292 File.Delete (xmlFilePath);
293 } else {
294 Console.WriteLine ("Xml file {0} missing", xmlFilePath);
297 if (paramsFileExists) {
298 var text = File.ReadAllText (paramsFilePath);
299 if (!silent)
300 Console.WriteLine ("Params file {0}", text);
301 File.Delete (paramsFilePath);
302 } else {
303 Console.WriteLine ("Params file {0} missing", paramsFilePath);
306 if (crashFileExists) {
307 var crashFile = File.ReadAllText (crashFilePath);
308 File.Delete (crashFilePath);
310 var checker = new JavaScriptSerializer ();
312 // Throws if invalid json
313 if (!silent)
314 Console.WriteLine("Validating: {0}", crashFile);
315 try {
316 var obj = checker.DeserializeObject (crashFile);
317 if (validator is object)
318 validator (obj);
319 } catch (CrasherClass.ValidationException e) {
320 throw new Exception (String.Format ("Validation failed '{0}', json: {1}", e.Message, crashFile));
321 } catch (Exception e) {
322 throw new Exception (String.Format ("Invalid json: {0}", crashFile));
325 File.Delete (crashFilePath);
326 // Assert it has the required merp fields
327 } else {
328 Console.WriteLine ("Crash file {0} missing", crashFilePath);
331 if (!xmlFileExists)
332 throw new Exception (String.Format ("Did not produce {0}", xmlFilePath));
334 if (!paramsFileExists)
335 throw new Exception (String.Format ("Did not produce {0}", paramsFilePath));
337 if (!crashFileExists)
338 throw new Exception (String.Format ("Did not produce {0}", crashFilePath));
341 public static void
342 Cleanup (string configDir)
344 Directory.Delete (configDir, true);
347 static void DumpLogSet ()
349 var monoType = Type.GetType ("Mono.Runtime", false);
350 var convert = monoType.GetMethod("EnableCrashReportLog", BindingFlags.NonPublic | BindingFlags.Static);
351 convert.Invoke(null, new object[] { "./" });
354 static void DumpLogUnset ()
356 var monoType = Type.GetType ("Mono.Runtime", false);
357 var convert = monoType.GetMethod("EnableCrashReportLog", BindingFlags.NonPublic | BindingFlags.Static);
358 convert.Invoke(null, new object[] { null });
361 static void DumpLogCheck (string expected_level = "Done")
363 var monoType = Type.GetType ("Mono.Runtime", false);
364 var convert = monoType.GetMethod("CheckCrashReportLog", BindingFlags.NonPublic | BindingFlags.Static);
365 var result = (int) convert.Invoke(null, new object[] { "./", true });
366 // Value of enum
367 string [] levels = new string [] { "None", "Setup", "SuspendHandshake", "UnmanagedStacks", "ManagedStacks", "StateWriter", "StateWriterDone", "MerpWriter", "MerpInvoke", "Cleanup", "Done", "DoubleFault" };
369 if (expected_level != levels [result])
370 throw new Exception (String.Format ("Crash level {0} does not match expected {1}", levels [result], expected_level));
374 public static void
375 SpawnCrashingRuntime (string runtime, int testNum, bool silent)
377 var asm = "merp-crash-test.exe";
378 var pi = new Diag.ProcessStartInfo ();
379 pi.UseShellExecute = false;
380 pi.FileName = runtime;
381 pi.Arguments = String.Format ("{0} {1}", asm, testNum);;
382 pi.Environment ["MONO_PATH"] = env;
384 if (!silent) {
385 Console.WriteLine ("Running {0}", CrasherClass.Crashers [testNum].Name);
386 Console.WriteLine ("MONO_PATH={0} {1} {2} {3}", env, runtime, asm, testNum);
389 if (Directory.Exists (configDir)) {
390 Console.WriteLine ("Cleaning up left over configDir {0}", configDir);
391 Cleanup (configDir);
394 Directory.CreateDirectory (configDir);
396 try {
397 var process = Diag.Process.Start (pi);
398 process.WaitForExit ();
400 TestValidate (configDir, silent, CrasherClass.Crashers [testNum].Validator);
401 } finally {
402 Cleanup (configDir);
406 public static void TestManagedException ()
408 if (Directory.Exists (configDir)) {
409 Console.WriteLine ("Cleaning up left over configDir {0}", configDir);
410 Cleanup (configDir);
412 Directory.CreateDirectory (configDir);
414 SetupCrash (configDir);
415 var monoType = Type.GetType ("Mono.Runtime", false);
416 var m = monoType.GetMethod ("ExceptionToState", BindingFlags.NonPublic | BindingFlags.Static);
417 var exception = new Exception ("test managed exception");
418 var m_params = new object[] { exception };
420 var result = m.Invoke (null, m_params) as Tuple<String, ulong, ulong>;
421 DumpLogCheck (expected_level: "StateWriterDone");
422 Cleanup (configDir);
425 public static Exception RunManagedExceptionTest ()
427 Console.WriteLine ("Testing ExceptionToState()...");
428 Exception exception_test_failure = null;
430 try {
431 TestManagedException();
433 catch (Exception e)
435 return e;
437 return null;
440 public static int Main (string [] args)
442 if (args.Length == 0) {
443 string processExe = Diag.Process.GetCurrentProcess ().MainModule.FileName;
444 if (processExe == null)
445 throw new ArgumentException ("Couldn't get name of running file");
446 else if (string.IsNullOrEmpty (processExe))
447 throw new ArgumentException ("Couldn't find mono runtime.");
448 else if (!Path.GetFileName (processExe).StartsWith ("mono"))
449 throw new ArgumentException (String.Format("Running native app {0} isn't 'mono'"));
451 var failures = new Exception [CrasherClass.Crashers.Count];
452 int failure_count = 0;
453 for (int i=0; i < CrasherClass.Crashers.Count; i++) {
454 try {
455 SpawnCrashingRuntime (processExe, i, false);
456 } catch (Exception e) {
457 failures [i] = e;
458 if (e.InnerException != null)
459 failures [i] = e.InnerException;
460 failure_count++;
464 // Also test sending a managed exception
465 Exception exception_test_failure = RunManagedExceptionTest ();
467 Console.WriteLine ("\n\n##################");
468 Console.WriteLine ("Merp Test Results:");
469 Console.WriteLine ("##################\n\n");
471 if (exception_test_failure != null)
473 Console.WriteLine ("Sending managed exception to MERP failed: {0}\n{1}\n", exception_test_failure.Message, exception_test_failure.StackTrace);
476 if (failure_count > 0) {
477 for (int i=0; i < CrasherClass.Crashers.Count; i++) {
478 if (failures [i] != null) {
479 Console.WriteLine ("Crash reporter failed test {0}", CrasherClass.Crashers [i].Name);
480 Console.WriteLine ("Cause: {0}\n{1}\n", failures [i].Message, failures [i].StackTrace);
485 if (failure_count > 0 || exception_test_failure != null)
486 return 1;
488 Console.WriteLine ("\n\n##################");
489 Console.WriteLine ("Merp Stress Test:");
490 Console.WriteLine ("##################\n\n");
492 Console.WriteLine ("Starting crash stress test\n");
493 int iter = 0;
494 for (iter=0; iter < 20; iter++) {
495 Console.WriteLine ("\n#############################################");
496 Console.WriteLine ("\tMerp Stress Test Iteration {0}", iter);
497 Console.WriteLine ("#############################################\n");
498 try {
499 SpawnCrashingRuntime (processExe, CrasherClass.StresserIndex, true);
500 } catch (Exception e) {
501 Console.WriteLine ("Stress test caught failure. Shutting down after {1} iterations.\n {0} \n\n", e.InnerException, iter);
502 throw;
505 Console.WriteLine ("Ending crash stress test. No failures caught.\n");
507 return 0;
508 } else {
509 CrashWithMerp (Convert.ToInt32 (args [0]));
510 return 0;