Skip to content

Commit 56f8e54

Browse files
authored
Merge pull request #64194 from jckarter/noncopyable-value-witness-traps
IRGen: Make copying value witnesses trap for noncopyable types.
2 parents 31a71c8 + 5c98a66 commit 56f8e54

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

lib/IRGen/GenValueWitness.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,17 @@ static llvm::Constant *getNoOpVoidFunction(IRGenModule &IGM) {
731731
});
732732
}
733733

734+
/// Return a function that traps because of an attempt to copy a noncopyable
735+
/// type.
736+
static llvm::Constant *getNoncopyableTrapFunction(IRGenModule &IGM) {
737+
return IGM.getOrCreateHelperFunction("__swift_cannot_copy_noncopyable_type",
738+
IGM.VoidTy, {},
739+
[&](IRGenFunction &IGF) {
740+
IGF.Builder.CreateNonMergeableTrap(IGM, "attempt to copy a value of a type that cannot be copied");
741+
IGF.Builder.CreateUnreachable();
742+
});
743+
}
744+
734745
/// Return a function which takes three pointer arguments and does a
735746
/// retaining assignWithCopy on the first two: it loads a pointer from
736747
/// the second, retains it, loads a pointer from the first, stores the
@@ -918,6 +929,33 @@ bool isRuntimeInstatiatedLayoutString(IRGenModule &IGM,
918929
return false;
919930
}
920931

932+
static bool
933+
valueWitnessRequiresCopyability(ValueWitness index) {
934+
switch (index) {
935+
case ValueWitness::InitializeBufferWithCopyOfBuffer:
936+
case ValueWitness::InitializeWithCopy:
937+
case ValueWitness::AssignWithCopy:
938+
return true;
939+
940+
case ValueWitness::Destroy:
941+
case ValueWitness::InitializeWithTake:
942+
case ValueWitness::AssignWithTake:
943+
case ValueWitness::GetEnumTagSinglePayload:
944+
case ValueWitness::StoreEnumTagSinglePayload:
945+
case ValueWitness::Size:
946+
case ValueWitness::Stride:
947+
case ValueWitness::Flags:
948+
case ValueWitness::ExtraInhabitantCount:
949+
case ValueWitness::GetEnumTag:
950+
case ValueWitness::DestructiveProjectEnumData:
951+
case ValueWitness::DestructiveInjectEnumTag:
952+
return false;
953+
}
954+
llvm_unreachable("not all value witnesses covered");
955+
}
956+
957+
958+
921959
/// Find a witness to the fact that a type is a value type.
922960
/// Always adds an i8*.
923961
static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
@@ -931,6 +969,16 @@ static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
931969
B.addSignedPointer(fn, IGM.getOptions().PointerAuth.ValueWitnesses, index);
932970
};
933971

972+
// Copyable and noncopyable types share a value witness table layout. It
973+
// should normally be statically impossible to generate a call to a copy
974+
// value witness, but if somebody manages to dynamically get hold of metadata
975+
// for a noncopyable type, and tries to use it to copy values of that type,
976+
// we should trap to prevent the attempt.
977+
if (!concreteTI.isCopyable(ResilienceExpansion::Maximal)
978+
&& valueWitnessRequiresCopyability(index)) {
979+
return addFunction(getNoncopyableTrapFunction(IGM));
980+
}
981+
934982
// Try to use a standard function.
935983
switch (index) {
936984
case ValueWitness::Destroy:

test/IRGen/moveonly_deinit.sil

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ sil_stage canonical
1515
class C {}
1616

1717
// CHECK-LABEL: @{{.*}}8MOStructVWV" =
18+
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
1819
// noncopyable, nontrivial deinit, pointer aligned
1920
// CHECK-64-SAME: <i32 0x81_0007>
2021
// CHECK-32-SAME: <i32 0x81_0003>
@@ -27,6 +28,7 @@ struct MOStruct {
2728
}
2829

2930
// CHECK-LABEL: @{{.*}}6MOEnumOWV" =
31+
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
3032
// noncopyable, enum, nontrivial deinit, pointer aligned
3133
// CHECK-64-SAME: <i32 0xA1_0007>
3234
// CHECK-32-SAME: <i32 0xA1_0003>
@@ -39,6 +41,7 @@ enum MOEnum {
3941
}
4042

4143
// CHECK-LABEL: @{{.*}}13MOComboStructVWV" =
44+
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
4245
// noncopyable, non-inline, nontrivial deinit, pointer aligned
4346
// CHECK-64-SAME: <i32 0x83_0007>
4447
// CHECK-32-SAME: <i32 0x83_0003>
@@ -50,6 +53,7 @@ struct MOComboStruct {
5053
}
5154

5255
// CHECK-LABEL: @{{.*}}11MOComboEnumOWV" =
56+
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
5357
// noncopyable, enum, nontrivial deinit, pointer aligned
5458
// CHECK-64-SAME: <i32 0xA1_0007>
5559
// CHECK-32-SAME: <i32 0xA1_0003>
@@ -64,6 +68,7 @@ enum MOComboEnum {
6468
// common layout types.
6569

6670
// CHECK-LABEL: @{{.*}}13MOEmptyStructVWV" =
71+
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
6772
// noncopyable, nontrivial deinit, byte aligned
6873
// CHECK-SAME: <i32 0x81_0000>
6974
@_moveOnly
@@ -72,6 +77,7 @@ struct MOEmptyStruct {
7277
}
7378

7479
// CHECK-LABEL: @{{.*}}15MOIntLikeStructVWV" =
80+
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
7581
// noncopyable, nontrivial deinit, pointer aligned
7682
// CHECK-64-SAME: <i32 0x81_0007>
7783
// CHECK-32-SAME: <i32 0x81_0003>
@@ -83,6 +89,7 @@ struct MOIntLikeStruct {
8389
}
8490

8591
// CHECK-LABEL: @{{.*}}26MOSingleRefcountLikeStructVWV" =
92+
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
8693
// noncopyable, nontrivial deinit, pointer aligned
8794
// CHECK-64-SAME: <i32 0x81_0007>
8895
// CHECK-32-SAME: <i32 0x81_0003>
@@ -96,13 +103,15 @@ struct MOSingleRefcountLikeStruct {
96103
// Even if they don't have deinits, we shouldn't share a vwt.
97104

98105
// CHECK-LABEL: @{{.*}}21MOEmptyStructNoDeinitVWV" =
106+
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
99107
// noncopyable, trivial deinit, byte aligned
100108
// CHECK-SAME: <i32 0x80_0000>
101109
@_moveOnly
102110
struct MOEmptyStructNoDeinit {
103111
}
104112

105113
// CHECK-LABEL: @{{.*}}23MOIntLikeStructNoDeinitVWV" =
114+
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
106115
// noncopyable, trivial deinit, pointer aligned
107116
// CHECK-64-SAME: <i32 0x80_0007>
108117
// CHECK-32-SAME: <i32 0x80_0003>
@@ -112,6 +121,7 @@ struct MOIntLikeStructNoDeinit {
112121
}
113122

114123
// CHECK-LABEL: @{{.*}}34MOSingleRefcountLikeStructNoDeinitVWV" =
124+
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
115125
// noncopyable, nontrivial deinit, pointer aligned
116126
// CHECK-64-SAME: <i32 0x81_0007>
117127
// CHECK-32-SAME: <i32 0x81_0003>
@@ -319,7 +329,7 @@ sil_moveonlydeinit MOGenericDeinit { @destroy_generic }
319329
// CHECK-LABEL: define {{.*}} @"{{.*}}13MOComboStructVwxx"
320330
// CHECK: call {{.*}} @destroy_struct(
321331
// CHECK: call {{.*}} @destroy_enum(
322-
// CHECK: call {{.*}} @swift_retain(
332+
// CHECK: call {{.*}} @swift_release
323333
// CHECK-LABEL: define {{.*}} @"{{.*}}11MOComboEnumOwxx"
324334
// CHECK: call {{.*}} @[[COMBO_ENUM_OUTLINED_DESTROY]]
325335

0 commit comments

Comments
 (0)