Add uncaught exception handler when Objective-C interop is enabled

UIApplicationMain doesn't forward exceptions to the caller,
so catching them in Kotlin main doesn't have any effect.
This commit is contained in:
Svyatoslav Scherbina
2017-09-05 11:19:28 +03:00
committed by SvyatoslavScherbina
parent 4e285a5ef4
commit 62755590a5
4 changed files with 57 additions and 0 deletions
+47
View File
@@ -18,6 +18,8 @@
#include <string.h>
#include <stdint.h>
#include <exception>
#if KONAN_NO_EXCEPTIONS
#define OMIT_BACKTRACE 1
#endif
@@ -38,6 +40,7 @@
#include "Natives.h"
#include "KString.h"
#include "Types.h"
#include "Utils.h"
namespace {
@@ -175,6 +178,50 @@ void ThrowException(KRef exception) {
#endif
}
#if KONAN_OBJC_INTEROP
void ReportUnhandledException(KRef e);
static void (*oldTerminateHandler)() = nullptr;
static void KonanTerminateHandler() {
auto currentException = std::current_exception();
if (!currentException) {
// No current exception.
oldTerminateHandler();
} else {
try {
std::rethrow_exception(currentException);
} catch (ObjHolder& e) {
ReportUnhandledException(e.obj());
konan::abort();
} catch (...) {
// Not a Kotlin exception.
oldTerminateHandler();
}
}
}
static SimpleMutex konanTerminateHandlerInitializationMutex;
void SetKonanTerminateHandler() {
if (oldTerminateHandler != nullptr) return; // Already initialized.
LockGuard<SimpleMutex> lockGuard(konanTerminateHandlerInitializationMutex);
if (oldTerminateHandler != nullptr) return; // Already initialized.
oldTerminateHandler = std::get_terminate(); // If termination happens between `set_terminate` and assignment.
oldTerminateHandler = std::set_terminate(&KonanTerminateHandler);
}
#else // KONAN_OBJC_INTEROP
void SetKonanTerminateHandler() {
// Nothing to do.
}
#endif // KONAN_OBJC_INTEROP
#ifdef __cplusplus
} // extern "C"
+2
View File
@@ -29,6 +29,8 @@ OBJ_GETTER0(GetCurrentStackTrace);
// Throws arbitrary exception.
void ThrowException(KRef exception);
void SetKonanTerminateHandler();
// The functions below are implemented in Kotlin (at package konan.internal).
// Throws null pointer exception. Context is evaluated from caller's address.
+2
View File
@@ -17,6 +17,7 @@
#include <stdio.h>
#include "Alloc.h"
#include "Exceptions.h"
#include "Memory.h"
#include "Porting.h"
#include "Runtime.h"
@@ -60,6 +61,7 @@ void AppendToInitializersTail(InitNode *next) {
// TODO: properly use RuntimeState.
RuntimeState* InitRuntime() {
SetKonanTerminateHandler();
RuntimeState* result = konanConstructInstance<RuntimeState>();
result->memoryState = InitMemory();
// Keep global variables in state as well.
@@ -66,6 +66,12 @@ fun PrintThrowable(throwable: Throwable) {
println(throwable)
}
@ExportForCppRuntime
fun ReportUnhandledException(e: Throwable) {
print("Uncaught Kotlin exception: ")
e.printStackTrace()
}
@ExportForCppRuntime
internal fun TheEmptyString() = ""