Skip to content

Commit 4622873

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 4622873

File tree

4 files changed

+24
-24
lines changed

4 files changed

+24
-24
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 & 6 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,8 @@ import Lib
4347

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

47-
/// Deserialization safety should keep the original chain. We're mostly
48-
/// documenting the current safety implementation details here, if we can get
49-
/// without deserializing 'InternalProtocol' it would be even better.
5052
// CHECK: Deserialized: 'IndirectConformant'
5153
// CHECK: Deserialized: 'PublicProtocol'
52-
// CHECK: Deserialized: 'InternalProtocol'
54+
// CHECK-NOT: Deserialized: 'InternalProtocol'

test/Serialization/Safety/unsafe-decls.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@
3434
public protocol PublicProto {}
3535
// SAFETY-PRIVATE: Serialization safety, safe: 'PublicProto'
3636
internal protocol InternalProto {}
37-
// SAFETY-INTERNAL: Serialization safety, safe: 'InternalProto'
38-
// NO-SAFETY-INTERNAL: Serialization safety, safe: 'InternalProto'
37+
// SAFETY-INTERNAL: Serialization safety, unsafe: 'InternalProto'
38+
// NO-SAFETY-INTERNAL: Serialization safety, unsafe: 'InternalProto'
3939
private protocol PrivateProto {}
40-
// SAFETY-PRIVATE: Serialization safety, safe: 'PrivateProto'
40+
// SAFETY-PRIVATE: Serialization safety, unsafe: 'PrivateProto'
4141
fileprivate protocol FileprivateProto {}
42-
// SAFETY-PRIVATE: Serialization safety, safe: 'FileprivateProto'
42+
// SAFETY-PRIVATE: Serialization safety, unsafe: 'FileprivateProto'
4343

4444
internal struct InternalStruct : PublicProto {
4545
// SAFETY-INTERNAL: Serialization safety, unsafe: 'InternalStruct'

test/Serialization/Safety/unsafe-extensions.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ extension ExtendedPublic : PublicProto {
4747

4848
/// Internal
4949
internal protocol InternalProto {}
50-
// SAFETY-INTERNAL: Serialization safety, safe: 'InternalProto'
51-
// NO-SAFETY-INTERNAL: Serialization safety, safe: 'InternalProto'
50+
// SAFETY-INTERNAL: Serialization safety, unsafe: 'InternalProto'
51+
// NO-SAFETY-INTERNAL: Serialization safety, unsafe: 'InternalProto'
5252
internal struct ExtendedInternal {}
5353
// SAFETY-INTERNAL: Serialization safety, unsafe: 'ExtendedInternal'
5454
// NO-SAFETY-INTERNAL: Serialization safety, safe: 'ExtendedInternal'
@@ -63,7 +63,7 @@ extension ExtendedInternal : InternalProto {}
6363

6464
/// Private
6565
private protocol PrivateProto {}
66-
// SAFETY-PRIVATE: Serialization safety, safe: 'PrivateProto'
66+
// SAFETY-PRIVATE: Serialization safety, unsafe: 'PrivateProto'
6767
private struct ExtendedPrivate {}
6868
// SAFETY-PRIVATE: Serialization safety, unsafe: 'ExtendedPrivate'
6969
extension ExtendedPrivate {
@@ -75,7 +75,7 @@ extension ExtendedPrivate : PrivateProto {}
7575

7676
/// Fileprivate
7777
private protocol FileprivateProto {}
78-
// SAFETY-PRIVATE: Serialization safety, safe: 'FileprivateProto'
78+
// SAFETY-PRIVATE: Serialization safety, unsafe: 'FileprivateProto'
7979
private struct ExtendedFileprivate {}
8080
// SAFETY-PRIVATE: Serialization safety, unsafe: 'ExtendedFileprivate'
8181
extension ExtendedFileprivate {
@@ -87,14 +87,14 @@ extension ExtendedFileprivate : FileprivateProto {}
8787

8888
/// Back to public
8989
extension ExtendedPublic : InternalProto {
90-
// SAFETY-INTERNAL: Serialization safety, safe: 'extension ExtendedPublic'
91-
// NO-SAFETY-INTERNAL: Serialization safety, safe: 'extension ExtendedPublic'
90+
// SAFETY-INTERNAL: Serialization safety, unsafe: 'extension ExtendedPublic'
91+
// NO-SAFETY-INTERNAL: Serialization safety, unsafe: 'extension ExtendedPublic'
9292
}
9393
extension ExtendedPublic : PrivateProto {
94-
// SAFETY-PRIVATE: Serialization safety, safe: 'extension ExtendedPublic'
94+
// SAFETY-PRIVATE: Serialization safety, unsafe: 'extension ExtendedPublic'
9595
}
9696
extension ExtendedPublic : FileprivateProto {
97-
// SAFETY-PRIVATE: Serialization safety, safe: 'extension ExtendedPublic'
97+
// SAFETY-PRIVATE: Serialization safety, unsafe: 'extension ExtendedPublic'
9898
}
9999

100100
extension ExtendedPublic {

0 commit comments

Comments
 (0)