Skip to content

Commit

Permalink
[K/N][Tests] Fix crashes when casting to an Obj-C class companion #5270
Browse files Browse the repository at this point in the history
  • Loading branch information
edisongz committed Apr 8, 2024
1 parent 11d137c commit 7ca042a
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ internal class CodegenLlvmHelpers(private val generationState: NativeGenerationS

val Kotlin_Interop_DoesObjectConformToProtocol by lazyRtFunction
val Kotlin_Interop_IsObjectKindOfClass by lazyRtFunction
val Kotlin_Interop_IsSameClass by lazyRtFunction

val Kotlin_ObjCExport_refToLocalObjC by lazyRtFunction
val Kotlin_ObjCExport_refToRetainedObjC by lazyRtFunction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1648,12 +1648,7 @@ internal class CodeGeneratorVisitor(
val resultNullBB = currentBlock.takeIf { !isAfterTerminator() }

positionAtEnd(bbInstanceOf)
val checkResult = if (isSuperClassCast) {
kTrue
} else {
if (!isCompanionParentClass(value, dstClass)) kFalse else genInstanceOfImpl(srcArg, dstClass)
}
val resultInstanceOf = onCheck(srcArg, checkResult)
val resultInstanceOf = onCheck(srcArg, if (isSuperClassCast) kTrue else genInstanceOfImpl(srcArg, dstClass))
val resultInstanceOfBB = currentBlock.also { require(!isAfterTerminator()) }


Expand All @@ -1672,16 +1667,6 @@ internal class CodeGeneratorVisitor(
}
}

private fun isCompanionParentClass(value: IrTypeOperatorCall, dstClass: IrClass): Boolean {
var result = true
if (dstClass.isCompanion) {
(dstClass.parent as? IrClass)?.symbol?.let {
result = value.argument.type == it
}
}
return result
}

private fun genInstanceOfImpl(obj: LLVMValueRef, dstClass: IrClass) = with(functionGenerationContext) {
if (dstClass.defaultType.isObjCObjectType()) {
genInstanceOfObjC(obj, dstClass)
Expand All @@ -1701,7 +1686,12 @@ internal class CodeGeneratorVisitor(
null
)

return if (dstClass.isObjCClass()) {
return if (dstClass.isCompanion) {
call(
llvm.Kotlin_Interop_IsSameClass,
listOf(objCObject, genGetObjCClass(dstClass))
)
} else if (dstClass.isObjCClass()) {
if (dstClass.isInterface) {
val isMeta = if (dstClass.isObjCMetaClass()) kTrue else kFalse
call(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

touchFunction(Kotlin_Interop_DoesObjectConformToProtocol)
touchFunction(Kotlin_Interop_IsObjectKindOfClass)
touchFunction(Kotlin_Interop_IsSameClass)

touchFunction(Kotlin_ObjCExport_refToLocalObjC)
touchFunction(Kotlin_ObjCExport_refToRetainedObjC)
Expand Down
1 change: 1 addition & 0 deletions kotlin-native/runtime/src/main/cpp/ObjCInteropUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extern "C" {
id MissingInitImp(id self, SEL _cmd);
KBoolean Kotlin_Interop_DoesObjectConformToProtocol(id obj, void* prot, KBoolean isMeta);
KBoolean Kotlin_Interop_IsObjectKindOfClass(id obj, void* cls);
KBoolean Kotlin_Interop_IsSameClass(id obj, void* cls);
}

#endif // KONAN_OBJC_INTEROP
Expand Down
4 changes: 4 additions & 0 deletions kotlin-native/runtime/src/main/cpp/ObjCInteropUtils.mm
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ KBoolean Kotlin_Interop_IsObjectKindOfClass(id obj, void* cls) {
return [((id<NSObject>)obj) isKindOfClass:(Class)cls];
}

KBoolean Kotlin_Interop_IsSameClass(id obj, void* cls) {
return object_getClass(obj) == (Class)cls;
}

OBJ_GETTER((*Konan_ObjCInterop_getWeakReference_ptr), KRef ref) = nullptr;
void (*Konan_ObjCInterop_initWeakReference_ptr)(KRef ref, id objcPtr) = nullptr;

Expand Down
20 changes: 20 additions & 0 deletions native/native.tests/testData/codegen/cinterop/objc/kt65260.kt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ import platform.Foundation.*
import platform.darwin.*
import kotlin.test.*

open class FooK {
companion object
}

class BarK: FooK() {
companion object
}

fun testAnyCast() {
try {
Any() as NSObject.Companion
Expand Down Expand Up @@ -111,10 +119,22 @@ fun testMetaClassCast() {
assertTrue(NSData is NSData.Companion)
}

fun testNonObjCObjectTypeCast() {
val foo: Any = FooK
assertTrue(foo is FooK.Companion)

try {
BarK as FooK.Companion
} catch (e: Exception) {
assertTrue(e is ClassCastException)
}
}

fun box(): String {
testAnyCast()
testMetaClassCast()
testExternalObjCMetaClassCast()
testNonObjCObjectTypeCast()

return "OK"
}

0 comments on commit 7ca042a

Please sign in to comment.