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
  • Loading branch information
edisongz committed Apr 4, 2024
1 parent a110cd6 commit 5b7dc82
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,9 @@ 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() }
val parent = this.parent as? IrClass
parent?.getExplicitExternalObjCClassBinaryName()?.let { return it }
parent?.let { return it.name.asString() }
}
return this.name.asString().removeSuffix("Meta")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1648,7 +1648,12 @@ internal class CodeGeneratorVisitor(
val resultNullBB = currentBlock.takeIf { !isAfterTerminator() }

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


Expand All @@ -1667,6 +1672,16 @@ 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 Down
77 changes: 69 additions & 8 deletions native/native.tests/testData/codegen/cinterop/objc/kt65260.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,101 @@
*/
// TARGET_BACKEND: NATIVE
// DISABLE_NATIVE: isAppleTarget=false

// MODULE: cinterop
// FILE: conversion.def
language = Objective-C
headers = conversion.h
headerFilter = conversion.h

// FILE: conversion.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

__attribute__((objc_runtime_name("Foo")))
@interface A : NSObject
@end

__attribute__((objc_runtime_name("Bar")))
@interface B : A
@end

NS_ASSUME_NONNULL_END

// FILE: conversion.m
#import "conversion.h"

@implementation A
@end

@implementation B
@end

// MODULE: lib(cinterop)
// FILE: lib.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import conversion.*
import platform.darwin.*
import kotlinx.cinterop.*
import kotlin.test.*

class ANativeHeir : A() {
companion object
}

class BNativeHeir : B() {
companion object
}

fun testExternalObjCMetaClassCast() {
assertFalse(ANativeHeir is A.Companion)
assertFalse(BNativeHeir is A.Companion)

assertTrue(A is A.Companion)
}


// MODULE: main(cinterop, lib)
// FILE: main.kt
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
import platform.Foundation.*
import platform.darwin.*
import kotlinx.cinterop.internal.*
import kotlin.test.*

fun test1() {
fun testAnyCast() {
try {
Any() as NSObject.Companion
} catch (e: Exception) {
assertTrue(e is ClassCastException)
}
}

fun test2() {
try {
Any() as NSNumber.Companion
} catch (e: Exception) {
assertTrue(e is ClassCastException)
}
}

fun test3() {
fun testMetaClassCast() {
assertFalse(Any() is NSObject.Companion)
assertFalse(Any() is NSNumber.Companion)

val nsObjectClass: Any = NSObject
assertFalse(nsObjectClass is NSNumberMeta)

NSData is NSData.Companion
try {
NSNumber as NSObject.Companion
} catch (e: Exception) {
assertTrue(e is ClassCastException)
}
}

fun box(): String {
test1()
test2()
test3()
testAnyCast()
testMetaClassCast()
testExternalObjCMetaClassCast()

return "OK"
}

0 comments on commit 5b7dc82

Please sign in to comment.