Describe the bug
I'm building Kotlin/Native gRPC support for protokt, a Kotlin Protocol Buffer compiler. protokt generates its own message types and uses the kotlinx-rpc compiler plugin to process @Grpc-annotated service interfaces for gRPC transport. I have it working on JVM but it segfaults on Native.
To Reproduce
- Kotlin version: 2.3.20
- Gradle version: 9.4.1
- OS: macOS (macosArm64 target)
- Minimal reproducer:
@Grpc
interface SimpleService {
suspend fun echo(message: String): String
}
fun main() {
val desc = serviceDescriptorOf(SimpleService::class)
println(desc.fqName) // works
println(desc.getCallable("echo")) // works by reading from the callables map
println(desc.callables) // segfaults (exit 139)
}
Crash stack from the macOS crash report:
[?] offset 0
[grpc-krpc-native.kexe] kfun:kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor#<get-callables>(){}kotlin.collections.Map<kotlin.String,kotlinx.rpc.
descriptor.RpcCallable<1:0>>-trampoline
[grpc-krpc-native.kexe] kfun:kotlinx.rpc.grpc.server.internal.GrpcServerImpl.getDefinition#internal
[grpc-krpc-native.kexe] kfun:kotlinx.rpc.grpc.server.internal.GrpcServerImpl#registerService(kotlin.reflect.KClass<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}
Expected behavior
descriptor.callables should return the map of callables, same as on JVM.
Additional context
The bug doesn't seem specific to protokt; I have a minimal reproducer that consumes the published 0.11.0-grpc-187 artifacts with no protokt involved. I was unable to reproduce the issue within the kotlinx-rpc project itself, which points to a subtler bug in the published artifacts.
Possible solution:
I have a minimal PR here that, when published locally, allows this branch of protokt to run successfully.
The failing invocation is ./examples/grpc-krpc-native/build/bin/macosArm64/debugExecutable/grpc-krpc-native.kexe, which creates a GrpcServer, registers a Greeter service with protokt messages, starts the server, connects a client, and calls SayHello.
Before, with 0.11.0-grpc-187:
Server started on port 50051
Exit: 139
After:
Server started on port 50051
Received: Hello Native World
Exit: 0
I've changed GrpcServerImpl to use delegate.methodNames instead of descriptor.callables. I haven't fully diagnosed why callables is broken. I've established that:
desc.fqName and desc.simpleName work (string properties on the same companion object)
desc.getCallable("echo") works (a function that reads from the callables backing field directly)
desc.callables segfaults at offset 0 in the itable trampoline
- The crash is in the property getter dispatch
- In the compiler plugin codegen,
callables is created via generateMapProperty with visibility = PRIVATE then gets a PUBLIC getter added, while simpleName/fqName are created with visibility = PUBLIC from the start (generateStringOverriddenProperty). I tried making callables PUBLIC too but that didn't fix it.
Describe the bug
I'm building Kotlin/Native gRPC support for protokt, a Kotlin Protocol Buffer compiler. protokt generates its own message types and uses the kotlinx-rpc compiler plugin to process @Grpc-annotated service interfaces for gRPC transport. I have it working on JVM but it segfaults on Native.
To Reproduce
Crash stack from the macOS crash report:
Expected behavior
descriptor.callables should return the map of callables, same as on JVM.
Additional context
The bug doesn't seem specific to protokt; I have a minimal reproducer that consumes the published 0.11.0-grpc-187 artifacts with no protokt involved. I was unable to reproduce the issue within the kotlinx-rpc project itself, which points to a subtler bug in the published artifacts.
Possible solution:
I have a minimal PR here that, when published locally, allows this branch of protokt to run successfully.
The failing invocation is
./examples/grpc-krpc-native/build/bin/macosArm64/debugExecutable/grpc-krpc-native.kexe, which creates a GrpcServer, registers a Greeter service with protokt messages, starts the server, connects a client, and calls SayHello.Before, with 0.11.0-grpc-187:
After:
I've changed GrpcServerImpl to use
delegate.methodNamesinstead ofdescriptor.callables. I haven't fully diagnosed whycallablesis broken. I've established that:desc.fqNameanddesc.simpleNamework (string properties on the same companion object)desc.getCallable("echo")works (a function that reads from thecallablesbacking field directly)desc.callablessegfaults at offset 0 in the itable trampolinecallablesis created viagenerateMapPropertywithvisibility = PRIVATEthen gets aPUBLICgetter added, whilesimpleName/fqNameare created withvisibility = PUBLICfrom the start (generateStringOverriddenProperty). I tried makingcallablesPUBLIC too but that didn't fix it.