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
|
#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.
|
// 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.
|
// This restriction can be lifted later when toolchains will be updated.
|
||||||
#if KONAN_HAS_CXX11_EXCEPTION_FUNCTIONS
|
#if KONAN_HAS_CXX11_EXCEPTION_FUNCTIONS
|
||||||
|
|
||||||
void ReportUnhandledException(KRef e);
|
|
||||||
|
|
||||||
static void (*oldTerminateHandler)() = nullptr;
|
static void (*oldTerminateHandler)() = nullptr;
|
||||||
|
|
||||||
static void KonanTerminateHandler() {
|
static void KonanTerminateHandler() {
|
||||||
@@ -208,8 +213,7 @@ static void KonanTerminateHandler() {
|
|||||||
try {
|
try {
|
||||||
std::rethrow_exception(currentException);
|
std::rethrow_exception(currentException);
|
||||||
} catch (ObjHolder& e) {
|
} catch (ObjHolder& e) {
|
||||||
ReportUnhandledException(e.obj());
|
TerminateWithUnhandledException(e.obj());
|
||||||
konan::abort();
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// Not a Kotlin exception.
|
// Not a Kotlin exception.
|
||||||
oldTerminateHandler();
|
oldTerminateHandler();
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace);
|
|||||||
// Throws arbitrary exception.
|
// Throws arbitrary exception.
|
||||||
void ThrowException(KRef exception);
|
void ThrowException(KRef exception);
|
||||||
|
|
||||||
|
RUNTIME_NORETURN void TerminateWithUnhandledException(KRef exception);
|
||||||
|
|
||||||
void SetKonanTerminateHandler();
|
void SetKonanTerminateHandler();
|
||||||
|
|
||||||
// The functions below are implemented in Kotlin (at package kotlin.native.internal).
|
// The functions below are implemented in Kotlin (at package kotlin.native.internal).
|
||||||
|
|||||||
@@ -22,17 +22,41 @@
|
|||||||
|
|
||||||
#import "Exceptions.h"
|
#import "Exceptions.h"
|
||||||
#import "ObjCExport.h"
|
#import "ObjCExport.h"
|
||||||
|
#import "Porting.h"
|
||||||
#import "Runtime.h"
|
#import "Runtime.h"
|
||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
|
|
||||||
extern "C" OBJ_GETTER(Kotlin_Throwable_getMessage, KRef throwable);
|
extern "C" OBJ_GETTER(Kotlin_Throwable_getMessage, KRef throwable);
|
||||||
extern "C" OBJ_GETTER(Kotlin_ObjCExport_getWrappedError, 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;
|
static char kotlinExceptionOriginChar;
|
||||||
|
|
||||||
extern "C" void Kotlin_ObjCExport_RethrowExceptionAsNSError(KRef exception, id* outError) {
|
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) {
|
if (outError == nullptr) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -281,35 +281,13 @@ class ObjCErrorException(
|
|||||||
override fun toString(): String = "NSError-based exception: $message"
|
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
|
@ExportForCppRuntime
|
||||||
private fun Kotlin_ObjCExport_abortIfUnchecked(exception: Throwable) {
|
private fun Kotlin_ObjCExport_isUnchecked(exception: Throwable): Boolean =
|
||||||
if (exception.isUncheckedException()) {
|
exception is kotlin.Error || exception is kotlin.RuntimeException
|
||||||
println(uncheckedExceptionMessage)
|
|
||||||
ReportUnhandledException(exception)
|
|
||||||
kotlin.system.exitProcess(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExportForCompiler
|
@PublishedApi
|
||||||
private fun trapOnUndeclaredException(exception: Throwable) {
|
@SymbolName("Kotlin_ObjCExport_trapOnUndeclaredException")
|
||||||
if (exception.isUncheckedException()) {
|
internal external fun trapOnUndeclaredException(exception: Throwable)
|
||||||
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)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExportForCppRuntime
|
@ExportForCppRuntime
|
||||||
private fun Kotlin_Throwable_getMessage(throwable: Throwable): String? = throwable.message
|
private fun Kotlin_Throwable_getMessage(throwable: Throwable): String? = throwable.message
|
||||||
|
|||||||
Reference in New Issue
Block a user