Make crash with non-converted Kotlin exception debugger-friendly (#2353)
* Use `abort` instead of `exit` to make debugger recognize it as crash * Terminate from C++ to prevent debugger from showing Kotlin handlers #KT-28066 Fixed
This commit is contained in:
committed by
GitHub
parent
f4cf5e842d
commit
6fe37a00c5
@@ -190,12 +190,17 @@ void ThrowException(KRef exception) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void ReportUnhandledException(KRef e);
|
||||
|
||||
RUNTIME_NORETURN void TerminateWithUnhandledException(KRef e) {
|
||||
ReportUnhandledException(e);
|
||||
konan::abort();
|
||||
}
|
||||
|
||||
// Some libstdc++-based targets has limited support for std::current_exception and other C++11 functions.
|
||||
// This restriction can be lifted later when toolchains will be updated.
|
||||
#if KONAN_HAS_CXX11_EXCEPTION_FUNCTIONS
|
||||
|
||||
void ReportUnhandledException(KRef e);
|
||||
|
||||
static void (*oldTerminateHandler)() = nullptr;
|
||||
|
||||
static void KonanTerminateHandler() {
|
||||
@@ -208,8 +213,7 @@ static void KonanTerminateHandler() {
|
||||
try {
|
||||
std::rethrow_exception(currentException);
|
||||
} catch (ObjHolder& e) {
|
||||
ReportUnhandledException(e.obj());
|
||||
konan::abort();
|
||||
TerminateWithUnhandledException(e.obj());
|
||||
} catch (...) {
|
||||
// Not a Kotlin exception.
|
||||
oldTerminateHandler();
|
||||
|
||||
@@ -31,6 +31,8 @@ OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace);
|
||||
// Throws arbitrary exception.
|
||||
void ThrowException(KRef exception);
|
||||
|
||||
RUNTIME_NORETURN void TerminateWithUnhandledException(KRef exception);
|
||||
|
||||
void SetKonanTerminateHandler();
|
||||
|
||||
// The functions below are implemented in Kotlin (at package kotlin.native.internal).
|
||||
|
||||
@@ -22,17 +22,41 @@
|
||||
|
||||
#import "Exceptions.h"
|
||||
#import "ObjCExport.h"
|
||||
#import "Porting.h"
|
||||
#import "Runtime.h"
|
||||
#import "Utils.h"
|
||||
|
||||
extern "C" OBJ_GETTER(Kotlin_Throwable_getMessage, KRef throwable);
|
||||
extern "C" OBJ_GETTER(Kotlin_ObjCExport_getWrappedError, KRef throwable);
|
||||
extern "C" void Kotlin_ObjCExport_abortIfUnchecked(KRef exception);
|
||||
extern "C" KBoolean Kotlin_ObjCExport_isUnchecked(KRef exception);
|
||||
|
||||
static void printlnMessage(const char* message) {
|
||||
konan::consolePrintf("%s\n", message);
|
||||
}
|
||||
|
||||
static const char* uncheckedExceptionMessage =
|
||||
"Instances of kotlin.Error, kotlin.RuntimeException and subclasses "
|
||||
"aren't propagated from Kotlin to Objective-C/Swift.";
|
||||
|
||||
extern "C" RUNTIME_NORETURN void Kotlin_ObjCExport_trapOnUndeclaredException(KRef exception) {
|
||||
if (Kotlin_ObjCExport_isUnchecked(exception)) {
|
||||
printlnMessage(uncheckedExceptionMessage);
|
||||
printlnMessage("Other exceptions can be propagated as NSError if method has or inherits @Throws annotation.");
|
||||
} else {
|
||||
printlnMessage("Exceptions are propagated from Kotlin to Objective-C/Swift as NSError "
|
||||
"only if method has or inherits @Throws annotation");
|
||||
}
|
||||
|
||||
TerminateWithUnhandledException(exception);
|
||||
}
|
||||
|
||||
static char kotlinExceptionOriginChar;
|
||||
|
||||
extern "C" void Kotlin_ObjCExport_RethrowExceptionAsNSError(KRef exception, id* outError) {
|
||||
Kotlin_ObjCExport_abortIfUnchecked(exception);
|
||||
if (Kotlin_ObjCExport_isUnchecked(exception)) {
|
||||
printlnMessage(uncheckedExceptionMessage);
|
||||
TerminateWithUnhandledException(exception);
|
||||
}
|
||||
|
||||
if (outError == nullptr) {
|
||||
return;
|
||||
|
||||
@@ -281,35 +281,13 @@ class ObjCErrorException(
|
||||
override fun toString(): String = "NSError-based exception: $message"
|
||||
}
|
||||
|
||||
private val uncheckedExceptionMessage: String
|
||||
get() = "Instances of kotlin.Error, kotlin.RuntimeException and subclasses " +
|
||||
"aren't propagated from Kotlin to Objective-C/Swift."
|
||||
|
||||
private fun Throwable.isUncheckedException(): Boolean = this is kotlin.Error || this is kotlin.RuntimeException
|
||||
|
||||
@ExportForCppRuntime
|
||||
private fun Kotlin_ObjCExport_abortIfUnchecked(exception: Throwable) {
|
||||
if (exception.isUncheckedException()) {
|
||||
println(uncheckedExceptionMessage)
|
||||
ReportUnhandledException(exception)
|
||||
kotlin.system.exitProcess(1)
|
||||
}
|
||||
}
|
||||
private fun Kotlin_ObjCExport_isUnchecked(exception: Throwable): Boolean =
|
||||
exception is kotlin.Error || exception is kotlin.RuntimeException
|
||||
|
||||
@ExportForCompiler
|
||||
private fun trapOnUndeclaredException(exception: Throwable) {
|
||||
if (exception.isUncheckedException()) {
|
||||
println(uncheckedExceptionMessage)
|
||||
println("Other exceptions can be propagated as NSError if method has or inherits @Throws annotation.")
|
||||
} else {
|
||||
println("Exceptions are propagated from Kotlin to Objective-C/Swift as NSError " +
|
||||
"only if method has or inherits @Throws annotation")
|
||||
}
|
||||
|
||||
ReportUnhandledException(exception)
|
||||
kotlin.system.exitProcess(1)
|
||||
|
||||
}
|
||||
@PublishedApi
|
||||
@SymbolName("Kotlin_ObjCExport_trapOnUndeclaredException")
|
||||
internal external fun trapOnUndeclaredException(exception: Throwable)
|
||||
|
||||
@ExportForCppRuntime
|
||||
private fun Kotlin_Throwable_getMessage(throwable: Throwable): String? = throwable.message
|
||||
|
||||
Reference in New Issue
Block a user