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:
committed by
SvyatoslavScherbina
parent
4e285a5ef4
commit
62755590a5
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() = ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user