[clang] 5fd03b0 - [Driver] Re-run lld with --reproduce when it crashes
Alex Brachet via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 1 13:01:10 PDT 2022
Author: Alex Brachet
Date: 2022-08-01T20:01:01Z
New Revision: 5fd03b00ee029b4cc958ae8e6c970a6123bd12f6
URL: https://github.com/llvm/llvm-project/commit/5fd03b00ee029b4cc958ae8e6c970a6123bd12f6
DIFF: https://github.com/llvm/llvm-project/commit/5fd03b00ee029b4cc958ae8e6c970a6123bd12f6.diff
LOG: [Driver] Re-run lld with --reproduce when it crashes
This was discussed on https://discourse.llvm.org/t/rfc-generating-lld-reproducers-on-crashes/58071/12
When lld crashes, or errors when -gen-reproducer=error
and -fcrash-diagnostics=all clang will re-run lld with
--reproduce=$temp_file for easily reproducing the
crash/error.
Differential Revision: https://reviews.llvm.org/D120175
Added:
clang/test/Driver/lld-repro.c
Modified:
clang/docs/UsersManual.rst
clang/include/clang/Driver/Compilation.h
clang/include/clang/Driver/Driver.h
clang/include/clang/Driver/Options.td
clang/lib/Driver/Driver.cpp
clang/test/Driver/crash-report.cpp
clang/test/Driver/lit.local.cfg
Removed:
################################################################################
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 1d11b00a1a78d..15df488e802de 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -667,6 +667,14 @@ a crash. These files should be attached to a bug report to ease
reproducibility of the failure. Below are the command line options to
control the crash diagnostics.
+.. option:: -fcrash-diagnostics=<val>
+
+ Valid values are:
+
+ * ``off`` (Disable auto-generation of preprocessed source files during a clang crash.)
+ * ``compiler`` (Generate diagnostics for compiler crashes (default))
+ * ``all`` (Generate diagnostics for all tools which support it)
+
.. option:: -fno-crash-diagnostics
Disable auto-generation of preprocessed source files during a clang crash.
diff --git a/clang/include/clang/Driver/Compilation.h b/clang/include/clang/Driver/Compilation.h
index c5714d3208884..842efda9f0774 100644
--- a/clang/include/clang/Driver/Compilation.h
+++ b/clang/include/clang/Driver/Compilation.h
@@ -216,6 +216,7 @@ class Compilation {
void addCommand(std::unique_ptr<Command> C) { Jobs.addJob(std::move(C)); }
+ llvm::opt::ArgStringList &getTempFiles() { return TempFiles; }
const llvm::opt::ArgStringList &getTempFiles() const { return TempFiles; }
const ArgStringMap &getResultFiles() const { return ResultFiles; }
diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index 0781d476ec4a0..59c2f1f52cecf 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -600,6 +600,11 @@ class Driver {
/// Returns the default name for linked images (e.g., "a.out").
const char *getDefaultImageName() const;
+ // Creates a temp file with $Prefix-%%%%%%.$Suffix
+ const char *CreateTempFile(Compilation &C, StringRef Prefix, StringRef Suffix,
+ bool MultipleArchs = false,
+ StringRef BoundArch = {}) const;
+
/// GetNamedOutputPath - Return the name to use for the output of
/// the action \p JA. The result is appended to the compilation's
/// list of temporary or result files, as appropriate.
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 1718234a56988..3312f999a33f7 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1433,6 +1433,10 @@ def fexperimental_new_constant_interpreter : Flag<["-"], "fexperimental-new-cons
MarshallingInfoFlag<LangOpts<"EnableNewConstInterp">>;
def fconstexpr_backtrace_limit_EQ : Joined<["-"], "fconstexpr-backtrace-limit=">,
Group<f_Group>;
+def fcrash_diagnostics_EQ : Joined<["-"], "fcrash-diagnostics=">, Group<f_clang_Group>, Flags<[NoArgumentUnused, CoreOption]>,
+ HelpText<"Set level of crash diagnostic reporting, (option: off, compiler, all)">;
+def fcrash_diagnostics : Flag<["-"], "fcrash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused, CoreOption]>,
+ HelpText<"Enable crash diagnostic reporting (default)">, Alias<fcrash_diagnostics_EQ>, AliasArgs<["compiler"]>;
def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused, CoreOption]>,
Alias<gen_reproducer_eq>, AliasArgs<["off"]>,
HelpText<"Disable auto-generation of preprocessed source files and a script for reproduction during a clang crash">;
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 3f29afd359718..7c727ba65ada6 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -1507,11 +1507,36 @@ void Driver::generateCompilationDiagnostics(
if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics))
return;
- // Don't try to generate diagnostics for link or dsymutil jobs.
- if (FailingCommand.getCreator().isLinkJob() ||
- FailingCommand.getCreator().isDsymutilJob())
+ unsigned Level = 1;
+ if (Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_EQ)) {
+ Level = llvm::StringSwitch<unsigned>(A->getValue())
+ .Case("off", 0)
+ .Case("compiler", 1)
+ .Case("all", 2)
+ .Default(1);
+ }
+ if (!Level)
return;
+ // Don't try to generate diagnostics for dsymutil jobs.
+ if (FailingCommand.getCreator().isDsymutilJob())
+ return;
+
+ bool IsLLD = false;
+ ArgStringList SavedTemps;
+ if (FailingCommand.getCreator().isLinkJob()) {
+ C.getDefaultToolChain().GetLinkerPath(&IsLLD);
+ if (!IsLLD || Level < 2)
+ return;
+
+ // If lld crashed, we will re-run the same command with the input it used
+ // to have. In that case we should not remove temp files in
+ // initCompilationForDiagnostics yet. They will be added back and removed
+ // later.
+ SavedTemps = std::move(C.getTempFiles());
+ assert(!C.getTempFiles().size());
+ }
+
// Print the version of the compiler.
PrintVersion(C, llvm::errs());
@@ -1605,6 +1630,18 @@ void Driver::generateCompilationDiagnostics(
return;
}
+ // If lld failed, rerun it again with --reproduce.
+ if (IsLLD) {
+ const char *TmpName = CreateTempFile(C, "linker-crash", "tar");
+ Command NewLLDInvocation = Cmd;
+ llvm::opt::ArgStringList ArgList = NewLLDInvocation.getArguments();
+ ArgList.push_back(Saver.save(Twine{"--reproduce="} + TmpName).data());
+ NewLLDInvocation.replaceArguments(std::move(ArgList));
+
+ // Redirect stdout/stderr to /dev/null.
+ NewLLDInvocation.Execute({None, {""}, {""}}, nullptr, nullptr);
+ }
+
const ArgStringList &TempFiles = C.getTempFiles();
if (TempFiles.empty()) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
@@ -1635,6 +1672,9 @@ void Driver::generateCompilationDiagnostics(
}
}
+ for (const char *TempFile : SavedTemps)
+ C.addTempFile(TempFile);
+
// Assume associated files are based off of the first temporary file.
CrashReportInfo CrashInfo(TempFiles[0], VFS);
@@ -5554,6 +5594,35 @@ static bool HasPreprocessOutput(const Action &JA) {
return false;
}
+const char *Driver::CreateTempFile(Compilation &C, StringRef Prefix,
+ StringRef Suffix, bool MultipleArchs,
+ StringRef BoundArch) const {
+ SmallString<128> TmpName;
+ Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir);
+ if (CCGenDiagnostics && A) {
+ SmallString<128> CrashDirectory(A->getValue());
+ if (!getVFS().exists(CrashDirectory))
+ llvm::sys::fs::create_directories(CrashDirectory);
+ llvm::sys::path::append(CrashDirectory, Prefix);
+ const char *Middle = !Suffix.empty() ? "-%%%%%%." : "-%%%%%%";
+ std::error_code EC = llvm::sys::fs::createUniqueFile(
+ CrashDirectory + Middle + Suffix, TmpName);
+ if (EC) {
+ Diag(clang::diag::err_unable_to_make_temp) << EC.message();
+ return "";
+ }
+ } else {
+ if (MultipleArchs && !BoundArch.empty()) {
+ TmpName = GetTemporaryDirectory(Prefix);
+ llvm::sys::path::append(TmpName,
+ Twine(Prefix) + "-" + BoundArch + "." + Suffix);
+ } else {
+ TmpName = GetTemporaryPath(Prefix, Suffix);
+ }
+ }
+ return C.addTempFile(C.getArgs().MakeArgString(TmpName));
+}
+
const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
const char *BaseInput,
StringRef OrigBoundArch, bool AtTopLevel,
@@ -5613,31 +5682,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
CCGenDiagnostics) {
StringRef Name = llvm::sys::path::filename(BaseInput);
std::pair<StringRef, StringRef> Split = Name.split('.');
- SmallString<128> TmpName;
const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode());
- Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir);
- if (CCGenDiagnostics && A) {
- SmallString<128> CrashDirectory(A->getValue());
- if (!getVFS().exists(CrashDirectory))
- llvm::sys::fs::create_directories(CrashDirectory);
- llvm::sys::path::append(CrashDirectory, Split.first);
- const char *Middle = Suffix ? "-%%%%%%." : "-%%%%%%";
- std::error_code EC = llvm::sys::fs::createUniqueFile(
- CrashDirectory + Middle + Suffix, TmpName);
- if (EC) {
- Diag(clang::diag::err_unable_to_make_temp) << EC.message();
- return "";
- }
- } else {
- if (MultipleArchs && !BoundArch.empty()) {
- TmpName = GetTemporaryDirectory(Split.first);
- llvm::sys::path::append(TmpName,
- Split.first + "-" + BoundArch + "." + Suffix);
- } else {
- TmpName = GetTemporaryPath(Split.first, Suffix);
- }
- }
- return C.addTempFile(C.getArgs().MakeArgString(TmpName));
+ return CreateTempFile(C, Split.first, Suffix, MultipleArchs, BoundArch);
}
SmallString<128> BasePath(BaseInput);
diff --git a/clang/test/Driver/crash-report.cpp b/clang/test/Driver/crash-report.cpp
index 7da94885080be..455597c9c0fc7 100644
--- a/clang/test/Driver/crash-report.cpp
+++ b/clang/test/Driver/crash-report.cpp
@@ -27,6 +27,29 @@
// RUN: cat %t/crash-report-*.cpp | FileCheck --check-prefix=CHECKSRC %s
// RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s
+// Test manually specifying -fcrash-diagnostics[=[compiler|all]] emits
+// diagnostics
+// RUN: env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 \
+// RUN: CC_PRINT_HEADERS=1 CC_LOG_DIAGNOSTICS=1 \
+// RUN: not %clang %s @%t.rsp -DFATAL -fcrash-diagnostics 2>&1 | \
+// RUN: FileCheck %s
+// RUN: cat %t/crash-report-*.cpp | FileCheck --check-prefix=CHECKSRC %s
+// RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s
+
+// RUN: env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 \
+// RUN: CC_PRINT_HEADERS=1 CC_LOG_DIAGNOSTICS=1 \
+// RUN: not %clang %s @%t.rsp -DFATAL -fcrash-diagnostics=compiler 2>&1 |\
+// RUN: FileCheck %s
+// RUN: cat %t/crash-report-*.cpp | FileCheck --check-prefix=CHECKSRC %s
+// RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s
+
+// RUN: env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 \
+// RUN: CC_PRINT_HEADERS=1 CC_LOG_DIAGNOSTICS=1 \
+// RUN: not %clang %s @%t.rsp -DFATAL -fcrash-diagnostics=all 2>&1 | \
+// RUN: FileCheck %s
+// RUN: cat %t/crash-report-*.cpp | FileCheck --check-prefix=CHECKSRC %s
+// RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s
+
// REQUIRES: crash-recovery
#ifdef PARSER
diff --git a/clang/test/Driver/lit.local.cfg b/clang/test/Driver/lit.local.cfg
index 671d9a4b18735..36e7ca4c2edf1 100644
--- a/clang/test/Driver/lit.local.cfg
+++ b/clang/test/Driver/lit.local.cfg
@@ -1,3 +1,5 @@
+from lit.llvm import llvm_config
+
config.suffixes = ['.c', '.cpp', '.h', '.m', '.mm', '.S', '.s', '.f90', '.F90', '.f95',
'.cu', '.rs', '.cl', '.clcpp', '.hip', '.hlsl']
config.substitutions = list(config.substitutions)
@@ -16,3 +18,6 @@ driver_overwrite_env_vars = ['MACOSX_DEPLOYMENT_TARGET',
for name in driver_overwrite_env_vars:
if name in config.environment:
del config.environment[name]
+
+if llvm_config.use_lld(required=False):
+ config.available_features.add('lld')
diff --git a/clang/test/Driver/lld-repro.c b/clang/test/Driver/lld-repro.c
new file mode 100644
index 0000000000000..f558b780fb23b
--- /dev/null
+++ b/clang/test/Driver/lld-repro.c
@@ -0,0 +1,26 @@
+// REQUIRES: lld
+
+// RUN: not %clang %s -fuse-ld=lld -gen-reproducer=error -fcrash-diagnostics-dir=%t -fcrash-diagnostics=all 2>&1 \
+// RUN: | FileCheck %s
+
+// check that we still get lld's output
+// CHECK: error: undefined symbol: a
+
+// CHECK: Preprocessed source(s) and associated run script(s) are located at:
+// CHECK-NEXT: note: diagnostic msg: {{.*}}/lld-repro-{{.*}}.c
+// CHECK-NEXT: note: diagnostic msg: {{.*}}/linker-crash-{{.*}}.tar
+// CHECK-NEXT: note: diagnostic msg: {{.*}}/lld-repro-{{.*}}.sh
+// CHECK-NEXT: note: diagnostic msg:
+// CHECK: ********************
+
+// RUN: not %clang %s -fuse-ld=lld -gen-reproducer=error -fcrash-diagnostics-dir=%t -fcrash-diagnostics=compiler 2>&1 \
+// RUN: | FileCheck %s --check-prefix=NO-LINKER
+// RUN: not %clang %s -fuse-ld=lld -gen-reproducer=error -fcrash-diagnostics-dir=%t 2>&1 \
+// RUN: | FileCheck %s --check-prefix=NO-LINKER
+
+// NO-LINKER-NOT: Preprocessed source(s) and associated run script(s) are located at:
+
+extern int a;
+int main() {
+ return a;
+}
More information about the cfe-commits
mailing list