[K/N][Interop] Fix throwing exceptions through bridges in opt mode
By default, C functions compiled to bitcode by clang have the nounwind attribute. If such functions throws an exception, the behaviour is undefined. Our interop machinery can process foreign exceptions on call sites (terminate or wrap them in Kotlin exceptions). But if the interop bridges have the nounwind attribute, LLVM optimizations (particularly inlining) may lead to the situation when a foreign exception is ignored by our foreign exception handler. This patch fixes the issue by compiling bridges with -fexceptions flag. This flag makes clang to not set the nounwind attribute, so exceptions can be thrown through C frames.
This commit is contained in:
+2
@@ -483,6 +483,8 @@ internal fun buildNativeLibrary(
|
||||
//
|
||||
// Note that PCH and the *.c file should be compiled with the same optimization level.
|
||||
add("-O2")
|
||||
// Allow throwing exceptions through generated stubs.
|
||||
add("-fexceptions")
|
||||
addAll(additionalCompilerOpts)
|
||||
addAll(getCompilerFlagsForVfsOverlay(arguments.headerFilterPrefix.toTypedArray(), def))
|
||||
addAll(when (language) {
|
||||
|
||||
+3
-2
@@ -40,8 +40,9 @@ class CStubsManager(private val target: KonanTarget) {
|
||||
val cSourcePath = cSource.absolutePath
|
||||
|
||||
val clangCommand = clang.clangC(
|
||||
*compilerOptions.toTypedArray(), "-O2",
|
||||
cSourcePath, "-emit-llvm", "-c", "-o", bitcode.absolutePath
|
||||
*compilerOptions.toTypedArray(), "-O2",
|
||||
"-fexceptions", // Allow throwing exceptions through generated stubs.
|
||||
cSourcePath, "-emit-llvm", "-c", "-o", bitcode.absolutePath
|
||||
)
|
||||
if (dumpBridges) {
|
||||
println("CSTUBS for ${language}")
|
||||
|
||||
@@ -3970,6 +3970,11 @@ createInterop("withSpaces") {
|
||||
it.defFile generateWithSpaceDefFile()
|
||||
}
|
||||
|
||||
createInterop("exceptions_throwThroughBridge") {
|
||||
it.defFile "interop/exceptions/throwThroughBridge.def"
|
||||
it.extraOpts "-Xcompile-source", "$projectDir/interop/exceptions/throwThroughBridgeInterop.cpp"
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a task for the interop test. Configures runner and adds library and test build tasks.
|
||||
*/
|
||||
@@ -4208,8 +4213,7 @@ interopTest("interop_threadStates") {
|
||||
|
||||
interopTest("interop_threadStates_callbacksWithExceptions") {
|
||||
disabled = (project.testTarget == 'wasm32') || // No interop for wasm yet.
|
||||
!isExperimentalMM || // No thread state switching in the legacy MM.
|
||||
project.globalTestArgs.contains('-opt') // TODO: Fix this test for -opt.
|
||||
!isExperimentalMM // No thread state switching in the legacy MM.
|
||||
source = "interop/threadStates/callbacksWithExceptions.kt"
|
||||
interop = "threadStates"
|
||||
}
|
||||
@@ -4711,6 +4715,15 @@ dynamicTest("interop_memory_leaks") {
|
||||
outputChecker = { s -> s.contains("Memory leaks detected, 1 objects leaked!") }
|
||||
}
|
||||
|
||||
dynamicTest("interop_exceptions_throwThroughBridge") {
|
||||
source = "interop/exceptions/throwThroughBridge.kt"
|
||||
cSource = "$projectDir/interop/exceptions/throwThroughBridge.cpp"
|
||||
clangTool = "clang++"
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
outputChecker = { s -> !s.contains("Should not happen") }
|
||||
interop = "exceptions_throwThroughBridge"
|
||||
}
|
||||
|
||||
tasks.register("library_mismatch", KonanDriverTest) {
|
||||
// Does not work for cross targets yet.
|
||||
enabled = !(project.testTarget != null && project.target.name != project.hostName)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "testlib_api.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
try {
|
||||
testlib_symbols()->kotlin.root.kotlinFun();
|
||||
} catch (...) {
|
||||
printf("Should not happen\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
language = C
|
||||
|
||||
---
|
||||
|
||||
__attribute__((always_inline)) void throwCppException();
|
||||
@@ -0,0 +1,5 @@
|
||||
import throwThroughBridge.*
|
||||
|
||||
fun kotlinFun() {
|
||||
throwCppException()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdexcept>
|
||||
|
||||
extern "C" __attribute__((always_inline)) void throwCppException() {
|
||||
throw std::runtime_error("Error");
|
||||
}
|
||||
Reference in New Issue
Block a user