As an experiment, I'm trying to load Kotlin native...
# kotlin-native
z
As an experiment, I'm trying to load Kotlin native shared library into an application at runtime. like a plugin loader. I'm able to easily call functions from the loader that are defined in the program but only with primitive types it seems. I'm trying to now add a way to pass over an application class. I created an application interface in a common api module that both the plugin and loader depend on. In the loader it implements the application simply as:
Copy code
val app = object : Application {
    override fun print(message: String) {
        println(message)
    }
}
Now when I try to use the application on the plugin side a segfault occurs. The loader code and plugin code are in the thread
This is the loader
Copy code
val app = object : Application {
    override fun print(message: String) {
        println(message)
    }
}

fun main(args: Array<String>) {
    val pluginPath = args.getOrNull(0)

    if (pluginPath == null) {
        println("No plugin path provided")
        exitProcess(1)
    }

    val a = args.getOrNull(1)?.toIntOrNull()
    val b = args.getOrNull(2)?.toIntOrNull()

    if (a == null || b == null) {
        println("Invalid arguments, expected two integers")
        exitProcess(1)
    }

    val plugin = try {
        Plugin(pluginPath)
    } catch (e: Exception) {
        e.printStackTrace()
        exitProcess(1)
    }

    println("Invoking \"add\" method")
    println(plugin.add(a, b))

    println("Invoking \"print\" method")
    plugin.print()
}

class Plugin(filename: String) : AutoCloseable {
    private val handle = dlopen(filename, RTLD_NOW)
        ?: throw IllegalStateException("Cannot load $filename: ${dlerror()}")
    private val _add = getFunction<(Int, Int) -> Int>("add")
    private val _testSay = getFunction<(COpaquePointer) -> Unit>("print")

    fun add(a: Int, b: Int): Int = _add(a, b)

    fun print() {
        val stableRef = StableRef.create(app)

        _testSay(stableRef.asCPointer())

        stableRef.dispose()
    }

    private fun <T : Function<*>> getFunction(name: String): CPointer<CFunction<T>> {
        return dlsym(handle, name)
            ?.reinterpret()
            ?: throw IllegalStateException("Could not find \"$name\": ${dlerror()}")
    }

    override fun close() {
        dlclose(handle)
    }
}
And the plugin:
Copy code
@CName("add")
fun add(a: Int, b: Int): Int = a + b

@OptIn(ExperimentalForeignApi::class)
@CName("print")
fun print(application: COpaquePointer) {
    val app = application.asStableRef<Application>()
    app.get().print("Hello from Kotlin plugin")
}
The add function works fine. But in the print function when it calls the print function on the application instance there it segfaults
Copy code
Uncaught Kotlin exception: kotlin.ClassCastException: class kotlin.String cannot be cast to class kotlin.String
    at 0   loader.kexe                         0x43618f           kfun:kotlin.Throwable#<init>(kotlin.String?){} + 111 
    at 1   loader.kexe                         0x430feb           kfun:kotlin.Exception#<init>(kotlin.String?){} + 107 
    at 2   loader.kexe                         0x43116b           kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 107 
    at 3   loader.kexe                         0x43172b           kfun:kotlin.ClassCastException#<init>(kotlin.String?){} + 107 
    at 4   loader.kexe                         0x448e95           ThrowClassCastException + 741 
    at 5   loader.kexe                         0x4a306e           _ZN12_GLOBAL__N_113kStringToUtf8B5cxx11EPK11ArrayHeader + 78 
    at 6   loader.kexe                         0x4a2eae           Kotlin_io_Console_print + 46 
    at 7   loader.kexe                         0x4a342a           Kotlin_io_Console_println + 10 
    at 8   loader.kexe                         0x439afc           kfun:kotlin.io#println(kotlin.Any?){} + 252 
    at 9   loader.kexe                         0x41ea3a           kfun:LoaderApp#print(kotlin.String){} + 74 
    at 10  libplugin.so                        0x74999f4df758     0x0 + 128203151505240 
    at 11  libplugin.so                        0x74999f4df6f0     0x0 + 128203151505136 
    at 12  libplugin.so                        0x74999f4df7fb     0x0 + 128203151505403 
    at 13  libplugin.so                        0x74999f4df9ab     print + 43 
    at 14  loader.kexe                         0x41f95b           kfun:Plugin#print(){} + 251 
    at 15  loader.kexe                         0x41ef9e           kfun:#main(kotlin.Array<kotlin.String>){} + 1358 
    at 16  loader.kexe                         0x420199           Konan_start + 137 
    at 17  loader.kexe                         0x42049a           Init_and_run_start + 122 
    at 18  libc.so.6                           0x7499a0837e07     0x0 + 128203171790343 
    at 19  libc.so.6                           0x7499a0837ecb     __libc_start_main + 139 
    at 20  loader.kexe                         0x41e806           0x0 + 4319238
Managed to solve my issue.. I changed the method to instead of using a String type to use a C-string (CPointer<ByteVar>) then converting to a cstring and Kotlin string where necessary. Not as convenient though