Skip to content

Commit 7cb9e5a

Browse files
committed
[Serialization] Fix deserializing opaque types for computed properties and subscripts
A client shouldn't know about the underlying type of an opaque type unless it can see the body of the naming decl. Attempting to read it can lead to accessing a hidden dependency and a compiler crash. This was protected by a check specific to function decls that left out var decls and subscripts. Fix this hole with a new service checking for inlinable attributes directly. rdar://117607906
1 parent 41dc466 commit 7cb9e5a

File tree

4 files changed

+80
-4
lines changed

4 files changed

+80
-4
lines changed

include/swift/AST/Decl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3294,6 +3294,14 @@ class OpaqueTypeDecl final :
32943294
};
32953295
}
32963296

3297+
/// Should we consider the underlying type as visible to clients outside of
3298+
/// the module?
3299+
///
3300+
/// This is used during deserialization to determine if this information
3301+
/// can be read reliably. We should be careful to what data is accessed by
3302+
/// this service as \c this may not be fully consistent.
3303+
bool exportUnderylingTypeToClients() const;
3304+
32973305
/// The substitutions that map the generic parameters of the opaque type to
32983306
/// the unique underlying types, when that information is known.
32993307
llvm::Optional<SubstitutionMap> getUniqueUnderlyingTypeSubstitutions() const {

lib/AST/Decl.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9464,6 +9464,25 @@ GenericTypeParamDecl *OpaqueTypeDecl::getExplicitGenericParam(
94649464
return genericParamType->getDecl();
94659465
}
94669466

9467+
bool OpaqueTypeDecl::exportUnderylingTypeToClients() const {
9468+
auto mod = getDeclContext()->getParentModule();
9469+
if (mod->getResilienceStrategy() != ResilienceStrategy::Resilient)
9470+
return true;
9471+
9472+
ValueDecl *namingDecl = getNamingDecl();
9473+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(namingDecl)) {
9474+
return AFD->getResilienceExpansion() == ResilienceExpansion::Minimal;
9475+
9476+
} else if (auto *ASD = dyn_cast<AbstractStorageDecl>(namingDecl)) {
9477+
return !ASD->isResilient();
9478+
9479+
} else {
9480+
llvm_unreachable("The naming decl is expected to be either an AFD or ASD");
9481+
}
9482+
9483+
return false;
9484+
}
9485+
94679486
llvm::Optional<unsigned>
94689487
OpaqueTypeDecl::getAnonymousOpaqueParamOrdinal(TypeRepr *repr) const {
94699488
assert(NamingDeclAndHasOpaqueReturnTypeRepr.getInt() &&

lib/Serialization/Deserialization.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4244,14 +4244,17 @@ class DeclDeserializer {
42444244
else
42454245
opaqueDecl->setGenericSignature(GenericSignature());
42464246

4247-
auto *AFD = dyn_cast<AbstractFunctionDecl>(namingDecl);
4248-
if (MF.getResilienceStrategy() == ResilienceStrategy::Resilient &&
4249-
!MF.FileContext->getParentModule()->isMainModule() &&
4250-
AFD && AFD->getResilienceExpansion() != ResilienceExpansion::Minimal) {
4247+
if (!MF.FileContext->getParentModule()->isMainModule() &&
4248+
!opaqueDecl->exportUnderylingTypeToClients()) {
42514249
// Do not try to read the underlying type information if the function
42524250
// is not inlinable in clients. This reflects the swiftinterface behavior
42534251
// in where clients are only aware of the underlying type when the body
42544252
// of the function is public.
4253+
LLVM_DEBUG(
4254+
llvm::dbgs() << "Ignoring underlying information for opaque type of '";
4255+
llvm::dbgs() << namingDecl->getName();
4256+
llvm::dbgs() << "'\n";
4257+
);
42554258

42564259
} else if (underlyingTypeSubsID) {
42574260
auto subMapOrError = MF.getSubstitutionMapChecked(underlyingTypeSubsID);

test/Serialization/Safety/skip-reading-internal-details.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@
6868
// SAFE: Skipping unsafe deserialization: 'fileprivateFunc()'
6969
// SAFE: Skipping unsafe deserialization: 'refToIOI()'
7070

71+
/// Always skip opaque return type underlying information when non-inlinable.
72+
// NEEDED: Ignoring underlying information for opaque type of 'opaqueReferencingPrivate()'
73+
// NEEDED: Ignoring underlying information for opaque type of 'opaqueReferencingPrivateVar'
74+
// NEEDED: Ignoring underlying information for opaque type of 'subscript(_:)'
75+
// NEEDED: Ignoring underlying information for opaque type of 'inlinableOpaqueVar'
76+
// NEEDED: Ignoring underlying information for opaque type of 'inlinableOpaqueVarPattern'
77+
// NEEDED-NOT: Ignoring underlying information for opaque type of
78+
7179
//--- HiddenLib.swift
7280

7381
public struct HiddenStruct {
@@ -113,6 +121,34 @@ public extension V {
113121
}
114122

115123
private func referencedPrivateFunc(v: some V) -> some V { return v }
124+
125+
var opaqueReferencingPrivateVar: some V {
126+
referencedPrivateFunc(v: EV())
127+
}
128+
129+
subscript(v: some V) -> some V {
130+
referencedPrivateFunc(v: v)
131+
}
132+
133+
@inlinable
134+
func inlinableOpaqueFunc() -> some V { EV() }
135+
136+
@backDeployed(before: SwiftStdlib 5.1)
137+
func backdeployedOpaqueFunc() -> some V { EV() }
138+
139+
@_alwaysEmitIntoClient
140+
func aeicOpaqueFunc() -> some V { EV() }
141+
142+
@_transparent
143+
func transparentOpaqueFunc() -> some V { EV() }
144+
145+
@inlinable
146+
var inlinableOpaqueVar: some V { EV() }
147+
148+
var inlinableOpaqueVarPattern: some V {
149+
@inlinable
150+
get { EV() }
151+
}
116152
}
117153

118154
//--- Client.swift
@@ -127,4 +163,14 @@ x.notAMember() // expected-error {{value of type 'PublicStruct' has no member 'n
127163
if #available(SwiftStdlib 5.1, *) {
128164
let v = EV()
129165
let _ = v.opaqueReferencingPrivate()
166+
let _ = v.opaqueReferencingPrivateVar
167+
let _ = v[v]
168+
169+
let _ = v.inlinableOpaqueFunc()
170+
let _ = v.backdeployedOpaqueFunc()
171+
let _ = v.aeicOpaqueFunc()
172+
let _ = v.transparentOpaqueFunc()
173+
174+
let _ = v.inlinableOpaqueVar
175+
let _ = v.inlinableOpaqueVarPattern
130176
}

0 commit comments

Comments
 (0)