Skip to content

Commit 7a4fcc6

Browse files
authored
[Runtime] Mask out reserved bits for SwiftError in BytecodeLayouts.cpp (#71669)
rdar://122911427 These bits can be used for storing multi payload enum tags and not masking them out can cause crashes an other unexpected behavior.
1 parent 1c24b88 commit 7a4fcc6

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,12 @@ static void handleEnd(const Metadata *metadata,
248248

249249
static void errorDestroy(const Metadata *metadata, LayoutStringReader1 &reader,
250250
uintptr_t &addrOffset, uint8_t *addr) {
251-
SwiftError *error = *(SwiftError**)(addr + addrOffset);
251+
uintptr_t object = *(uintptr_t *)(addr + addrOffset);
252+
if (object & _swift_abi_ObjCReservedBitsMask)
253+
return;
254+
object &= ~_swift_abi_SwiftSpareBitsMask;
252255
addrOffset += sizeof(SwiftError*);
253-
swift_errorRelease(error);
256+
swift_errorRelease((SwiftError *)object);
254257
}
255258

256259
static void nativeStrongDestroy(const Metadata *metadata,
@@ -899,10 +902,13 @@ static void handleRefCountsInitWithCopy(const Metadata *metadata,
899902
static void errorRetain(const Metadata *metadata, LayoutStringReader1 &reader,
900903
uintptr_t &addrOffset, uint8_t *dest, uint8_t *src) {
901904
uintptr_t _addrOffset = addrOffset;
902-
SwiftError *object = *(SwiftError **)(src + _addrOffset);
905+
uintptr_t object = *(uintptr_t *)(src + _addrOffset);
906+
if (object & _swift_abi_ObjCReservedBitsMask)
907+
return;
908+
object &= ~_swift_abi_SwiftSpareBitsMask;
903909
memcpy(dest + addrOffset, &object, sizeof(SwiftError*));
904910
addrOffset = _addrOffset + sizeof(SwiftError *);
905-
swift_errorRetain(object);
911+
swift_errorRetain((SwiftError *)object);
906912
}
907913

908914
static void nativeStrongRetain(const Metadata *metadata,
@@ -1286,12 +1292,21 @@ static void errorAssignWithCopy(const Metadata *metadata,
12861292
uintptr_t &addrOffset, uint8_t *dest,
12871293
uint8_t *src) {
12881294
uintptr_t _addrOffset = addrOffset;
1289-
SwiftError *destObject = *(SwiftError **)(dest + _addrOffset);
1290-
SwiftError *srcObject = *(SwiftError **)(src + _addrOffset);
1295+
uintptr_t destObject = *(uintptr_t *)(dest + _addrOffset);
1296+
uintptr_t srcObject = *(uintptr_t *)(src + _addrOffset);
1297+
12911298
memcpy(dest + _addrOffset, &srcObject, sizeof(SwiftError *));
12921299
addrOffset = _addrOffset + sizeof(SwiftError *);
1293-
swift_errorRelease(destObject);
1294-
swift_errorRetain(srcObject);
1300+
1301+
if (!(destObject & _swift_abi_ObjCReservedBitsMask)) {
1302+
destObject &= ~_swift_abi_SwiftSpareBitsMask;
1303+
swift_errorRelease((SwiftError *)destObject);
1304+
}
1305+
1306+
if (!(srcObject & _swift_abi_ObjCReservedBitsMask)) {
1307+
srcObject &= ~_swift_abi_SwiftSpareBitsMask;
1308+
swift_errorRetain((SwiftError *)srcObject);
1309+
}
12951310
}
12961311

12971312
static void nativeStrongAssignWithCopy(const Metadata *metadata,

test/Interpreter/Inputs/layout_string_witnesses_types.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,12 @@ public enum NestedMultiPayloadOuter {
588588
case c(NestedMultiPayloadInner)
589589
}
590590

591+
public enum MultiPayloadError {
592+
case empty
593+
case error1(Int, Error)
594+
case error2(Int, Error)
595+
}
596+
591597
@inline(never)
592598
public func consume<T>(_ x: T.Type) {
593599
withExtendedLifetime(x) {}

test/Interpreter/layout_string_witnesses_static.swift

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,54 @@ func testMultiPayloadEnumNested() {
11321132

11331133
testMultiPayloadEnumNested()
11341134

1135+
struct MyError: Error {
1136+
let x: SimpleClass
1137+
}
1138+
1139+
// Regression test for rdar://122911427
1140+
func testMultiPayloadError() {
1141+
let ptr = UnsafeMutablePointer<MultiPayloadError>.allocate(capacity: 1)
1142+
1143+
// initWithTake
1144+
do {
1145+
let x = MultiPayloadError.error2(0, MyError(x: SimpleClass(x: 23)))
1146+
testInitTake(ptr, to: consume x)
1147+
}
1148+
1149+
// assignWithTake
1150+
do {
1151+
let y = MultiPayloadError.error2(1, MyError(x: SimpleClass(x: 32)))
1152+
1153+
// CHECK-NEXT: Before deinit
1154+
print("Before deinit")
1155+
1156+
// CHECK-NEXT: SimpleClass deinitialized!
1157+
testAssign(ptr, from: y)
1158+
}
1159+
1160+
// assignWithCopy
1161+
do {
1162+
var z = MultiPayloadError.error2(2, MyError(x: SimpleClass(x: 41)))
1163+
1164+
// CHECK-NEXT: Before deinit
1165+
print("Before deinit")
1166+
1167+
// CHECK-NEXT: SimpleClass deinitialized!
1168+
testAssignCopy(ptr, from: &z)
1169+
}
1170+
1171+
// CHECK-NEXT: Before deinit
1172+
print("Before deinit")
1173+
1174+
// destroy
1175+
// CHECK-NEXT: SimpleClass deinitialized!
1176+
testDestroy(ptr)
1177+
1178+
ptr.deallocate()
1179+
}
1180+
1181+
testMultiPayloadError()
1182+
11351183
#if os(macOS)
11361184
func testObjc() {
11371185
let ptr = UnsafeMutablePointer<ObjcWrapper>.allocate(capacity: 1)

0 commit comments

Comments
 (0)