Skip to content

Commit 801956e

Browse files
committed
[GR-68497] Introduce UncaughtExceptionHandler for Native Image
PullRequest: graal/21771
2 parents e37732c + c43b72b commit 801956e

File tree

2 files changed

+30
-10
lines changed

2 files changed

+30
-10
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import java.util.ListIterator;
4747
import java.util.Locale;
4848
import java.util.Map;
49+
import java.util.Optional;
4950
import java.util.ServiceLoader;
5051
import java.util.Set;
5152
import java.util.concurrent.atomic.AtomicBoolean;
@@ -167,6 +168,7 @@
167168
import com.oracle.svm.core.option.RuntimeOptionValues;
168169
import com.oracle.svm.core.option.SubstrateOptionsParser;
169170
import com.oracle.svm.core.snippets.SnippetRuntime;
171+
import com.oracle.svm.core.util.ExitStatus;
170172
import com.oracle.svm.core.util.InterruptImageBuilding;
171173
import com.oracle.svm.core.util.LayeredHostedImageHeapMapCollector;
172174
import com.oracle.svm.core.util.LayeredImageHeapMapStore;
@@ -568,7 +570,7 @@ protected void doRun(Map<Method, CEntryPointData> entryPoints, JavaMainSupport j
568570

569571
try (DebugContext debug = new Builder(options, new GraalDebugHandlersFactory(GraalAccess.getOriginalSnippetReflection())).build();
570572
DebugCloseable featureCleanup = () -> featureHandler.forEachFeature(Feature::cleanup)) {
571-
setupNativeImage(options, entryPoints, javaMainSupport, harnessSubstitutions, debug);
573+
setupNativeImage(options, entryPoints, javaMainSupport, imageName, harnessSubstitutions, debug);
572574

573575
boolean returnAfterAnalysis = runPointsToAnalysis(imageName, options, debug);
574576
if (returnAfterAnalysis) {
@@ -923,9 +925,10 @@ protected boolean verifyAssignableTypes() {
923925

924926
@SuppressWarnings("try")
925927
protected void setupNativeImage(OptionValues options, Map<Method, CEntryPointData> entryPoints, JavaMainSupport javaMainSupport,
926-
SubstitutionProcessor harnessSubstitutions, DebugContext debug) {
928+
String imageName, SubstitutionProcessor harnessSubstitutions, DebugContext debug) {
927929
try (Indent ignored = debug.logAndIndent("setup native-image builder")) {
928930
try (StopTimer ignored1 = TimerCollection.createTimerAndStart(TimerCollection.Registry.SETUP)) {
931+
installDefaultExceptionHandler(options, imageName);
929932
SubstrateTargetDescription target = createTarget();
930933
ImageSingletons.add(Platform.class, loader.platform);
931934
ImageSingletons.add(SubstrateTargetDescription.class, target);
@@ -1121,6 +1124,30 @@ protected void setupNativeImage(OptionValues options, Map<Method, CEntryPointDat
11211124
}
11221125
}
11231126

1127+
/**
1128+
* We install a default uncaught exception handler to make sure that the image build terminates
1129+
* if an uncaught exception is encountered on <b>any</b> thread. As an unexpectedly failing
1130+
* thread could theoretically cause a deadlock if another thread was waiting for its result, we
1131+
* preventively terminate the build via {@link System#exit}.
1132+
*/
1133+
private void installDefaultExceptionHandler(OptionValues options, String imageName) {
1134+
/*
1135+
* A flag to make sure we run the reporting only once even if multiple uncaught exceptions
1136+
* are encountered.
1137+
*/
1138+
var reportStarted = new AtomicBoolean();
1139+
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
1140+
if (reportStarted.compareAndSet(false, true)) {
1141+
/*
1142+
* Call into the ProgressReporter to provide error reporting as if the throwable was
1143+
* thrown on the main thread.
1144+
*/
1145+
reporter.printEpilog(Optional.of(imageName), Optional.of(NativeImageGenerator.this), loader, NativeImageGeneratorRunner.BuildOutcome.FAILED, Optional.of(throwable), options);
1146+
System.exit(ExitStatus.BUILDER_ERROR.getValue());
1147+
}
1148+
});
1149+
}
1150+
11241151
protected void registerEntryPointStubs(Map<Method, CEntryPointData> entryPoints) {
11251152
entryPoints.forEach((method, entryPointData) -> CEntryPointCallStubSupport.singleton().registerStubForMethod(method, () -> entryPointData));
11261153
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/VMErrorReporter.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,7 @@ private static void reportStackTrace(PrintWriter pw, Throwable t) {
6666
pw.println("## Stack Trace");
6767
pw.println();
6868
pw.println("```java");
69-
Throwable current = t;
70-
while (current != null) {
71-
t.printStackTrace(pw);
72-
current = current.getCause();
73-
if (current != null) {
74-
pw.println("Caused by:");
75-
}
76-
}
69+
t.printStackTrace(pw);
7770
pw.println("```");
7871
}
7972

0 commit comments

Comments
 (0)