I’m trying to create some bindings for <Jolt Physi...
# kotlin-native
a
I’m trying to create some bindings for Jolt Physics (by way of zphysics). I’ve generated the K/N cinterop, but I’m having trouble converting some C code to Kotlin. I’ve tried it a few different ways, but when I run my K/N app it just crashes, with no error. Is there a way to get more information about runtime errors? Here’s the C code I’m trying to convert. It fails on
JPC_BodyInterface_CreateBody
Copy code
JPC_Body *floor = JPC_BodyInterface_CreateBody(body_interface, &floor_settings);
my Kotlin code is in the thread 🧵 I guess it’s a problem with passing in the
floor_settings
pointer? Or maybe
body_interface
isn’t stable? Do I need to pin it?
main.kt.cpp
this is the output I get - nothing too exciting
Copy code
<snip>
creating static floor body...

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':modules:interop-jolt:runDebugExecutableMacosX64'.
> Process 'command '/projects/jolt/build/bin/macosX64/debugExecutable/interop-jolt.kexe'' finished with non-zero exit value 139

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':jolt:runDebugExecutableMacosX64'.
	...
Caused by: org.gradle.process.internal.ExecException: Process 'command '/projects/jolt/build/bin/macosX64/debugExecutable/interop-jolt.kexe'' finished with non-zero exit value 139
	...
v
You can run the
.kexe
directly (not from intellij) and it might show you some more info. exit value 139 is probably a segfault
a
ah yeah, that’s right
Copy code
creating static floor body...
[1]    1444 segmentation fault  ./build/bin/macosX64/debugExecutable/interop-jolt.kexe
v
you can try some println logs in between statements to see in which function it occurs (assuming the segfault is on the same thread and not somewhere else)
the code you posted in the thread isn't the one that is being run? I don't see much references to your
creating static floor body
logs
a
oh I copied the wrong function, I’ll update it
it’s
JPC_BodyInterface_CreateBody
that’s failing
Copy code
println("creating static floor body...")
  val floor = JPC_BodyInterface_CreateBody(
    in_iface = bodyInterface,
    in_setting = floorSettings.ptr,
  )
I’m pretty sure it’s not a problem with
floorSettings.ptr
, since that’s used in
JPC_BodyCreationSettings_Set()
and it correctly updates the values of
floorSettings
maybe it’s something wrong with
bodyInterface
Copy code
val bodyInterface: CPointer<JPC_BodyInterface> =
  JPC_PhysicsSystem_GetBodyInterface(physicsSystem)!!
println("bodyInterface: $bodyInterface")
but this prints
bodyInterface: CPointer(raw=0x7fe76300a5b0)
, which seems okay
although the type,
JPC_BodyInterface
, doesn’t have any properties - maybe K/N gets confused about the size?
Copy code
typedef struct JPC_BodyInterface     JPC_BodyInterface;
v
you could try calling another method on bodyInterface
to see if that is the problem or if it is the floorSettings.ptr
a
good idea! Hmmm, this segfaults
Copy code
val bodyInterface: CPointer<JPC_BodyInterface> =
  JPC_PhysicsSystem_GetBodyInterface(physicsSystem)!!
println("    99u added?: ${JPC_BodyInterface_IsAdded(bodyInterface, 99u)}")
j
You can add
kotlin.native.binary.sourceInfoType=libbacktrace
to gradle.properties to get better stack traces in Kotlin/Native. It doesn't work with Windows targets though, so if you have a Windows target, you can selectively enable it in build.gradle.kts:
Copy code
targets.withType<KotlinNativeTarget> {
    if (konanTarget.family != Family.MINGW) {
        binaries.all {
            binaryOptions["sourceInfoType"] = "libbacktrace"
        }
    }
}
a
fixed it! In some of my set up code I was using
cValue<FooStruct> {}
, which apparently is wrong 🤷‍♀️
Copy code
private fun MemScope.createBodyActivationListener(): CValue<MyActivationListener> {
  return cValue<MyActivationListener> {
    vtable = cValue<JPC_BodyActivationListenerVTable> {
      OnBodyActivated = staticCFunction { _, _, _ -> /*...*/ }
      OnBodyDeactivated = staticCFunction { _, _, _ ->  /*...*/ }
    }.ptr
  }
}
instead I changed
cValue<FooStruct> {}
to
alloc<FooStruct> {}
Copy code
private fun AutofreeScope.createBodyActivationListener(): MyActivationListener {
  return alloc<MyActivationListener> {
    vtable = alloc<JPC_BodyActivationListenerVTable> {
      OnBodyActivated = staticCFunction { _, _, _ -> /*...*/ }
      OnBodyDeactivated = staticCFunction { _, _, _ ->  /*...*/ }
    }.ptr
  }
}
l
I believe cValue is stack allocated, so the memory becomes invalid once the method is over, especially because you return a ptr instead of returning by value.
a
I was confused because
.ptr
is a function provided by
MemScope
, and because
createBodyActivationListener()
was re-using the same
MemScope
as was used across my whole app I expected the pointer to be stable
l
A C pointer is only valid as long as the memory it points to is still allocated. It will be valid inside the memscope, but it's important that your pointer does not leave the memscoped, since the memory will be freed.
a
Yeah, that’s what I thought :) I had
Copy code
fun main(): Unit = memScoped {
  ...
}
and then all of the functions extended
MemScope
, so the same one was used