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 ba503f6 commit 11d137c
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 12 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
93 changes: 85 additions & 8 deletions native/native.tests/testData/codegen/cinterop/objc/kt65260.kt
Original file line number Diff line number Diff line change
@@ -1,43 +1,120 @@
import java.lang.Exception

/*
* 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

// 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() {
try {
BNativeHeir as A.Companion
} catch (e: Exception) {
assertTrue(e is ClassCastException)
}

try {
ANativeHeir as A.Companion
} catch (e: Exception) {
assertTrue(e is ClassCastException)
}

assertTrue(A is A.Companion)

val fooObjectClass: Any = A
val barObjectClass: Any = B
assertFalse(fooObjectClass is BMeta)
assertTrue(barObjectClass is AMeta)
}


// 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)

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

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

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 11d137c

Please sign in to comment.