|
70 | 70 |
|
71 | 71 | #include <vector>
|
72 | 72 |
|
| 73 | +#define DEBUG_TYPE "Serialization" |
| 74 | + |
73 | 75 | using namespace swift;
|
74 | 76 | using namespace swift::serialization;
|
75 | 77 | using namespace llvm::support;
|
@@ -3093,6 +3095,170 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
|
3093 | 3095 | }
|
3094 | 3096 | }
|
3095 | 3097 |
|
| 3098 | + /// Determine if \p decl is safe to deserialize when it's public |
| 3099 | + /// or otherwise needed by the client in normal builds, this should usually |
| 3100 | + /// correspond to logic in type-checking ensuring these safe decls don't |
| 3101 | + /// refer to implementation details. We have to be careful not to mark |
| 3102 | + /// anything needed by a client as unsafe as the client will reject reading |
| 3103 | + /// it, but at the same time keep the safety checks precise to avoid |
| 3104 | + /// XRef errors and such. |
| 3105 | + /// |
| 3106 | + /// \p decl should be either an \c ExtensionDecl or a \c ValueDecl. |
| 3107 | + static bool isDeserializationSafe(const Decl *decl) { |
| 3108 | + if (auto ext = dyn_cast<ExtensionDecl>(decl)) { |
| 3109 | + // Consider extensions as safe as their extended type. |
| 3110 | + auto nominalType = ext->getExtendedNominal(); |
| 3111 | + if (!nominalType || |
| 3112 | + !isDeserializationSafe(nominalType)) |
| 3113 | + return false; |
| 3114 | + |
| 3115 | + // We can mark the extension unsafe only if it has no public members. |
| 3116 | + auto members = ext->getMembers(); |
| 3117 | + auto hasSafeMembers = std::any_of(members.begin(), members.end(), |
| 3118 | + [](const Decl *D) -> bool { |
| 3119 | + if (auto VD = dyn_cast<ValueDecl>(D)) |
| 3120 | + return isDeserializationSafe(VD); |
| 3121 | + return true; |
| 3122 | + }); |
| 3123 | + if (hasSafeMembers) |
| 3124 | + return true; |
| 3125 | + |
| 3126 | + // We can mark the extension unsafe only if it has no public |
| 3127 | + // conformances. |
| 3128 | + auto protocols = ext->getLocalProtocols( |
| 3129 | + ConformanceLookupKind::OnlyExplicit); |
| 3130 | + bool hasSafeConformances = std::any_of(protocols.begin(), |
| 3131 | + protocols.end(), |
| 3132 | + isDeserializationSafe); |
| 3133 | + if (hasSafeConformances) |
| 3134 | + return true; |
| 3135 | + |
| 3136 | + // Truly empty extensions are safe, it may happen in swiftinterfaces. |
| 3137 | + if (members.empty() && protocols.size() == 0) |
| 3138 | + return true; |
| 3139 | + |
| 3140 | + return false; |
| 3141 | + } |
| 3142 | + |
| 3143 | + auto value = cast<ValueDecl>(decl); |
| 3144 | + |
| 3145 | + // A decl is safe if formally accessible publicly. |
| 3146 | + auto accessScope = value->getFormalAccessScope(/*useDC=*/nullptr, |
| 3147 | + /*treatUsableFromInlineAsPublic=*/true); |
| 3148 | + if (accessScope.isPublic()) |
| 3149 | + return true; |
| 3150 | + |
| 3151 | + // Testable allows access to internal details. |
| 3152 | + if (value->getDeclContext()->getParentModule()->isTestingEnabled() && |
| 3153 | + accessScope.isInternal()) |
| 3154 | + return true; |
| 3155 | + |
| 3156 | + if (auto accessor = dyn_cast<AccessorDecl>(value)) |
| 3157 | + // Accessors are as safe as their storage. |
| 3158 | + if (isDeserializationSafe(accessor->getStorage())) |
| 3159 | + return true; |
| 3160 | + |
| 3161 | + // Frozen fields are always safe. |
| 3162 | + if (auto var = dyn_cast<VarDecl>(value)) { |
| 3163 | + if (var->isLayoutExposedToClients()) |
| 3164 | + return true; |
| 3165 | + |
| 3166 | + // Consider all lazy var storage as "safe". |
| 3167 | + // FIXME: We should keep track of what lazy var is associated to the |
| 3168 | + // storage for them to preserve the same safeness. |
| 3169 | + if (var->isLazyStorageProperty()) |
| 3170 | + return true; |
| 3171 | + |
| 3172 | + // Property wrappers storage is as safe as the wrapped property. |
| 3173 | + if (VarDecl *wrapped = var->getOriginalWrappedProperty()) |
| 3174 | + if (isDeserializationSafe(wrapped)) |
| 3175 | + return true; |
| 3176 | + } |
| 3177 | + |
| 3178 | + return false; |
| 3179 | + } |
| 3180 | + |
| 3181 | + /// Write a \c DeserializationSafetyLayout record only when \p decl is unsafe |
| 3182 | + /// to deserialize. |
| 3183 | + /// |
| 3184 | + /// \sa isDeserializationSafe |
| 3185 | + void writeDeserializationSafety(const Decl *decl) { |
| 3186 | + using namespace decls_block; |
| 3187 | + |
| 3188 | + auto DC = decl->getDeclContext(); |
| 3189 | + if (!DC->getParentModule()->isResilient()) |
| 3190 | + return; |
| 3191 | + |
| 3192 | + // Everything should be safe in a swiftinterface. So, don't emit any safety |
| 3193 | + // record when building a swiftinterface in release builds. Debug builds |
| 3194 | + // instead print inconsistencies. |
| 3195 | + auto parentSF = DC->getParentSourceFile(); |
| 3196 | + bool fromModuleInterface = parentSF && |
| 3197 | + parentSF->Kind == SourceFileKind::Interface; |
| 3198 | +#if NDEBUG |
| 3199 | + if (fromModuleInterface) |
| 3200 | + return; |
| 3201 | +#endif |
| 3202 | + |
| 3203 | + // Private imports allow safe access to everything. |
| 3204 | + if (DC->getParentModule()->arePrivateImportsEnabled()) |
| 3205 | + return; |
| 3206 | + |
| 3207 | + // Ignore things with no access level. |
| 3208 | + // Note: There's likely room to report some of these as unsafe to prevent |
| 3209 | + // failures. |
| 3210 | + if (isa<GenericTypeParamDecl>(decl) || |
| 3211 | + isa<OpaqueTypeDecl>(decl) || |
| 3212 | + isa<ParamDecl>(decl) || |
| 3213 | + isa<EnumCaseDecl>(decl) || |
| 3214 | + isa<EnumElementDecl>(decl)) |
| 3215 | + return; |
| 3216 | + |
| 3217 | + if (!isa<ValueDecl>(decl) && !isa<ExtensionDecl>(decl)) |
| 3218 | + return; |
| 3219 | + |
| 3220 | + // Don't look at decls inside functions and |
| 3221 | + // check the ValueDecls themselves. |
| 3222 | + auto declIsSafe = DC->isLocalContext() || |
| 3223 | + isDeserializationSafe(decl); |
| 3224 | +#ifdef NDEBUG |
| 3225 | + // In release builds, bail right away if the decl is safe. |
| 3226 | + // In debug builds, wait to bail after the debug prints and asserts. |
| 3227 | + if (declIsSafe) |
| 3228 | + return; |
| 3229 | +#endif |
| 3230 | + |
| 3231 | + // Write a human readable name to an identifier. |
| 3232 | + SmallString<64> out; |
| 3233 | + llvm::raw_svector_ostream outStream(out); |
| 3234 | + if (auto val = dyn_cast<ValueDecl>(decl)) { |
| 3235 | + outStream << val->getName(); |
| 3236 | + } else if (auto ext = dyn_cast<ExtensionDecl>(decl)) { |
| 3237 | + outStream << "extension "; |
| 3238 | + if (auto nominalType = ext->getExtendedNominal()) |
| 3239 | + outStream << nominalType->getName(); |
| 3240 | + } |
| 3241 | + auto name = S.getASTContext().getIdentifier(out); |
| 3242 | + |
| 3243 | + LLVM_DEBUG( |
| 3244 | + llvm::dbgs() << "Serialization safety, " |
| 3245 | + << (declIsSafe? "safe" : "unsafe") |
| 3246 | + << ": '" << name << "'\n"; |
| 3247 | + assert((declIsSafe || !fromModuleInterface) && |
| 3248 | + "All swiftinterface decls should be deserialization safe"); |
| 3249 | + ); |
| 3250 | + |
| 3251 | +#ifndef NDEBUG |
| 3252 | + // Bail out here in debug builds, release builds would bailed out earlier. |
| 3253 | + if (declIsSafe) |
| 3254 | + return; |
| 3255 | +#endif |
| 3256 | + |
| 3257 | + auto abbrCode = S.DeclTypeAbbrCodes[DeserializationSafetyLayout::Code]; |
| 3258 | + DeserializationSafetyLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, |
| 3259 | + S.addDeclBaseNameRef(name)); |
| 3260 | + } |
| 3261 | + |
3096 | 3262 | void writeForeignErrorConvention(const ForeignErrorConvention &fec) {
|
3097 | 3263 | using namespace decls_block;
|
3098 | 3264 |
|
@@ -3410,6 +3576,8 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
|
3410 | 3576 | if (D->isInvalid())
|
3411 | 3577 | writeDeclErrorFlag();
|
3412 | 3578 |
|
| 3579 | + writeDeserializationSafety(D); |
| 3580 | + |
3413 | 3581 | // Emit attributes (if any).
|
3414 | 3582 | for (auto Attr : D->getAttrs())
|
3415 | 3583 | writeDeclAttribute(D, Attr);
|
|
0 commit comments