Skip to content

Add all deserialization fatal output to the pretty stack trace #37743

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

Merged
merged 1 commit into from
Jun 4, 2021
Merged
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
8 changes: 0 additions & 8 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -792,14 +792,6 @@ ERROR(serialization_fatal,Fatal,
"fatal error encountered while reading from module '%0'; "
SWIFT_BUG_REPORT_MESSAGE,
(StringRef))
NOTE(serialization_misc_version,none,
"module '%0' full misc version is '%1'"
"%select{ (built while allowing compiler errors)|}2",
(StringRef, StringRef, bool))
NOTE(serialization_compatibility_version_mismatch,none,
"compiling as Swift %0, with '%1' built as Swift %2 "
"(this is supported but may expose additional compiler issues)",
(StringRef, StringRef, StringRef))

ERROR(serialization_invalid_decl,Fatal,
"deserialized invalid declaration %0 (%1) in module '%2'",
Expand Down
23 changes: 19 additions & 4 deletions lib/FrontendTool/FrontendTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Statistic.h"
#include "swift/Basic/UUID.h"
#include "swift/Basic/Version.h"
#include "swift/Option/Options.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/AccumulatingDiagnosticConsumer.h"
Expand Down Expand Up @@ -1953,6 +1954,23 @@ static void printTargetInfo(const CompilerInvocation &invocation,
out << "}\n";
}

/// A PrettyStackTraceEntry to print frontend information useful for debugging.
class PrettyStackTraceFrontend : public llvm::PrettyStackTraceEntry {
const LangOptions &LangOpts;

public:
PrettyStackTraceFrontend(const LangOptions &langOpts)
: LangOpts(langOpts) {}

void print(llvm::raw_ostream &os) const override {
auto effective = LangOpts.EffectiveLanguageVersion;
if (effective != version::Version::getCurrentLanguageVersion()) {
os << "Compiling with effective version " << effective;
}
os << "\n";
};
};

int swift::performFrontend(ArrayRef<const char *> Args,
const char *Argv0, void *MainAddr,
FrontendObserver *observer) {
Expand Down Expand Up @@ -2046,10 +2064,7 @@ int swift::performFrontend(ArrayRef<const char *> Args,
return finishDiagProcessing(1, /*verifierEnabled*/ false);
}

Optional<llvm::PrettyStackTraceString> allowErrorsStackTrace;
if (Invocation.getFrontendOptions().AllowModuleWithCompilerErrors)
allowErrorsStackTrace.emplace("While allowing modules with compiler errors "
"enabled");
PrettyStackTraceFrontend frontendTrace(Invocation.getLangOptions());

// Make an array of PrettyStackTrace objects to dump the configuration files
// we used to parse the arguments. These are RAII objects, so they and the
Expand Down
48 changes: 10 additions & 38 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@ using namespace swift;
using namespace swift::serialization;
using llvm::Expected;

StringRef swift::getNameOfModule(const ModuleFile *MF) {
return MF->getName();
}

namespace {
struct DeclAndOffset {
const Decl *D;
Expand Down Expand Up @@ -111,7 +107,7 @@ namespace {
os << DeclAndOffset{DeclOrOffset.get(), offset};
}
}
os << " in '" << getNameOfModule(MF) << "'\n";
os << " in '" << MF->getName() << "'\n";
}
};

Expand Down Expand Up @@ -166,33 +162,15 @@ static void skipRecord(llvm::BitstreamCursor &cursor, unsigned recordKind) {
(void)kind;
}

void ModuleFile::fatal(llvm::Error error) {
if (FileContext) {
getContext().Diags.diagnose(SourceLoc(), diag::serialization_fatal, Core->Name);
getContext().Diags.diagnose(
SourceLoc(), diag::serialization_misc_version, Core->Name,
Core->MiscVersion, allowCompilerErrors());

if (!Core->CompatibilityVersion.empty()) {
if (getContext().LangOpts.EffectiveLanguageVersion
!= Core->CompatibilityVersion) {
SmallString<16> effectiveVersionBuffer, compatVersionBuffer;
{
llvm::raw_svector_ostream out(effectiveVersionBuffer);
out << getContext().LangOpts.EffectiveLanguageVersion;
}
{
llvm::raw_svector_ostream out(compatVersionBuffer);
out << Core->CompatibilityVersion;
}
getContext().Diags.diagnose(
SourceLoc(), diag::serialization_compatibility_version_mismatch,
effectiveVersionBuffer, Core->Name, compatVersionBuffer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still have the information about the Swift language compatibility version of the module somewhere in the output? This note has been useful to me at least once to quickly explain a deserialization failure due to changes in ClangImporter behaviors between two Swift versions.

Copy link
Contributor Author

@bnbarham bnbarham Jun 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above re. the effective version, as an example output:

Stack dump:
0.	Program arguments: ......
1.	Swift version 5.5-dev (LLVM <hash>, Swift <hash>)
2.	Compiling with Swift version 5.5-dev effective-4.2 (LLVM <hash>, Swift <hash>)
3.	While evaluating request TypeCheckSourceFileRequest(source_file "<stdin>")
4.	While type-checking statement at [<stdin>:1:13 - line:1:21] RangeText="_ = Sub."
5.	While type-checking expression at [<stdin>:1:13 - line:1:21] RangeText="_ = Sub."
6.	While evaluating request QualifiedLookupRequest(0x7fa27c81ce00 TopLevelCodeDecl line=1, {Lib.(file).Sub}, 'disappearingMethod', { NL_ProtocolMembers, NL_RemoveNonVisible, NL_RemoveOverridden, NL_OnlyTypes })
7.	While evaluating request DirectLookupRequest(directly looking up 'disappearingMethod' on Lib.(file).Sub with options {  })
8.	While loading members for 'Sub' (in module 'Lib')
9.	*** DESERIALIZATION FAILURE ***
module 'Lib' with full misc version '5.5(4.1.50)/Swift version 5.5-dev (LLVM <hash>, Swift <hash>)'
could not find 'disappearingMethod()' in parent class

So here we can see the version being compiled is effective-4.2 (2.) and the module was compiled with (4.1.50) (9.)

}
}
}
void ModuleFile::fatal(llvm::Error error) const {
if (FileContext)
getContext().Diags.diagnose(SourceLoc(), diag::serialization_fatal,
Core->Name);
Core->fatal(std::move(error));
}

ModuleFileSharedCore::fatal(std::move(error));
void ModuleFile::outputDiagnosticInfo(llvm::raw_ostream &os) const {
Core->outputDiagnosticInfo(os);
}

static Optional<swift::AccessorKind>
Expand Down Expand Up @@ -6302,7 +6280,7 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
uint64_t contextData) {
using namespace decls_block;

PrettyStackTraceModuleFile traceModule("While reading from", *this);
PrettyStackTraceModuleFile traceModule(*this);
PrettyStackTraceConformance trace("finishing conformance for",
conformance);
++NumNormalProtocolConformancesCompleted;
Expand Down Expand Up @@ -6718,9 +6696,3 @@ Optional<ForeignAsyncConvention> ModuleFile::maybeReadForeignAsyncConvention() {
completionHandlerErrorFlagParamIndex,
errorFlagPolarity);
}

void serialization::PrettyStackTraceModuleFile::outputModuleBuildInfo(
raw_ostream &os) const {
if (MF.compiledAllowingCompilerErrors())
os << " (built while allowing compiler errors)";
}
18 changes: 7 additions & 11 deletions lib/Serialization/DeserializationErrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,15 @@
#ifndef SWIFT_SERIALIZATION_DESERIALIZATIONERRORS_H
#define SWIFT_SERIALIZATION_DESERIALIZATIONERRORS_H

#include "ModuleFile.h"
#include "ModuleFileSharedCore.h"
#include "ModuleFormat.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/Module.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/PrettyStackTrace.h"

namespace swift {
class ModuleFile;
class ModuleFileSharedCore;

StringRef getNameOfModule(const ModuleFile *);
StringRef getNameOfModule(const ModuleFileSharedCore *);

namespace serialization {

class XRefTracePath {
Expand Down Expand Up @@ -470,12 +466,10 @@ class PrettyStackTraceModuleFile : public llvm::PrettyStackTraceEntry {
: PrettyStackTraceModuleFile("While reading from", module) {}

void print(raw_ostream &os) const override {
os << Action << " \'" << getNameOfModule(&MF) << "'";
outputModuleBuildInfo(os);
os << Action << " ";
MF.outputDiagnosticInfo(os);
os << "\n";
}

void outputModuleBuildInfo(raw_ostream &os) const;
};

class PrettyStackTraceModuleFileCore : public llvm::PrettyStackTraceEntry {
Expand All @@ -485,7 +479,9 @@ class PrettyStackTraceModuleFileCore : public llvm::PrettyStackTraceEntry {
: MF(module) {}

void print(raw_ostream &os) const override {
os << "While reading from \'" << getNameOfModule(&MF) << "'\n";
os << "While reading from ";
MF.outputDiagnosticInfo(os);
os << "\n";
}
};

Expand Down
17 changes: 9 additions & 8 deletions lib/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ class ModuleFile
llvm::BitstreamCursor SILIndexCursor;
llvm::BitstreamCursor DeclMemberTablesCursor;

friend StringRef getNameOfModule(const ModuleFile *);

public:
static std::unique_ptr<llvm::MemoryBuffer> getModuleName(ASTContext &Ctx,
StringRef modulePath,
Expand Down Expand Up @@ -333,24 +331,27 @@ class ModuleFile
return issue;
}

/// Emits one last diagnostic, logs the error, and then aborts for the stack
/// trace.
LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error error);
void fatalIfNotSuccess(llvm::Error error) {
/// Emits one last diagnostic, adds the current module details and errors to
/// the pretty stack trace, and then aborts.
LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error error) const;
void fatalIfNotSuccess(llvm::Error error) const {
if (error)
fatal(std::move(error));
}
template <typename T> T fatalIfUnexpected(llvm::Expected<T> expected) {
template <typename T> T fatalIfUnexpected(llvm::Expected<T> expected) const {
if (expected)
return std::move(expected.get());
fatal(expected.takeError());
}

LLVM_ATTRIBUTE_NORETURN void fatal() {
LLVM_ATTRIBUTE_NORETURN void fatal() const {
fatal(llvm::make_error<llvm::StringError>(
"(see \"While...\" info below)", llvm::inconvertibleErrorCode()));
}

/// Outputs information useful for diagnostics to \p out
void outputDiagnosticInfo(llvm::raw_ostream &os) const;

ASTContext &getContext() const {
assert(FileContext && "no associated context yet");
return FileContext->getParentModule()->getASTContext();
Expand Down
32 changes: 24 additions & 8 deletions lib/Serialization/ModuleFileSharedCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,17 @@
#include "ModuleFileCoreTableInfo.h"
#include "BCReadingExtras.h"
#include "DeserializationErrors.h"
#include "swift/Basic/LangOptions.h"
#include "swift/Strings.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/PrettyStackTrace.h"

using namespace swift;
using namespace swift::serialization;
using namespace llvm::support;
using llvm::Expected;

StringRef swift::getNameOfModule(const ModuleFileSharedCore *MF) {
return MF->getName();
}

static bool checkModuleSignature(llvm::BitstreamCursor &cursor,
ArrayRef<unsigned char> signature) {
for (unsigned char byte : signature) {
Expand Down Expand Up @@ -472,13 +470,31 @@ std::string ModuleFileSharedCore::Dependency::getPrettyPrintedPath() const {
return output;
}

void ModuleFileSharedCore::fatal(llvm::Error error) {
logAllUnhandledErrors(std::move(error), llvm::errs(),
"\n*** DESERIALIZATION FAILURE (please include this "
"section in any bug report) ***\n");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good change but I feel nostalgic with the idea of losing the part the nobody read (please include this section in any bug report)!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the main issue is that most of the time the compiler output wouldn't even be seen - ie. there'd be a crash and it gets reported based on the crash log and not the output.

void ModuleFileSharedCore::fatal(llvm::Error error) const {
llvm::SmallString<0> errorStr;
llvm::raw_svector_ostream out(errorStr);

out << "*** DESERIALIZATION FAILURE ***\n";
outputDiagnosticInfo(out);
out << "\n";
if (error) {
handleAllErrors(std::move(error), [&](const llvm::ErrorInfoBase &ei) {
ei.log(out);
out << "\n";
});
}

llvm::PrettyStackTraceString trace(errorStr.c_str());
abort();
}

void ModuleFileSharedCore::outputDiagnosticInfo(llvm::raw_ostream &os) const {
os << "module '" << Name << "' with full misc version '" << MiscVersion
<< "'";
if (Bits.IsAllowModuleWithCompilerErrorsEnabled)
os << " (built with -experimental-allow-module-with-compiler-errors)";
}

ModuleFileSharedCore::~ModuleFileSharedCore() { }

std::unique_ptr<ModuleFileSharedCore::SerializedDeclTable>
Expand Down
9 changes: 6 additions & 3 deletions lib/Serialization/ModuleFileSharedCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,12 +371,12 @@ class ModuleFileSharedCore {

/// Emits one last diagnostic, logs the error, and then aborts for the stack
/// trace.
LLVM_ATTRIBUTE_NORETURN static void fatal(llvm::Error error);
void fatalIfNotSuccess(llvm::Error error) {
LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error error) const;
void fatalIfNotSuccess(llvm::Error error) const {
if (error)
fatal(std::move(error));
}
template <typename T> T fatalIfUnexpected(llvm::Expected<T> expected) {
template <typename T> T fatalIfUnexpected(llvm::Expected<T> expected) const {
if (expected)
return std::move(expected.get());
fatal(expected.takeError());
Expand Down Expand Up @@ -508,6 +508,9 @@ class ModuleFileSharedCore {
return info;
}

/// Outputs information useful for diagnostics to \p out
void outputDiagnosticInfo(llvm::raw_ostream &os) const;

// Out of line to avoid instantiation OnDiskChainedHashTable here.
~ModuleFileSharedCore();

Expand Down
1 change: 1 addition & 0 deletions test/Frontend/crash-in-user-code.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// CHECK: Stack dump:
// CHECK-NEXT: Program arguments:
// CHECK-NEXT: Swift version
// CHECK-NEXT: Compiling with effective version
// CHECK-NEXT: Contents of {{.*}}.filelist.txt:
// CHECK-NEXT: ---
// CHECK-NEXT: crash-in-user-code.swift
Expand Down
7 changes: 4 additions & 3 deletions test/Frontend/crash.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
// RUN: not --crash %target-swift-frontend -typecheck -debug-crash-after-parse -filelist %t.filelist.txt 2>&1 | %FileCheck %s

// Check that we see the contents of the input file list in the crash log.
// CHECK-NOT: Compiling with {{.*}} while allowing modules with compiler errors enabled
// CHECK-LABEL: Stack dump
// CHECK-NEXT: Program arguments: {{.*swift(-frontend)?(c?)(\.exe)?}}
// CHECK-NEXT: Swift version
// CHECK-NEXT: Compiling with effective version
// CHECK-NEXT: Contents of {{.*}}.filelist.txt:
// CHECK-NEXT: ---
// CHECK-NEXT: test{{[\\/]}}Frontend{{[\\/]}}crash.swift{{$}}
// CHECK-NEXT: ---

// Check that a message when allowing errors is output
// RUN: not --crash %target-swift-frontend -typecheck -debug-crash-after-parse -experimental-allow-module-with-compiler-errors %s 2>&1 | %FileCheck -check-prefix CHECK-ALLOW %s
// CHECK-ALLOW-LABEL: Stack dump
// CHECK-ALLOW: While allowing modules with compiler errors enabled
// CHECK-ALLOW: Program arguments: {{.*}} -experimental-allow-module-with-compiler-errors
// CHECK-ALLOW: Compiling with effective version

func anchor() {}
anchor()
Expand Down
16 changes: 0 additions & 16 deletions test/Serialization/AllowErrors/crash-adds-message.swift

This file was deleted.

10 changes: 5 additions & 5 deletions test/Serialization/Recovery/crash-recovery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public class Sub: Base {
}

// CHECK-CRASH: error: fatal error encountered while reading from module 'Lib'; please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project
// CHECK-CRASH: note: module 'Lib' full misc version is
// CHECK-CRASH-4-NOT: note: compiling as
// CHECK-CRASH-4_2: note: compiling as Swift 4.2, with 'Lib' built as Swift 4.1.50
// CHECK-CRASH-LABEL: *** DESERIALIZATION FAILURE (please include this section in any bug report) ***
// CHECK-CRASH: could not find 'disappearingMethod()' in parent class
// CHECK-CRASH-4: Compiling with effective version 4.1.50
// CHECK-CRASH-4_2: Compiling with effective version 4.2
// CHECK-CRASH: While loading members for 'Sub' (in module 'Lib')
// CHECK-CRASH-LABEL: *** DESERIALIZATION FAILURE ***
// CHECK-CRASH: module 'Lib' with full misc version {{.*}}4.1.50
// CHECK-CRASH: could not find 'disappearingMethod()' in parent class
Loading