Skip to content

Commit bdbf042

Browse files
authored
Merge pull request swiftlang#38833 from apple/cherry-crash-fixes
[5.5] Fix serialization crashes found from stress tester
2 parents e84be85 + 7539947 commit bdbf042

File tree

4 files changed

+53
-14
lines changed

4 files changed

+53
-14
lines changed

lib/Serialization/Serialization.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,8 +2029,10 @@ void Serializer::writePatternBindingInitializer(PatternBindingDecl *binding,
20292029
StringRef initStr;
20302030
SmallString<128> scratch;
20312031
auto varDecl = binding->getAnchoringVarDecl(bindingIndex);
2032+
assert((varDecl || allowCompilerErrors()) &&
2033+
"Serializing PDB without anchoring VarDecl");
20322034
if (binding->hasInitStringRepresentation(bindingIndex) &&
2033-
varDecl->isInitExposedToClients()) {
2035+
varDecl && varDecl->isInitExposedToClients()) {
20342036
initStr = binding->getInitStringRepresentation(bindingIndex, scratch);
20352037
}
20362038

@@ -3929,9 +3931,6 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
39293931
using namespace decls_block;
39303932
verifyAttrSerializable(dtor);
39313933

3932-
if (S.allowCompilerErrors() && dtor->isInvalid())
3933-
return;
3934-
39353934
auto contextID = S.addDeclContextRef(dtor->getDeclContext());
39363935

39373936
unsigned abbrCode = S.DeclTypeAbbrCodes[DestructorLayout::Code];
@@ -3973,12 +3972,34 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
39733972
}
39743973
};
39753974

3975+
/// When allowing modules with errors there may be cases where there's little
3976+
/// point in serializing a declaration and doing so would create a maintenance
3977+
/// burden on the deserialization side. Returns \c true if the given declaration
3978+
/// should be skipped and \c false otherwise.
3979+
static bool canSkipWhenInvalid(const Decl *D) {
3980+
// There's no point writing out the deinit when its context is not a class
3981+
// as nothing would be able to reference it
3982+
if (auto *deinit = dyn_cast<DestructorDecl>(D)) {
3983+
if (!isa<ClassDecl>(D->getDeclContext()))
3984+
return true;
3985+
}
3986+
return false;
3987+
}
3988+
39763989
void Serializer::writeASTBlockEntity(const Decl *D) {
39773990
using namespace decls_block;
39783991

39793992
PrettyStackTraceDecl trace("serializing", D);
39803993
assert(DeclsToSerialize.hasRef(D));
39813994

3995+
if (D->isInvalid()) {
3996+
assert(allowCompilerErrors() &&
3997+
"cannot create a module with an invalid decl");
3998+
3999+
if (canSkipWhenInvalid(D))
4000+
return;
4001+
}
4002+
39824003
BitOffset initialOffset = Out.GetCurrentBitNo();
39834004
SWIFT_DEFER {
39844005
// This is important enough to leave on in Release builds.
@@ -3988,8 +4009,6 @@ void Serializer::writeASTBlockEntity(const Decl *D) {
39884009
}
39894010
};
39904011

3991-
assert((allowCompilerErrors() || !D->isInvalid()) &&
3992-
"cannot create a module with an invalid decl");
39934012
if (isDeclXRef(D)) {
39944013
writeCrossReference(D);
39954014
return;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// Serialize and deserialize a deinit with SourceFile context to make sure we
4+
// don't crash
5+
// RUN: %target-swift-frontend -verify -module-name errors -emit-module -o %t/errors.swiftmodule -experimental-allow-module-with-compiler-errors %s
6+
// RUN: %target-swift-ide-test -print-module -module-to-print=errors -source-filename=x -I %t -allow-compiler-errors
7+
8+
// Also check it wasn't serialized
9+
// RUN: llvm-bcanalyzer -dump %t/errors.swiftmodule | %FileCheck %s
10+
// CHECK-NOT: DESTRUCTOR_DECL
11+
12+
struct Foo {}
13+
14+
@discardableResult // expected-error{{'@discardableResult' attribute cannot be applied to this declaration}}
15+
deinit {} // expected-error{{deinitializers may only be declared within a class}}
16+
17+
func foo() -> Foo { return Foo() }
18+
19+
// Make sure @discardableResult isn't added to `foo`, which could be possible
20+
// if the deinit is partially serialized
21+
foo() // expected-warning{{result of call to 'foo()' is unused}}

validation-test/Serialization/AllowErrors/invalid-deinit.swift

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// -parse-as-library added so that the PDB isn't added to a TopLevelCodeDecl,
4+
// which isn't serialized at all
5+
// RUN: %target-swift-frontend -emit-module -o %t/errors.swiftmodule -module-name errors -experimental-allow-module-with-compiler-errors -parse-as-library %s
6+
7+
let self = 1

0 commit comments

Comments
 (0)