Skip to content

Commit 1b1d5ed

Browse files
committed
IRGen: support the @sensitive attribute
Call `swift_clearSensitive` 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 ce33d47 commit 1b1d5ed

34 files changed

+571
-82
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: 73 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,7 +1474,7 @@ void SignatureExpansion::expandExternalSignatureTypes() {
14741474
bool formalIndirectResult = FnType->getNumResults() > 0 &&
14751475
FnType->getSingleResult().isFormalIndirect();
14761476
assert(
1477-
(cxxCtorDecl || !formalIndirectResult || returnInfo.isIndirect()) &&
1477+
(cxxCtorDecl || !formalIndirectResult || returnInfo.isIndirect() || SILResultTy.isSensitive()) &&
14781478
"swift and clang disagree on whether the result is returned indirectly");
14791479
#endif
14801480

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

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

24012397
class SyncCallEmission final : public CallEmission {
@@ -2634,11 +2630,19 @@ class SyncCallEmission final : public CallEmission {
26342630
return;
26352631
}
26362632

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

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

26582666
// Gather the values.
26592667
Explosion nativeExplosion;
@@ -3983,7 +3991,7 @@ Address getForwardableAlloca(const TypeInfo &TI, bool isForwardableArgument,
39833991
return TI.getAddressForPointer(alloca);
39843992
}
39853993

3986-
static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
3994+
void CallEmission::externalizeArguments(IRGenFunction &IGF, const Callee &callee,
39873995
Explosion &in, Explosion &out,
39883996
TemporarySet &temporaries,
39893997
bool isOutlined) {
@@ -4020,11 +4028,26 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
40204028

40214029
bool formalIndirectResult = fnType->getNumResults() > 0 &&
40224030
fnType->getSingleResult().isFormalIndirect();
4023-
4024-
// If clang returns directly and swift returns indirectly, this must be a c++
4025-
// constructor call. In that case, skip the "self" param.
4026-
if (!FI.getReturnInfo().isIndirect() && formalIndirectResult)
4027-
firstParam += 1;
4031+
if (!FI.getReturnInfo().isIndirect() && formalIndirectResult) {
4032+
// clang returns directly and swift returns indirectly
4033+
4034+
SILType returnTy = SILType::getPrimitiveObjectType(
4035+
fnType->getSingleResult().getReturnValueType(
4036+
IGF.IGM.getSILModule(), fnType, TypeExpansionContext::minimal()));
4037+
4038+
if (returnTy.isSensitive()) {
4039+
// Sensitive return types are represented as indirect return value in SIL,
4040+
// but are returned as values (if small) in LLVM IR.
4041+
assert(out.size() == 1 && "expect a single address for the return value");
4042+
llvm::Value *returnAddr = out.claimNext();
4043+
out.reset();
4044+
assert(returnAddr == indirectReturnAddress.getAddress());
4045+
convertDirectToIndirectReturn = true;
4046+
} else {
4047+
// This must be a constructor call. In that case, skip the "self" param.
4048+
firstParam += 1;
4049+
}
4050+
}
40284051

40294052
for (unsigned i = firstParam; i != paramEnd; ++i) {
40304053
auto clangParamTy = FI.arg_begin()[i].type;
@@ -4039,8 +4062,9 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
40394062
if (auto *padType = AI.getPaddingType())
40404063
out.add(llvm::UndefValue::get(padType));
40414064

4065+
const SILParameterInfo &paramInfo = params[i - firstParam];
40424066
SILType paramType = silConv.getSILType(
4043-
params[i - firstParam], IGF.IGM.getMaximalTypeExpansionContext());
4067+
paramInfo, IGF.IGM.getMaximalTypeExpansionContext());
40444068

40454069
bool isForwardableArgument = IGF.isForwardableArgument(i - firstParam);
40464070

@@ -4060,6 +4084,35 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
40604084
continue;
40614085
}
40624086

4087+
bool passIndirectToDirect = paramInfo.isIndirectInGuaranteed() && paramType.isSensitive();
4088+
if (passIndirectToDirect) {
4089+
llvm::Value *ptr = in.claimNext();
4090+
4091+
if (AI.getKind() == clang::CodeGen::ABIArgInfo::Indirect) {
4092+
// It's a large struct which is also passed indirectl in LLVM IR.
4093+
// The C function (= the callee) is allowed to modify the memory used
4094+
// for passing arguments, therefore we need to copy the argument value
4095+
// to a temporary.
4096+
// TODO: avoid the temporary if the SIL parameter value in memory is
4097+
// not used anymore after the call.
4098+
auto &ti = cast<LoadableTypeInfo>(IGF.getTypeInfo(paramType));
4099+
auto temp = ti.allocateStack(IGF, paramType, "indirect-temporary");
4100+
Address tempAddr = temp.getAddress();
4101+
temporaries.add({temp, paramType});
4102+
Address paramAddr = ti.getAddressForPointer(ptr);
4103+
ti.initializeWithCopy(IGF, tempAddr, paramAddr, paramType, isOutlined);
4104+
4105+
out.add(tempAddr.getAddress());
4106+
continue;
4107+
}
4108+
4109+
auto &ti = cast<LoadableTypeInfo>(IGF.getTypeInfo(paramType));
4110+
Explosion loadedValue;
4111+
ti.loadAsCopy(IGF, ti.getAddressForPointer(ptr), loadedValue);
4112+
in.transferInto(loadedValue, in.size());
4113+
in = std::move(loadedValue);
4114+
}
4115+
40634116
switch (AI.getKind()) {
40644117
case clang::CodeGen::ABIArgInfo::Extend: {
40654118
bool signExt = clangParamTy->hasSignedIntegerRepresentation();
@@ -4072,7 +4125,7 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
40724125
auto toTy = AI.getCoerceToType();
40734126

40744127
// Indirect parameters are bridged as Clang pointer types.
4075-
if (silConv.isSILIndirect(params[i - firstParam])) {
4128+
if (silConv.isSILIndirect(params[i - firstParam]) && !passIndirectToDirect) {
40764129
assert(paramType.isAddress() && "SIL type is not an address?");
40774130

40784131
auto addr = in.claimNext();
@@ -4111,7 +4164,8 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
41114164
// preceeding the apply.
41124165
if (isForwardableArgument && forwardFromAddr.isValid()) {
41134166
ti.initializeWithTake(IGF, addr, forwardFromAddr,
4114-
paramType.getAddressType(), isOutlined);
4167+
paramType.getAddressType(), isOutlined,
4168+
/*zeroizeIfSensitive=*/ true);
41154169
(void)in.claim(ti.getSchema().size());
41164170
} else {
41174171
ti.initialize(IGF, in, addr, isOutlined);

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 || T.hasLocalArchetype()) {
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 || T.hasLocalArchetype()) {
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)