Skip to content

Speculative PrintAsObjC crasher fix #38902

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions include/swift/AST/DiagnosticsClangImporter.def
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,20 @@ WARNING(import_multiple_mainactor_attr,none,

ERROR(module_map_not_found, none, "module map file '%0' not found", (StringRef))

//------------------------------------------------------------------------------
// MARK: PrintAsObjC
//------------------------------------------------------------------------------
// Included here only because the diagnostic below is hopefully temporary. If
// PrintAsObjC ever grows its own diagnostics for real, we should put them in
// their own file.

WARNING(objc_printing_unexpected_sort_tie,none,
"generated header file declaration order may change on recompile "
"because '@objc' %0 %1 unexpectedly cannot be sorted with respect to "
"other %0 %1; non-extensions should always be sortable, so please file "
"a bug report (" SWIFT_BUG_REPORT_URL ") containing the build log and, "
"if possible, the source code of your project",
(DescriptiveDeclKind, DeclName, DescriptiveDeclKind, DeclName))

#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
48 changes: 47 additions & 1 deletion lib/PrintAsObjC/ModuleContentsWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "DeclAndTypePrinter.h"

#include "swift/AST/DiagnosticsClangImporter.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/Module.h"
#include "swift/AST/PrettyStackTrace.h"
Expand All @@ -40,6 +41,37 @@ static bool isOSObjectType(const clang::Decl *decl) {
return !DeclAndTypePrinter::maybeGetOSObjectBaseName(named).empty();
}

/// Get a DeclName, or create a fake descriptive name. Used defensively in a
/// diagnostic below where we think we should have a ValueDecl but aren't sure.
static DeclName getOrInventName(Decl *D) {
assert(D && "decl not null");

if (auto *VD = dyn_cast<ValueDecl>(D))
return VD->getName();

// Generate a fake name that describes the location.
SmallString<32> baseName;
llvm::raw_svector_ostream baseNameOS(baseName);
baseNameOS << "__anonymous_";
do {
baseNameOS << Decl::getKindName(D->getKind()) << "_in_";

D = D->getDeclContext()->getInnermostDeclarationDeclContext();
assert(D && "decl not null");
} while (!isa<ValueDecl>(D)); // Will always eventually reach a ModuleDecl

auto parentName = cast<ValueDecl>(D)->getName();
baseNameOS << parentName.getBaseName();

ASTContext &ctx = D->getASTContext();
Identifier baseID = ctx.getIdentifier(baseName);

if (parentName.isSimpleName())
return DeclName(baseID);
else
return DeclName(ctx, baseID, parentName.getArgumentNames());
}

namespace {
class ReferencedTypeFinder : public TypeDeclFinder {
friend TypeDeclFinder;
Expand Down Expand Up @@ -510,12 +542,26 @@ class ModuleWriter {
return result;

// Prefer value decls to extensions.
assert(!(isa<ValueDecl>(*lhs) && isa<ValueDecl>(*rhs)));
if (isa<ValueDecl>(*lhs) && !isa<ValueDecl>(*rhs))
return Descending;
if (!isa<ValueDecl>(*lhs) && isa<ValueDecl>(*rhs))
return Ascending;

if (!isa<ExtensionDecl>(*lhs) || !isa<ExtensionDecl>(*rhs)) {
// In theory, only ExtensionDecls should still have a tie by this point.
// In practice, we've seen crashes which might be caused by other kinds
// of Decls reaching the code below (rdar://81811616) but we don't know
// how to reproduce them. Defensively check for this and recover with a
// warning or two.
(*lhs)->diagnose(diag::objc_printing_unexpected_sort_tie,
(*lhs)->getDescriptiveKind(), getOrInventName(*lhs),
(*rhs)->getDescriptiveKind(), getOrInventName(*rhs));
(*rhs)->diagnose(diag::objc_printing_unexpected_sort_tie,
(*rhs)->getDescriptiveKind(), getOrInventName(*rhs),
(*lhs)->getDescriptiveKind(), getOrInventName(*lhs));
return Equivalent;
}

// Break ties in extensions by putting smaller extensions last (in reverse
// order).
// FIXME: This will end up taking linear time.
Expand Down