Skip to content

Commit

Permalink
[K/N][Tests] Fix: Crashes when casting to an Obj-C class companion
Browse files Browse the repository at this point in the history
When generating section `__objc_classrefs`, need to consider distinguishing
`_OBJC_CLASS_$_` and `_OBJC_METACLASS_$_`

KT-65260
  • Loading branch information
edisongz committed Mar 22, 2024
1 parent 83ddf90 commit 757812a
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,14 @@ fun IrClass.getExternalObjCClassBinaryName(): String =
this.getExplicitExternalObjCClassBinaryName()
?: this.name.asString()

fun IrClass.getExternalObjCMetaClassBinaryName(): String =
this.getExplicitExternalObjCClassBinaryName()
?: this.name.asString().removeSuffix("Meta")
fun IrClass.getExternalObjCMetaClassBinaryName(): String {
this.getExplicitExternalObjCClassBinaryName()?.let { return it }
// External ObjC metaclass is named as `Foo.Componion`, Foo is subclass of NSObject or itself.
if (this.isCompanion) {
(this.parent as? IrClass)?.let { return it.name.asString() }
}
return this.name.asString().removeSuffix("Meta")
}

private fun IrClass.getExplicitExternalObjCClassBinaryName() =
this.annotations.findAnnotation(externalObjCClassFqName)!!.getAnnotationValueOrNull<String>("binaryName")
this.annotations.findAnnotation(externalObjCClassFqName)?.getAnnotationValueOrNull<String>("binaryName")
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,7 @@ internal abstract class FunctionGenerationContext(
generationState.dependenciesTracker.add(irClass)
if (irClass.isObjCMetaClass()) {
val name = irClass.getExternalObjCMetaClassBinaryName()
val objCClass = getObjCClass(name)
val objCClass = getObjCClass(name, isMetaclass = true)

val getClass = llvm.externalNativeRuntimeFunction(
"object_getClass",
Expand Down Expand Up @@ -1364,7 +1364,8 @@ internal abstract class FunctionGenerationContext(
}
}

private fun getObjCClass(binaryName: String) = load(llvm.int8PtrType, codegen.objCDataGenerator!!.genClassRef(binaryName).llvm)
private fun getObjCClass(binaryName: String, isMetaclass: Boolean = false) =
load(llvm.int8PtrType, codegen.objCDataGenerator!!.genClassRef(binaryName, isMetaclass).llvm)

fun getObjCClassFromNativeRuntime(binaryName: String): LLVMValueRef {
generationState.dependenciesTracker.addNativeRuntime()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
global.pointer
}

fun genClassRef(name: String): ConstPointer = classRefs.getOrPut(name) {
val classGlobal = getClassGlobal(name, isMetaclass = false)
fun genClassRef(name: String, isMetaclass: Boolean = false): ConstPointer = classRefs.getOrPut(name) {
// Need to distinguish between _OBJC_CLASS_$_ and _OBJC_METACLASS_$_
val classGlobal = getClassGlobal(name, isMetaclass)
val global = codegen.staticData.placeGlobal("OBJC_CLASSLIST_REFERENCES_\$_", classGlobal).also {
it.setLinkage(LLVMLinkage.LLVMPrivateLinkage)
it.setSection("__DATA,__objc_classrefs,regular,no_dead_strip")
Expand Down
24 changes: 24 additions & 0 deletions native/native.tests/testData/codegen/cinterop/objc/kt65260.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
// TARGET_BACKEND: NATIVE
// DISABLE_NATIVE: isAppleTarget=false
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import platform.Foundation.*
import platform.darwin.*
import kotlin.test.*

fun box(): String {
try {
// Test: cast to NSObject Metaclass
Any() as NSObject.Companion
// Test: cast to subclass of NSObject Metaclass
Any() as NSString.Companion
Any() as NSArray.Companion
} catch (e: Exception) {
// Cannot access 'TypeCastException': it is internal in Kotlin/Native.
assertTrue(e is ClassCastException)
}
return "OK"
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 757812a

Please sign in to comment.