Skip to content

Commit 85d92ad

Browse files
authored
Merge pull request #69633 from drexin/wip-117755666-5.10
[5.10][Runtime] Fix missing memcpy in handleSingleRefCountInitWithCopy
2 parents a8d721d + 479de23 commit 85d92ad

File tree

3 files changed

+59
-6
lines changed

3 files changed

+59
-6
lines changed

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ static void singlePayloadEnumGenericBranchless(const Metadata *metadata,
296296
if (SWIFT_LIKELY(xiType)) {
297297
auto tag = xiType->vw_getEnumTagSinglePayload(
298298
(const OpaqueValue *)(addr + addrOffset + xiTagBytesOffset),
299-
numEmptyCases);
299+
xiType->vw_getNumExtraInhabitants());
300300
if (SWIFT_LIKELY(tag == 0)) {
301301
return;
302302
}
@@ -523,7 +523,7 @@ static void singlePayloadEnumGenericBranchless(const Metadata *metadata,
523523
if (SWIFT_LIKELY(xiType)) {
524524
auto tag = xiType->vw_getEnumTagSinglePayload(
525525
(const OpaqueValue *)(src + addrOffset + xiTagBytesOffset),
526-
numEmptyCases);
526+
xiType->vw_getNumExtraInhabitants());
527527
if (SWIFT_LIKELY(tag == 0)) {
528528
return;
529529
}
@@ -1378,7 +1378,12 @@ static void handleSingleRefCountInitWithCopy(const Metadata *metadata,
13781378
uint8_t *dest,
13791379
uint8_t *src) {
13801380
auto tag = reader.readBytes<uint64_t>();
1381-
addrOffset += (tag & ~(0xFFULL << 56));
1381+
auto _addrOffset = addrOffset;
1382+
auto offset = (tag & ~(0xFFULL << 56));
1383+
if (SWIFT_UNLIKELY(offset)) {
1384+
memcpy(dest + _addrOffset, src + _addrOffset, offset);
1385+
}
1386+
addrOffset = _addrOffset + offset;
13821387
tag >>= 56;
13831388
if (SWIFT_UNLIKELY(tag == 0)) {
13841389
return;
@@ -1551,13 +1556,13 @@ static void singlePayloadEnumGenericAssignWithCopy(const Metadata *metadata,
15511556
if (!srcTag) {
15521557
srcTag = xiType->vw_getEnumTagSinglePayload(
15531558
(const OpaqueValue *)(src + addrOffset + xiTagBytesOffset),
1554-
numEmptyCases);
1559+
xiType->vw_getNumExtraInhabitants());
15551560
}
15561561

15571562
if (!destTag) {
15581563
destTag = xiType->vw_getEnumTagSinglePayload(
15591564
(const OpaqueValue *)(dest + addrOffset + xiTagBytesOffset),
1560-
numEmptyCases);
1565+
xiType->vw_getNumExtraInhabitants());
15611566
}
15621567
}
15631568

@@ -2107,7 +2112,8 @@ swift_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
21072112
uint8_t numExtraTagBytes) -> unsigned {
21082113
if (xiType) {
21092114
return xiType->vw_getEnumTagSinglePayload(
2110-
(const OpaqueValue *)(addr + xiTagBytesOffset), numEmptyCases);
2115+
(const OpaqueValue *)(addr + xiTagBytesOffset),
2116+
xiType->vw_getNumExtraInhabitants());
21112117
}
21122118

21132119
return 0;

test/Interpreter/Inputs/layout_string_witnesses_types.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,12 @@ public enum PrespecializedMultiPayloadEnum<T> {
534534
case nonEmpty1(T, Int)
535535
}
536536

537+
public enum SinglePayloadEnumExistential {
538+
case a(SomeProtocol, AnyObject)
539+
case b
540+
case c
541+
}
542+
537543
@inline(never)
538544
public func consume<T>(_ x: T.Type) {
539545
withExtendedLifetime(x) {}
@@ -566,6 +572,10 @@ public func testAssign<T>(_ ptr: UnsafeMutablePointer<T>, from x: UnsafeMutableP
566572
ptr.assign(from: x, count: 1)
567573
}
568574

575+
public func testAssignCopy<T>(_ ptr: UnsafeMutablePointer<T>, from x: inout T) {
576+
ptr.update(from: &x, count: 1)
577+
}
578+
569579
@inline(never)
570580
public func testInit<T>(_ ptr: UnsafeMutablePointer<T>, to x: T) {
571581
ptr.initialize(to: x)

test/Interpreter/layout_string_witnesses_static.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,43 @@ func testSinglePayloadEnumManyXIEmpty() {
770770

771771
testSinglePayloadEnumManyXIEmpty()
772772

773+
func testEnumWithExistential() {
774+
// Regression test for rdar://117755666
775+
// A missing call to memcpy in `handleSingleRefCountInitWithCopy`
776+
// was causing unexpected behavior like wrong enum cases, crashes etc.
777+
// Without the fix, this test would not release the references.
778+
struct SomeProtocolImpl: SomeProtocol {
779+
let x: AnyObject
780+
}
781+
782+
let ptr = UnsafeMutablePointer<SinglePayloadEnumExistential>.allocate(capacity: 1)
783+
784+
do {
785+
let x = SinglePayloadEnumExistential.b
786+
testInit(ptr, to: x)
787+
}
788+
789+
do {
790+
var z = SinglePayloadEnumExistential.a(SomeProtocolImpl(x: SimpleClass(x: 23)), SimpleClass(x: 43))
791+
792+
// CHECK-NEXT: Before deinit
793+
print("Before deinit")
794+
795+
testAssignCopy(ptr, from: &z)
796+
}
797+
798+
// CHECK-NEXT: Before deinit
799+
print("Before deinit")
800+
801+
// CHECK-NEXT: SimpleClass deinitialized!
802+
// CHECK-NEXT: SimpleClass deinitialized!
803+
testDestroy(ptr)
804+
805+
ptr.deallocate()
806+
}
807+
808+
testEnumWithExistential()
809+
773810
#if os(macOS)
774811
func testObjc() {
775812
let ptr = UnsafeMutablePointer<ObjcWrapper>.allocate(capacity: 1)

0 commit comments

Comments
 (0)