Skip to content

Commit 4b61d6e

Browse files
Catch unhandled exceptions from other threads (#2771)
Co-authored-by: codefactor-io <[email protected]>
1 parent 34d2377 commit 4b61d6e

File tree

1 file changed

+46
-6
lines changed

1 file changed

+46
-6
lines changed

ImperatorToCK3/Program.cs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
using commonItems;
1+
using commonItems;
22
using ImperatorToCK3.Exceptions;
33
using log4net.Core;
44
using System;
55
using System.Globalization;
66
using System.Linq;
7+
using System.Threading.Tasks;
78

89
namespace ImperatorToCK3;
910
public static class Program {
1011
public static int Main(string[] args) {
12+
RegisterGlobalExceptionHandlers();
13+
1114
try {
12-
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
13-
CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
14-
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
15-
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;
15+
SetInvariantCulture();
1616

1717
var converterVersion = new ConverterVersion();
1818
converterVersion.LoadVersion("configurables/version.txt");
@@ -28,7 +28,7 @@ public static int Main(string[] args) {
2828
if (ex is AggregateException aggregateEx) {
2929
ex = aggregateEx.Flatten().InnerExceptions.FirstOrDefault() ?? ex;
3030
}
31-
31+
3232
Logger.Log(Level.Fatal, ex is UserErrorException ? ex.Message : $"{ex.GetType()}: {ex.Message}");
3333
if (ex.StackTrace is not null) {
3434
Logger.Debug(ex.StackTrace);
@@ -41,4 +41,44 @@ public static int Main(string[] args) {
4141
return -1;
4242
}
4343
}
44+
45+
private static void RegisterGlobalExceptionHandlers() {
46+
// Catch any unhandled exceptions from other threads.
47+
AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) => {
48+
if (eventArgs.ExceptionObject is Exception ex) {
49+
// If the exception is an AggregateException, we want the original inner exception's stack trace.
50+
if (ex is AggregateException aggregateEx) {
51+
ex = aggregateEx.Flatten().InnerExceptions.FirstOrDefault() ?? ex;
52+
}
53+
54+
Logger.Log(Level.Fatal, ex is UserErrorException ? ex.Message : $"{ex.GetType()}: {ex.Message}");
55+
if (ex.StackTrace is not null) {
56+
Logger.Debug(ex.StackTrace);
57+
}
58+
} else {
59+
Logger.Log(Level.Fatal, "An unhandled exception occurred, but it could not be identified.");
60+
}
61+
Environment.Exit(-1); // Ensure the process exits with a non-zero code.
62+
};
63+
TaskScheduler.UnobservedTaskException += (sender, eventArgs) => {
64+
Exception ex = eventArgs.Exception;
65+
// If the exception is an AggregateException, we want the original inner exception's stack trace.
66+
if (ex is AggregateException aggregateEx) {
67+
ex = aggregateEx.Flatten().InnerExceptions.FirstOrDefault() ?? ex;
68+
}
69+
70+
Logger.Log(Level.Fatal, ex is UserErrorException ? ex.Message : $"{ex.GetType()}: {ex.Message}");
71+
if (ex.StackTrace is not null) {
72+
Logger.Debug(ex.StackTrace);
73+
}
74+
Environment.Exit(-1); // Ensure the process exits with a non-zero code.
75+
};
76+
}
77+
78+
private static void SetInvariantCulture() {
79+
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
80+
CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
81+
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
82+
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;
83+
}
4484
}

0 commit comments

Comments
 (0)