Skip to content

Commit f994fe1

Browse files
committed
[6.0] IRGen: Properly adjust the closure type of a partial_apply of an objc_method
It needs to match with the (large loadable) lowered closure type in the rest of the program: Large types in the signature need to be passed indirectly. A failure to do so results in mis-matched ptr auth descriminators and a crash at runtime on arm64e. Scope: Should only affect programs that form closures of objective c methods involving large types Risk: Low for other code, medium for programs involving such closures Testing: A regression test was added rdar://127367321 Original PR: #73791 (cherry picked from commit 69b635a)
1 parent bb9c038 commit f994fe1

File tree

5 files changed

+83
-16
lines changed

5 files changed

+83
-16
lines changed

lib/IRGen/IRGenSIL.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6536,6 +6536,20 @@ void IRGenSILFunction::visitEndUnpairedAccessInst(EndUnpairedAccessInst *i) {
65366536
}
65376537

65386538
void IRGenSILFunction::visitConvertFunctionInst(swift::ConvertFunctionInst *i) {
6539+
auto &lv = getLoweredValue(i->getOperand());
6540+
if (lv.kind == LoweredValue::Kind::ObjCMethod) {
6541+
// LoadableByAddress lowering will insert convert_function instructions to
6542+
// change the type of a partial_apply instruction involving a objc_method
6543+
// convention, to change the partial_apply's SIL type (rewriting large types
6544+
// to @in_guaranteed/@out). This is important for pointer authentication.
6545+
6546+
// The convert_function instruction will carry the desired SIL type.
6547+
// Here we just forward the objective-c method.
6548+
auto &objcMethod = lv.getObjCMethod();
6549+
setLoweredObjCMethod(i, objcMethod.getMethod());
6550+
return;
6551+
}
6552+
65396553
// This instruction is specified to be a no-op.
65406554
Explosion temp = getLoweredExplosion(i->getOperand());
65416555

lib/IRGen/LoadableByAddress.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,12 @@ class LargeSILTypeMapper {
8080
irgen::IRGenModule &IGM);
8181
SmallVector<SILResultInfo, 2> getNewResults(GenericEnvironment *GenericEnv,
8282
CanSILFunctionType fnType,
83-
irgen::IRGenModule &Mod);
83+
irgen::IRGenModule &Mod,
84+
bool mustTransform = false);
8485
CanSILFunctionType getNewSILFunctionType(GenericEnvironment *env,
8586
CanSILFunctionType fnType,
86-
irgen::IRGenModule &IGM);
87+
irgen::IRGenModule &IGM,
88+
bool mustTransform = false);
8789
SILType getNewOptionalFunctionType(GenericEnvironment *GenericEnv,
8890
SILType storageType,
8991
irgen::IRGenModule &Mod);
@@ -240,8 +242,9 @@ bool LargeSILTypeMapper::newResultsDiffer(GenericEnvironment *GenericEnv,
240242

241243
static bool modNonFuncTypeResultType(GenericEnvironment *genEnv,
242244
CanSILFunctionType loweredTy,
243-
irgen::IRGenModule &Mod) {
244-
if (!modifiableFunction(loweredTy)) {
245+
irgen::IRGenModule &Mod,
246+
bool mustTransform = false) {
247+
if (!modifiableFunction(loweredTy) && !mustTransform) {
245248
return false;
246249
}
247250
if (loweredTy->getNumResults() != 1) {
@@ -258,7 +261,8 @@ static bool modNonFuncTypeResultType(GenericEnvironment *genEnv,
258261
SmallVector<SILResultInfo, 2>
259262
LargeSILTypeMapper::getNewResults(GenericEnvironment *GenericEnv,
260263
CanSILFunctionType fnType,
261-
irgen::IRGenModule &Mod) {
264+
irgen::IRGenModule &Mod,
265+
bool mustTransform) {
262266
// Get new SIL Function results - same as old results UNLESS:
263267
// 1) Function type results might have a different signature
264268
// 2) Large loadables are replaced by @out version
@@ -267,7 +271,7 @@ LargeSILTypeMapper::getNewResults(GenericEnvironment *GenericEnv,
267271
for (auto result : origResults) {
268272
SILType currResultTy = result.getSILStorageInterfaceType();
269273
SILType newSILType = getNewSILType(GenericEnv, currResultTy, Mod);
270-
if (modNonFuncTypeResultType(GenericEnv, fnType, Mod)) {
274+
if (modNonFuncTypeResultType(GenericEnv, fnType, Mod, mustTransform)) {
271275
// Case (2) Above
272276
SILResultInfo newSILResultInfo(newSILType.getASTType(),
273277
ResultConvention::Indirect);
@@ -287,8 +291,9 @@ LargeSILTypeMapper::getNewResults(GenericEnvironment *GenericEnv,
287291
CanSILFunctionType
288292
LargeSILTypeMapper::getNewSILFunctionType(GenericEnvironment *env,
289293
CanSILFunctionType fnType,
290-
irgen::IRGenModule &IGM) {
291-
if (!modifiableFunction(fnType)) {
294+
irgen::IRGenModule &IGM,
295+
bool mustTransform) {
296+
if (!modifiableFunction(fnType) && !mustTransform) {
292297
return fnType;
293298
}
294299

@@ -300,7 +305,7 @@ LargeSILTypeMapper::getNewSILFunctionType(GenericEnvironment *env,
300305

301306
auto newParams = getNewParameters(env, fnType, IGM);
302307
auto newYields = getNewYields(env, fnType, IGM);
303-
auto newResults = getNewResults(env, fnType, IGM);
308+
auto newResults = getNewResults(env, fnType, IGM, mustTransform);
304309
auto newFnType = SILFunctionType::get(
305310
fnType->getInvocationGenericSignature(),
306311
fnType->getExtInfo(),
@@ -2621,7 +2626,20 @@ void LoadableByAddress::recreateSingleApply(
26212626
// Change the type of the Closure
26222627
auto partialApplyConvention = castedApply->getCalleeConvention();
26232628
auto resultIsolation = castedApply->getResultIsolation();
2624-
2629+
// We do need to update the closure's funtion type to match with the other
2630+
// uses inside of the binary. Pointer auth cares about the SIL function
2631+
// type.
2632+
if (callee->getType().castTo<SILFunctionType>()->getExtInfo().getRepresentation() ==
2633+
SILFunctionTypeRepresentation::ObjCMethod) {
2634+
CanSILFunctionType newFnType =
2635+
MapperCache.getNewSILFunctionType(
2636+
genEnv,
2637+
callee->getType().castTo<SILFunctionType>(), *currIRMod,
2638+
/*mustTransform*/ true);
2639+
SILType newType = SILType::getPrimitiveObjectType(newFnType);
2640+
callee = applyBuilder.createConvertFunction(castedApply->getLoc(),
2641+
callee, newType, false);
2642+
}
26252643
auto newApply = applyBuilder.createPartialApply(
26262644
castedApply->getLoc(), callee, applySite.getSubstitutionMap(), callArgs,
26272645
partialApplyConvention, resultIsolation, castedApply->isOnStack());

test/IRGen/Inputs/large_c.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct SamplesType {
3030
void* AA;
3131
};
3232

33+
struct SamplesType samples();
3334

3435
typedef struct _ContainedType {
3536
unsigned int f1;

test/IRGen/big_types_corner_cases.sil

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
// RUN: %target-swift-frontend -Xllvm -sil-disable-pass=simplification -I %S/Inputs/abi %s -emit-ir | %FileCheck %s
1+
// RUN: %target-swift-frontend -sil-verify-none -Xllvm -sil-disable-pass=simplification -I %S/Inputs/abi %s -emit-ir | %FileCheck %s
22

33
// REQUIRES: CPU=x86_64
44
// REQUIRES: OS=macosx
55

6-
sil_stage canonical
6+
sil_stage lowered
7+
78
import c_layout
89
import Builtin
910
import Swift
@@ -307,13 +308,17 @@ bb0(%0 : $AnyObject):
307308
dynamic_method_br %2 : $@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self, #X.foo!foreign, bb1, bb2
308309

309310
bb1(%6 : $@convention(objc_method) (@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self) -> BitfieldOne): // Preds: bb0
311+
%addr = alloc_stack $BitfieldOne
310312
strong_retain %2 : $@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self
311-
%8 = partial_apply [callee_guaranteed] %6(%2) : $@convention(objc_method) (@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self) -> BitfieldOne
312-
%9 = apply %8() : $@callee_guaranteed () -> BitfieldOne
313+
%cvt = convert_function %6 : $@convention(objc_method) (@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self) -> BitfieldOne to $@convention(objc_method) (@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self) -> @out BitfieldOne
314+
%8 = partial_apply [callee_guaranteed] %cvt(%2) : $@convention(objc_method) (@opened("E5D03528-36AD-11E8-A0AB-D0817AD47398", AnyObject) Self) -> @out BitfieldOne
315+
%9 = apply %8(%addr) : $@callee_guaranteed () -> @out BitfieldOne
313316
%10 = init_enum_data_addr %4 : $*Optional<BitfieldOne>, #Optional.some!enumelt
314-
store %9 to %10 : $*BitfieldOne
317+
%val = load %addr : $*BitfieldOne
318+
store %val to %10 : $*BitfieldOne
315319
inject_enum_addr %4 : $*Optional<BitfieldOne>, #Optional.some!enumelt
316-
strong_release %8 : $@callee_guaranteed () -> BitfieldOne
320+
strong_release %8 : $@callee_guaranteed () -> @out BitfieldOne
321+
dealloc_stack %addr : $*BitfieldOne
317322
br bb3
318323

319324
bb2: // Preds: bb0
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %target-swift-frontend -I %t -emit-ir %s -import-objc-header %S/Inputs/large_c.h | %FileCheck %s
2+
// RUN: %target-swift-frontend -I %t -emit-ir %s -import-objc-header %S/Inputs/large_c.h -Xllvm -sil-print-after=loadable-address 2>&1 | %FileCheck %s --check-prefix=SIL
3+
4+
// REQUIRES: OS=ios && CPU=arm64e
5+
6+
import Foundation
7+
8+
@objc protocol P { @objc optional func testFunction(_ i: SamplesType) -> SamplesType }
9+
10+
class C: P { func testFunction(_ i: SamplesType) -> SamplesType { samples() } }
11+
12+
func test() {
13+
_ = (C() as P).testFunction?(samples())
14+
}
15+
16+
// Make sure the ptrauth discriminator at closure build and invocation time match.
17+
18+
// CHECK: @"$sTa.ptrauth" = private constant {{.*}} ptr @"$sTa"{{.*}} i64 55683 }, section "llvm.ptrauth"
19+
// CHECK: define hidden swiftcc void @"$s31loadable_by_address_objc_method4testyyF"()
20+
// CHECK: store {{.*}} @"$sTa.ptrauth"
21+
// CHECK: call swiftcc void {{.*}}(ptr {{.*}}sret(%TSo11SamplesTypeV) {{.*}} [ "ptrauth"(i32 0, i64 55683) ]
22+
// CHECK: }
23+
24+
test()
25+
26+
27+
// SIL: sil hidden @$s31loadable_by_address_objc_method4testyyF : $@convention(thin) () -> () {
28+
// SIL: [[C:%.*]] = convert_function {{.*}} : $@convention(objc_method) (SamplesType, @opened({{.*}}, any P) Self) -> SamplesType to $@convention(objc_method) (@in_guaranteed SamplesType, @opened({{.*}}, any P) Self) -> @out SamplesType
29+
// SIL: partial_apply [callee_guaranteed] [[C]]({{.*}}) : $@convention(objc_method) (@in_guaranteed SamplesType, @opened({{.*}}, any P) Self) -> @out SamplesType

0 commit comments

Comments
 (0)