Workaround false positive in AppStore private API usage detector

Fix #2751
This commit is contained in:
Svyatoslav Scherbina
2019-03-18 13:27:05 +03:00
committed by SvyatoslavScherbina
parent 87ae1eaa3b
commit 581aaea0c9
2 changed files with 58 additions and 2 deletions
@@ -89,10 +89,17 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
)
fun emitEmptyClass(name: String, superName: String) {
emitClass(name, superName, instanceMethods = emptyList())
}
class Method(val selector: String, val encoding: String, val imp: ConstPointer)
fun emitClass(name: String, superName: String, instanceMethods: List<Method>) {
val runtime = context.llvm.runtime
fun struct(name: String) = runtime.getStructType(name)
val classRoType = struct("_class_ro_t")
val methodType = struct("_objc_method")
val methodListType = struct("__method_list_t")
val protocolListType = struct("_objc_protocol_list")
val ivarListType = struct("_ivar_list_t")
@@ -100,6 +107,31 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
val classNameLiteral = classNames.get(name)
fun emitInstanceMethodList(): ConstPointer {
if (instanceMethods.isEmpty()) return NullPointer(methodListType)
val methodStructs = instanceMethods.map {
Struct(methodType, selectors.get(it.selector), encodings.get(it.encoding), it.imp.bitcast(int8TypePtr))
}
val methodList = Struct(
Int32(LLVMABISizeOfType(codegen.llvmTargetData, methodType).toInt()),
Int32(instanceMethods.size),
ConstArray(methodType, methodStructs)
)
val globalName = "\u0001l_OBJC_\$_INSTANCE_METHODS_$name"
val global = context.llvm.staticData.placeGlobal(globalName, methodList).also {
it.setLinkage(LLVMLinkage.LLVMPrivateLinkage)
it.setAlignment(runtime.pointerAlignment)
it.setSection("__DATA, __objc_const")
}
context.llvm.compilerUsedGlobals += global.llvmGlobal
return global.pointer.bitcast(pointerType(methodListType))
}
fun buildClassRo(isMetaclass: Boolean): ConstPointer {
// TODO: add NonFragileABI_Class_CompiledByARC flag?
@@ -124,7 +156,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
fields += Int32(size)
fields += NullPointer(int8Type) // ivar layout name
fields += classNameLiteral
fields += NullPointer(methodListType)
fields += if (isMetaclass) NullPointer(methodListType) else emitInstanceMethodList()
fields += NullPointer(protocolListType)
fields += NullPointer(ivarListType)
fields += NullPointer(int8Type) // ivar layout
@@ -220,6 +252,9 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
private val selectors =
CStringLiteralsTable("OBJC_METH_VAR_NAME_", "__TEXT,__objc_methname,cstring_literals")
private val encodings =
CStringLiteralsTable("OBJC_METH_VAR_TYPE_", "__TEXT,__objc_methtype,cstring_literals")
private inner class CStringLiteralsTable(val label: String, val section: String) {
private val literals = mutableMapOf<String, ConstPointer>()
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.constructedClass
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCCodeGenerator
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCDataGenerator
import org.jetbrains.kotlin.backend.konan.objcexport.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin
@@ -52,6 +53,8 @@ internal class ObjCExportCodeGenerator(
}
}
val referencedSelectors = mutableMapOf<String, MethodBridge>()
// TODO: currently bridges don't have any custom `landingpad`s,
// so it is correct to use [callAtFunctionScope] here.
// However, exception handling probably should be refactored
@@ -231,6 +234,20 @@ internal class ObjCExportCodeGenerator(
emitSortedAdapters(placedClassAdapters, "Kotlin_ObjCExport_sortedClassAdapters")
emitSortedAdapters(placedInterfaceAdapters, "Kotlin_ObjCExport_sortedProtocolAdapters")
emitSelectorsHolder()
}
private fun emitSelectorsHolder() {
val impType = functionType(voidType, false, int8TypePtr, int8TypePtr)
val imp = generateFunction(codegen, impType, "") {
unreachable()
}
val methods = referencedSelectors.map { (selector, bridge) ->
ObjCDataGenerator.Method(selector, getEncoding(bridge), constPointer(imp))
}
dataGenerator.emitClass("KotlinSelectorsHolder", "NSObject", instanceMethods = methods)
}
private val impType = pointerType(functionType(int8TypePtr, true, int8TypePtr, int8TypePtr))
@@ -674,7 +691,11 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
}
MethodBridgeReceiver.Instance -> kotlinReferenceToObjC(parameters[parameter]!!)
MethodBridgeSelector -> genSelector(namer.getSelector(baseMethod))
MethodBridgeSelector -> {
val selector = namer.getSelector(baseMethod)
referencedSelectors.getOrPut(selector) { methodBridge }
genSelector(selector)
}
MethodBridgeReceiver.Static,
MethodBridgeReceiver.Factory ->