Skip to content

Commit f4e6353

Browse files
committed
[Mirror] Don't destroy and reconstitute enums when reflecting them.
It's possible to get multiple threads reading from the same enum at the same time, and the result can be bad data extracted or even permanent corruption of the value in memory. Instead, copy the enum value, then project the data from the copy. rdar://problem/59493486
1 parent 9d4ea56 commit f4e6353

File tree

1 file changed

+12
-5
lines changed

1 file changed

+12
-5
lines changed

stdlib/public/runtime/ReflectionMirror.mm

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -488,14 +488,21 @@ AnyReturn subscript(intptr_t i, const char **outName,
488488

489489
auto *caseName = getInfo(&tag, &payloadType, &indirect);
490490

491+
// Copy the enum itself so that we can project the data without destroying
492+
// the original.
493+
Any enumCopy;
494+
auto *enumCopyContainer
495+
= type->allocateBoxForExistentialIn(&enumCopy.Buffer);
496+
type->vw_initializeWithCopy(enumCopyContainer,
497+
const_cast<OpaqueValue *>(value));
498+
491499
// Copy the enum payload into a box
492500
const Metadata *boxType = (indirect ? &METADATA_SYM(Bo).base : payloadType);
493501
BoxPair pair = swift_allocBox(boxType);
494-
495-
type->vw_destructiveProjectEnumData(const_cast<OpaqueValue *>(value));
496-
boxType->vw_initializeWithCopy(pair.buffer, const_cast<OpaqueValue *>(value));
497-
type->vw_destructiveInjectEnumTag(const_cast<OpaqueValue *>(value), tag);
498-
502+
type->vw_destructiveProjectEnumData(enumCopyContainer);
503+
boxType->vw_initializeWithTake(pair.buffer, enumCopyContainer);
504+
type->deallocateBoxForExistentialIn(&enumCopy.Buffer);
505+
499506
value = pair.buffer;
500507

501508
// If the payload is indirect, we need to jump through the box to get it.

0 commit comments

Comments
 (0)