Skip to content

Commit 73f8c54

Browse files
committed
IRGen: support the @sensitive attribute
Call `memset_s` after destroying or taking "sensitive" struct types. Also, support calling C-functions with "sensitive" parameters or return values. In SIL, sensitive types are address-only and so are sensitive parameters/return values. Though, (small) sensitive C-structs are passed directly to/from C-functions. We need re-abstract such parameter and return values for C-functions.
1 parent 7205c47 commit 73f8c54

33 files changed

+552
-80
lines changed

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2832,6 +2832,13 @@ FUNCTION(ClearSensitive, swift_clearSensitive, C_CC, ClearSensitiveAvailability,
28322832
EFFECT(NoEffect),
28332833
UNKNOWN_MEMEFFECTS)
28342834

2835+
FUNCTION(MemsetS, memset_s, C_CC, AlwaysAvailable,
2836+
RETURNS(Int32Ty),
2837+
ARGS(PtrTy, SizeTy, Int32Ty, SizeTy),
2838+
ATTRS(NoUnwind),
2839+
EFFECT(NoEffect),
2840+
UNKNOWN_MEMEFFECTS)
2841+
28352842
#undef RETURNS
28362843
#undef ARGS
28372844
#undef ATTRS

lib/IRGen/CallEmission.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ class CallEmission {
5757
/// The function we're going to call.
5858
Callee CurCallee;
5959

60+
/// Only valid if the SIL function has indirect return values.
61+
/// If the function has multiple indirect return values, this is the address
62+
/// of the first indirect return value.
63+
Address indirectReturnAddress;
64+
65+
/// For C-functions: true if the return is indirect in SIL, but direct for a C-function.
66+
/// That can happen for "sensitive" structs.
67+
bool convertDirectToIndirectReturn = false;
68+
6069
unsigned LastArgWritten;
6170

6271
/// Whether this is a coroutine invocation.
@@ -94,6 +103,11 @@ class CallEmission {
94103
virtual llvm::CallBase *createCall(const FunctionPointer &fn,
95104
ArrayRef<llvm::Value *> args) = 0;
96105

106+
void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
107+
Explosion &in, Explosion &out,
108+
TemporarySet &temporaries,
109+
bool isOutlined);
110+
97111
CallEmission(IRGenFunction &IGF, llvm::Value *selfValue, Callee &&callee)
98112
: IGF(IGF), selfValue(selfValue), CurCallee(std::move(callee)) {}
99113

@@ -119,6 +133,8 @@ class CallEmission {
119133

120134
void addFnAttribute(llvm::Attribute::AttrKind Attr);
121135

136+
void setIndirectReturnAddress(Address addr) { indirectReturnAddress = addr; }
137+
122138
void addParamAttribute(unsigned ParamIndex, llvm::Attribute::AttrKind Attr);
123139

124140
void emitToMemory(Address addr, const LoadableTypeInfo &substResultTI,

lib/IRGen/FixedTypeInfo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ class FixedTypeInfo : public TypeInfo {
9191
// We can give these reasonable default implementations.
9292

9393
void initializeWithTake(IRGenFunction &IGF, Address destAddr, Address srcAddr,
94-
SILType T, bool isOutlined) const override;
94+
SILType T, bool isOutlined,
95+
bool zeroizeIfSensitive) const override;
9596

9697
llvm::Value *getSize(IRGenFunction &IGF, SILType T) const override;
9798
llvm::Value *getAlignmentMask(IRGenFunction &IGF, SILType T) const override;

lib/IRGen/GenBuiltin.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,8 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
12291229
case BuiltinValueKind::TakeArrayNoAlias:
12301230
case BuiltinValueKind::TakeArrayFrontToBack:
12311231
case BuiltinValueKind::TakeArrayBackToFront:
1232-
elemTI.initializeWithTake(IGF, destAddr, srcAddr, elemTy, isOutlined);
1232+
elemTI.initializeWithTake(IGF, destAddr, srcAddr, elemTy, isOutlined,
1233+
/*zeroizeIfSensitive=*/ true);
12331234
break;
12341235
case BuiltinValueKind::AssignCopyArrayNoAlias:
12351236
case BuiltinValueKind::AssignCopyArrayFrontToBack:

lib/IRGen/GenCall.cpp

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,7 +1473,7 @@ void SignatureExpansion::expandExternalSignatureTypes() {
14731473
bool formalIndirectResult = FnType->getNumResults() > 0 &&
14741474
FnType->getSingleResult().isFormalIndirect();
14751475
assert(
1476-
(cxxCtorDecl || !formalIndirectResult || returnInfo.isIndirect()) &&
1476+
(cxxCtorDecl || !formalIndirectResult || returnInfo.isIndirect() || SILResultTy.isSensitive()) &&
14771477
"swift and clang disagree on whether the result is returned indirectly");
14781478
#endif
14791479

@@ -2391,10 +2391,6 @@ std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
23912391
return {fn, size};
23922392
}
23932393

2394-
static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
2395-
Explosion &in, Explosion &out,
2396-
TemporarySet &temporaries, bool isOutlined);
2397-
23982394
namespace {
23992395

24002396
class SyncCallEmission final : public CallEmission {
@@ -2633,11 +2629,19 @@ class SyncCallEmission final : public CallEmission {
26332629
return;
26342630
}
26352631

2636-
// Get the natural IR type in the body of the function that makes
2637-
// the call. This may be different than the IR type returned by the
2638-
// call itself due to ABI type coercion.
2639-
auto resultType =
2640-
fnConv.getSILResultType(IGF.IGM.getMaximalTypeExpansionContext());
2632+
SILType resultType;
2633+
if (convertDirectToIndirectReturn) {
2634+
resultType = SILType::getPrimitiveObjectType(
2635+
origFnType->getSingleResult().getReturnValueType(
2636+
IGF.IGM.getSILModule(), origFnType, TypeExpansionContext::minimal()));
2637+
} else {
2638+
// Get the natural IR type in the body of the function that makes
2639+
// the call. This may be different than the IR type returned by the
2640+
// call itself due to ABI type coercion.
2641+
resultType =
2642+
fnConv.getSILResultType(IGF.IGM.getMaximalTypeExpansionContext());
2643+
}
2644+
26412645
auto &nativeSchema = IGF.IGM.getTypeInfo(resultType).nativeReturnValueSchema(IGF.IGM);
26422646

26432647
// For ABI reasons the result type of the call might not actually match the
@@ -2653,6 +2657,10 @@ class SyncCallEmission final : public CallEmission {
26532657
result =
26542658
IGF.coerceValue(result, expectedNativeResultType, IGF.IGM.DataLayout);
26552659
}
2660+
if (convertDirectToIndirectReturn) {
2661+
IGF.Builder.CreateStore(result, indirectReturnAddress);
2662+
return;
2663+
}
26562664

26572665
// Gather the values.
26582666
Explosion nativeExplosion;
@@ -3962,7 +3970,7 @@ void irgen::emitClangExpandedParameter(IRGenFunction &IGF,
39623970
swiftTI.deallocateStack(IGF, tempAlloc, swiftType);
39633971
}
39643972

3965-
static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
3973+
void CallEmission::externalizeArguments(IRGenFunction &IGF, const Callee &callee,
39663974
Explosion &in, Explosion &out,
39673975
TemporarySet &temporaries,
39683976
bool isOutlined) {
@@ -3999,11 +4007,26 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
39994007

40004008
bool formalIndirectResult = fnType->getNumResults() > 0 &&
40014009
fnType->getSingleResult().isFormalIndirect();
4002-
4003-
// If clang returns directly and swift returns indirectly, this must be a c++
4004-
// constructor call. In that case, skip the "self" param.
4005-
if (!FI.getReturnInfo().isIndirect() && formalIndirectResult)
4006-
firstParam += 1;
4010+
if (!FI.getReturnInfo().isIndirect() && formalIndirectResult) {
4011+
// clang returns directly and swift returns indirectly
4012+
4013+
SILType returnTy = SILType::getPrimitiveObjectType(
4014+
fnType->getSingleResult().getReturnValueType(
4015+
IGF.IGM.getSILModule(), fnType, TypeExpansionContext::minimal()));
4016+
4017+
if (returnTy.isSensitive()) {
4018+
// Sensitive return types are represented as indirect return value in SIL,
4019+
// but are returned as values (if small) in LLVM IR.
4020+
assert(out.size() == 1 && "expect a single address for the return value");
4021+
llvm::Value *returnAddr = out.claimNext();
4022+
out.reset();
4023+
assert(returnAddr == indirectReturnAddress.getAddress());
4024+
convertDirectToIndirectReturn = true;
4025+
} else {
4026+
// This must be a constructor call. In that case, skip the "self" param.
4027+
firstParam += 1;
4028+
}
4029+
}
40074030

40084031
for (unsigned i = firstParam; i != paramEnd; ++i) {
40094032
auto clangParamTy = FI.arg_begin()[i].type;
@@ -4018,8 +4041,9 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
40184041
if (auto *padType = AI.getPaddingType())
40194042
out.add(llvm::UndefValue::get(padType));
40204043

4044+
const SILParameterInfo &paramInfo = params[i - firstParam];
40214045
SILType paramType = silConv.getSILType(
4022-
params[i - firstParam], IGF.IGM.getMaximalTypeExpansionContext());
4046+
paramInfo, IGF.IGM.getMaximalTypeExpansionContext());
40234047

40244048
// In Swift, values that are foreign references types will always be
40254049
// pointers. Additionally, we only import functions which use foreign
@@ -4037,6 +4061,23 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
40374061
continue;
40384062
}
40394063

4064+
bool passIndirectToDirect = paramInfo.isIndirectInGuaranteed() && paramType.isSensitive();
4065+
if (passIndirectToDirect) {
4066+
llvm::Value *ptr = in.claimNext();
4067+
4068+
if (AI.getKind() == clang::CodeGen::ABIArgInfo::Indirect) {
4069+
// It's a large struct which is also passed indirectl in LLVM IR.
4070+
out.add(ptr);
4071+
continue;
4072+
}
4073+
4074+
auto &ti = cast<LoadableTypeInfo>(IGF.getTypeInfo(paramType));
4075+
Explosion loadedValue;
4076+
ti.loadAsCopy(IGF, ti.getAddressForPointer(ptr), loadedValue);
4077+
in.transferInto(loadedValue, in.size());
4078+
in = std::move(loadedValue);
4079+
}
4080+
40404081
switch (AI.getKind()) {
40414082
case clang::CodeGen::ABIArgInfo::Extend: {
40424083
bool signExt = clangParamTy->hasSignedIntegerRepresentation();
@@ -4049,7 +4090,7 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
40494090
auto toTy = AI.getCoerceToType();
40504091

40514092
// Indirect parameters are bridged as Clang pointer types.
4052-
if (silConv.isSILIndirect(params[i - firstParam])) {
4093+
if (silConv.isSILIndirect(params[i - firstParam]) && !passIndirectToDirect) {
40534094
assert(paramType.isAddress() && "SIL type is not an address?");
40544095

40554096
auto addr = in.claimNext();

lib/IRGen/GenClangType.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ clang::CanQualType IRGenModule::getClangType(SILParameterInfo params,
5050
if (params.isIndirectMutating()) {
5151
return getClangASTContext().getPointerType(clangType);
5252
}
53-
if (params.isFormalIndirect()) {
53+
if (params.isFormalIndirect() &&
54+
// Sensitive return types are represented as indirect return value in SIL,
55+
// but are returned as values (if small) in LLVM IR.
56+
!paramTy.isSensitive()) {
5457
auto constTy =
5558
getClangASTContext().getCanonicalType(clangType.withConst());
5659
return getClangASTContext().getPointerType(constTy);

lib/IRGen/GenEnum.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ void EnumImplStrategy::initializeFromParams(IRGenFunction &IGF,
187187
if (TIK >= Loadable)
188188
return initialize(IGF, params, dest, isOutlined);
189189
Address src = TI->getAddressForPointer(params.claimNext());
190-
TI->initializeWithTake(IGF, dest, src, T, isOutlined);
190+
TI->initializeWithTake(IGF, dest, src, T, isOutlined, /*zeroizeIfSensitive=*/ true);
191191
}
192192

193193
bool EnumImplStrategy::isReflectable() const { return true; }
@@ -619,15 +619,16 @@ namespace {
619619
}
620620

621621
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
622-
SILType T, bool isOutlined) const override {
622+
SILType T, bool isOutlined,
623+
bool zeroizeIfSensitive) const override {
623624
if (!getSingleton()) return;
624625
if (!ElementsAreABIAccessible) {
625626
emitInitializeWithTakeCall(IGF, T, dest, src);
626627
} else if (isOutlined || T.hasParameterizedExistential()) {
627628
dest = getSingletonAddress(IGF, dest);
628629
src = getSingletonAddress(IGF, src);
629630
getSingleton()->initializeWithTake(
630-
IGF, dest, src, getSingletonType(IGF.IGM, T), isOutlined);
631+
IGF, dest, src, getSingletonType(IGF.IGM, T), isOutlined, zeroizeIfSensitive);
631632
} else {
632633
callOutlinedCopy(IGF, dest, src, T, IsInitialization, IsTake);
633634
}
@@ -1110,7 +1111,8 @@ namespace {
11101111
void emitScalarFixLifetime(IRGenFunction &IGF, llvm::Value *value) const {}
11111112

11121113
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
1113-
SILType T, bool isOutlined) const override {
1114+
SILType T, bool isOutlined,
1115+
bool zeroizeIfSensitive) const override {
11141116
// No-payload enums are always POD, so we can always initialize by
11151117
// primitive copy.
11161118
llvm::Value *val = IGF.Builder.CreateLoad(src);
@@ -3277,7 +3279,8 @@ namespace {
32773279
}
32783280

32793281
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
3280-
SILType T, bool isOutlined) const override {
3282+
SILType T, bool isOutlined,
3283+
bool zeroizeIfSensitive) const override {
32813284
if (!ElementsAreABIAccessible) {
32823285
emitInitializeWithTakeCall(IGF, T, dest, src);
32833286
} else if (isOutlined || T.hasParameterizedExistential()) {
@@ -5109,7 +5112,7 @@ namespace {
51095112

51105113
if (isTake)
51115114
payloadTI.initializeWithTake(IGF, destData, srcData, PayloadT,
5112-
isOutlined);
5115+
isOutlined, /*zeroizeIfSensitive=*/ true);
51135116
else
51145117
payloadTI.initializeWithCopy(IGF, destData, srcData, PayloadT,
51155118
isOutlined);
@@ -5183,7 +5186,8 @@ namespace {
51835186
}
51845187

51855188
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
5186-
SILType T, bool isOutlined) const override {
5189+
SILType T, bool isOutlined,
5190+
bool zeroizeIfSensitive) const override {
51875191
if (!ElementsAreABIAccessible) {
51885192
emitInitializeWithTakeCall(IGF, T, dest, src);
51895193
} else if (isOutlined || T.hasParameterizedExistential()) {
@@ -6121,7 +6125,8 @@ namespace {
61216125
}
61226126

61236127
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
6124-
SILType T, bool isOutlined) const override {
6128+
SILType T, bool isOutlined,
6129+
bool zeroizeIfSensitive) const override {
61256130
emitInitializeWithTakeCall(IGF, T,
61266131
dest, src);
61276132
}
@@ -6571,8 +6576,10 @@ namespace {
65716576
return Strategy.initializeWithCopy(IGF, dest, src, T, isOutlined);
65726577
}
65736578
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
6574-
SILType T, bool isOutlined) const override {
6575-
return Strategy.initializeWithTake(IGF, dest, src, T, isOutlined);
6579+
SILType T, bool isOutlined,
6580+
bool zeroizeIfSensitive) const override {
6581+
return Strategy.initializeWithTake(IGF, dest, src, T, isOutlined,
6582+
zeroizeIfSensitive);
65766583
}
65776584
void collectMetadataForOutlining(OutliningMetadataCollector &collector,
65786585
SILType T) const override {

lib/IRGen/GenEnum.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ class EnumImplStrategy {
408408
virtual void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src,
409409
SILType T, bool isOutlined) const = 0;
410410
virtual void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
411-
SILType T, bool isOutlined) const = 0;
411+
SILType T, bool isOutlined,
412+
bool zeroizeIfSensitive) const = 0;
412413

413414
virtual void initializeMetadata(IRGenFunction &IGF,
414415
llvm::Value *metadata,

lib/IRGen/GenExistential.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ namespace {
291291
}
292292

293293
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
294-
SILType T, bool isOutlined) const override {
294+
SILType T, bool isOutlined,
295+
bool zeroizeIfSensitive) const override {
295296
if (isOutlined) {
296297
Address destValue = projectValue(IGF, dest);
297298
Address srcValue = projectValue(IGF, src);
@@ -976,7 +977,8 @@ class OpaqueExistentialTypeInfo final :
976977
}
977978

978979
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
979-
SILType T, bool isOutlined) const override {
980+
SILType T, bool isOutlined,
981+
bool zeroizeIfSensitive) const override {
980982
if (isOutlined) {
981983
// memcpy the existential container. This is safe because: either the
982984
// value is stored inline and is therefore by convention bitwise takable

lib/IRGen/GenFunc.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2309,7 +2309,8 @@ std::optional<StackAddress> irgen::emitFunctionPartialApplication(
23092309
auto addr =
23102310
fieldLayout.getType().getAddressForPointer(args.claimNext());
23112311
fieldLayout.getType().initializeWithTake(IGF, fieldAddr, addr,
2312-
fieldTy, isOutlined);
2312+
fieldTy, isOutlined,
2313+
/*zeroizeIfSensitive=*/ true);
23132314
}
23142315
break;
23152316
}

0 commit comments

Comments
 (0)