Skip to content

Commit 44d8251

Browse files
committed
Serialization: Refine safety checks for extensions/protocols.
In #65267 deserialization safety was made more conservative, allowing deserialization of any protocol and deserialization of any extension declaring an explicit conformance to any protocol. We can refine this to only allow deserialization of safe protocols and deserialization of extensions declaring conformances to safe protocols. Importantly, though, we must look up all conformances declared by the extension, not just the explicit ones. Resolves rdar://114673761
1 parent 2a75214 commit 44d8251

File tree

2 files changed

+12
-9
lines changed

2 files changed

+12
-9
lines changed

lib/Serialization/Serialization.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3289,9 +3289,10 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
32893289

32903290
// We can mark the extension unsafe only if it has no public
32913291
// conformances.
3292-
auto protocols = ext->getLocalProtocols(
3293-
ConformanceLookupKind::OnlyExplicit);
3294-
if (!protocols.empty())
3292+
auto protocols = ext->getLocalProtocols(ConformanceLookupKind::All);
3293+
bool hasSafeConformances = std::any_of(protocols.begin(), protocols.end(),
3294+
isDeserializationSafe);
3295+
if (hasSafeConformances)
32953296
return true;
32963297

32973298
// Truly empty extensions are safe, it may happen in swiftinterfaces.
@@ -3301,9 +3302,6 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
33013302
return false;
33023303
}
33033304

3304-
if (isa<ProtocolDecl>(decl))
3305-
return true;
3306-
33073305
auto value = cast<ValueDecl>(decl);
33083306

33093307
// A decl is safe if formally accessible publicly.

test/Serialization/Safety/indirect-conformance.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,22 @@
1212

1313
// RUN: cat %t/Lib.swiftinterface | %FileCheck %t/Lib.swift
1414

15-
public protocol PublicProtocol : AnyObject {}
16-
// CHECK: public protocol PublicProtocol : AnyObject
15+
public protocol PublicProtocol {}
16+
// CHECK: public protocol PublicProtocol
1717

1818
protocol InternalProtocol: PublicProtocol {}
1919
// CHECK-NOT: InternalProtocol
2020

2121
public class IndirectConformant {
2222
public init() {}
2323
}
24+
2425
extension IndirectConformant: InternalProtocol {}
2526
// CHECK: extension Lib.IndirectConformant : Lib.PublicProtocol {}
2627

28+
extension String: InternalProtocol {}
29+
// CHECK: extension Swift.String : Lib.PublicProtocol {}
30+
2731
//--- Client.swift
2832

2933
/// Works without safety.
@@ -43,10 +47,11 @@ import Lib
4347

4448
func requireConformanceToPublicProtocol(_ a: PublicProtocol) {}
4549
requireConformanceToPublicProtocol(IndirectConformant())
50+
requireConformanceToPublicProtocol("string")
4651

4752
/// Deserialization safety should keep the original chain. We're mostly
4853
/// documenting the current safety implementation details here, if we can get
4954
/// without deserializing 'InternalProtocol' it would be even better.
5055
// CHECK: Deserialized: 'IndirectConformant'
5156
// CHECK: Deserialized: 'PublicProtocol'
52-
// CHECK: Deserialized: 'InternalProtocol'
57+
// CHECK-NOT: Deserialized: 'InternalProtocol'

0 commit comments

Comments
 (0)