[SE-0470] Prohibit isolated conformances in dynamic casts marked as such

Certain dynamic casts cannot work safely with isolated conformances,
regardless of what executor the code runs on. For such cases, reject
all attempts to conform to the type.
This commit is contained in:
Doug Gregor
2025-03-26 22:29:12 -07:00
parent e0b52cd20e
commit 43df05a89c
8 changed files with 202 additions and 84 deletions

View File

@@ -614,12 +614,19 @@ bool swift::_conformsToProtocolInContext(
const OpaqueValue *value,
const Metadata *type,
ProtocolDescriptorRef protocol,
const WitnessTable **conformance) {
const WitnessTable **conformance,
bool prohibitIsolatedConformances) {
ConformanceExecutionContext context;
if (!_conformsToProtocol(value, type, protocol, conformance, &context))
return false;
// If we aren't allowed to use isolated conformances and we ended up with
// one, fail.
if (prohibitIsolatedConformances &&
context.globalActorIsolationType)
return false;
if (!swift_isInConformanceExecutionContext(type, &context))
return false;
@@ -631,7 +638,8 @@ bool swift::_conformsToProtocolInContext(
static bool _conformsToProtocols(const OpaqueValue *value,
const Metadata *type,
const ExistentialTypeMetadata *existentialType,
const WitnessTable **conformances) {
const WitnessTable **conformances,
bool prohibitIsolatedConformances) {
if (auto *superclass = existentialType->getSuperclassConstraint()) {
if (!swift_dynamicCastMetatype(type, superclass))
return false;
@@ -644,7 +652,7 @@ static bool _conformsToProtocols(const OpaqueValue *value,
for (auto protocol : existentialType->getProtocols()) {
if (!_conformsToProtocolInContext(
value, type, protocol, conformances))
value, type, protocol, conformances, prohibitIsolatedConformances))
return false;
if (conformances != nullptr && protocol.needsWitnessTable()) {
assert(*conformances != nullptr);
@@ -1050,9 +1058,10 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType,
}
static const Metadata *
swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType,
const Metadata *targetType,
const char *file, unsigned line, unsigned column) {
swift_dynamicCastMetatypeUnconditionalImpl(
const Metadata *sourceType,
const Metadata *targetType,
const char *file, unsigned line, unsigned column) {
auto origSourceType = sourceType;
// Identical types always succeed
@@ -1138,7 +1147,8 @@ swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType,
case MetadataKind::Existential: {
auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType);
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential,
nullptr, /*prohibitIsolatedConformances=*/false))
return origSourceType;
swift_dynamicCastFailure(sourceType, targetType);
}