From d15ee71b6c4f2992037643aad79dcbdd2247b635 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Tue, 21 Nov 2023 12:07:16 +0100 Subject: [PATCH] Native: get rid of `__NSCFBoolean` references in ObjCExport ObjCExport accessed `__NSCFBoolean` using `objc_getClass("__NSCFBoolean")`. This class is a private API. Remove this private API usage by getting the same class from `[[NSNumber numberWithBool:YES] class]` instead. Also remove `__NSCFBoolean` from the related error messages. `__NSCFBoolean` didn't cause Kotlin-compiled apps to be rejected by Apple, but this commit reduces the risk that this might happen in the future, and addresses related user concerns. ^KT-62091 --- .../runtime/src/main/cpp/ObjCExport.mm | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/kotlin-native/runtime/src/main/cpp/ObjCExport.mm b/kotlin-native/runtime/src/main/cpp/ObjCExport.mm index d0b94376f1e..a49a70c556a 100644 --- a/kotlin-native/runtime/src/main/cpp/ObjCExport.mm +++ b/kotlin-native/runtime/src/main/cpp/ObjCExport.mm @@ -329,12 +329,20 @@ static void Kotlin_ObjCExport_initializeImpl() { BOOL added = class_addMethod(nsBlockClass, toKotlinSelector, (IMP)blockToKotlinImp, toKotlinTypeEncoding); RuntimeAssert(added, "Unable to add 'toKotlin:' method to NSBlock class"); - // Note: __NSCFBoolean is not visible to linker, so this case can't be handled with a category too. - Class booleanClass = objc_getClass("__NSCFBoolean"); - RuntimeAssert(booleanClass != nullptr, "__NSCFBoolean class not found"); + // Note: the boolean class is not visible to linker, so this case can't be handled with a category too. + // Referring it directly is also undesirable, because this is "private API" (see e.g. KT-62091). + // Get the class from an object instead: + Class booleanClass = [[NSNumber numberWithBool:YES] class]; + RuntimeAssert(booleanClass != nullptr, "The NS boolean class not found"); - added = class_addMethod(booleanClass, toKotlinSelector, (IMP)boxedBooleanToKotlinImp, toKotlinTypeEncoding); - RuntimeAssert(added, "Unable to add 'toKotlin:' method to __NSCFBoolean class"); + if (booleanClass != [[NSNumber numberWithInt:1] class]) { + added = class_addMethod(booleanClass, toKotlinSelector, (IMP)boxedBooleanToKotlinImp, toKotlinTypeEncoding); + RuntimeAssert(added, "Unable to add 'toKotlin:' method to the NS boolean class"); + } else { + // Shouldn't really happen unless something changed in the implementation. + // Play safe in that case, don't botch the numbers case. + RuntimeAssert(false, "NSNumber uses the same class for booleans and numbers: %s", class_getName(booleanClass)); + } for (const char* swiftRootClassName : { "SwiftObject", "_TtCs12_SwiftObject" }) { Class swiftRootClass = objc_getClass(swiftRootClassName);