-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[Clang][Driver] Create crash reproducers for IR inputs #165572
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
Changes from 1 commit
be66c84
dad986e
09ffbf7
e766981
96fc5a6
8a2f7f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,6 +70,7 @@ | |
| #include "llvm/ADT/ArrayRef.h" | ||
| #include "llvm/ADT/STLExtras.h" | ||
| #include "llvm/ADT/SmallSet.h" | ||
| #include "llvm/ADT/SmallVector.h" | ||
| #include "llvm/ADT/StringExtras.h" | ||
| #include "llvm/ADT/StringRef.h" | ||
| #include "llvm/ADT/StringSet.h" | ||
|
|
@@ -103,6 +104,7 @@ | |
| #include <memory> | ||
| #include <optional> | ||
| #include <set> | ||
| #include <string> | ||
| #include <utility> | ||
| #if LLVM_ON_UNIX | ||
| #include <unistd.h> // getpid | ||
|
|
@@ -2041,12 +2043,17 @@ void Driver::generateCompilationDiagnostics( | |
| InputList Inputs; | ||
| BuildInputs(C.getDefaultToolChain(), C.getArgs(), Inputs); | ||
|
|
||
| ArgStringList IRInputs; | ||
| for (InputList::iterator it = Inputs.begin(), ie = Inputs.end(); it != ie;) { | ||
| bool IgnoreInput = false; | ||
|
|
||
| // Ignore input from stdin or any inputs that cannot be preprocessed. | ||
| // Check type first as not all linker inputs have a value. | ||
| if (types::getPreprocessedType(it->first) == types::TY_INVALID) { | ||
| // Save IR inputs separately, ignore input from stdin or any other inputs | ||
| // that cannot be preprocessed. Check type first as not all linker inputs | ||
| // have a value. | ||
| if (types::isLLVMIR(it->first)) { | ||
| IRInputs.push_back(it->second->getValue()); | ||
| IgnoreInput = true; | ||
| } else if (types::getPreprocessedType(it->first) == types::TY_INVALID) { | ||
| IgnoreInput = true; | ||
| } else if (!strcmp(it->second->getValue(), "-")) { | ||
| Diag(clang::diag::note_drv_command_failed_diag_msg) | ||
|
|
@@ -2063,7 +2070,7 @@ void Driver::generateCompilationDiagnostics( | |
| } | ||
| } | ||
|
|
||
| if (Inputs.empty()) { | ||
| if (Inputs.empty() && IRInputs.empty()) { | ||
| Diag(clang::diag::note_drv_command_failed_diag_msg) | ||
| << "Error generating preprocessed source(s) - " | ||
| "no preprocessable inputs."; | ||
|
|
@@ -2086,46 +2093,77 @@ void Driver::generateCompilationDiagnostics( | |
| return; | ||
| } | ||
|
|
||
| // Construct the list of abstract actions to perform for this compilation. On | ||
| // Darwin OSes this uses the driver-driver and builds universal actions. | ||
| const ToolChain &TC = C.getDefaultToolChain(); | ||
| if (TC.getTriple().isOSBinFormatMachO()) | ||
| BuildUniversalActions(C, TC, Inputs); | ||
| else | ||
| BuildActions(C, C.getArgs(), Inputs, C.getActions()); | ||
| // If we only have IR inputs there's no need for preprocessing. | ||
| if (!Inputs.empty()) { | ||
| // Construct the list of abstract actions to perform for this compilation. | ||
| // On | ||
| // Darwin OSes this uses the driver-driver and builds universal actions. | ||
| const ToolChain &TC = C.getDefaultToolChain(); | ||
| if (TC.getTriple().isOSBinFormatMachO()) | ||
| BuildUniversalActions(C, TC, Inputs); | ||
| else | ||
| BuildActions(C, C.getArgs(), Inputs, C.getActions()); | ||
|
|
||
| BuildJobs(C); | ||
| BuildJobs(C); | ||
|
|
||
| // If there were errors building the compilation, quit now. | ||
| if (Trap.hasErrorOccurred()) { | ||
| Diag(clang::diag::note_drv_command_failed_diag_msg) | ||
| << "Error generating preprocessed source(s)."; | ||
| return; | ||
| } | ||
| // If there were errors building the compilation, quit now. | ||
| if (Trap.hasErrorOccurred()) { | ||
| Diag(clang::diag::note_drv_command_failed_diag_msg) | ||
| << "Error generating preprocessed source(s)."; | ||
| return; | ||
| } | ||
| // Generate preprocessed output. | ||
| SmallVector<std::pair<int, const Command *>, 4> FailingCommands; | ||
| C.ExecuteJobs(C.getJobs(), FailingCommands); | ||
|
|
||
| // Generate preprocessed output. | ||
| SmallVector<std::pair<int, const Command *>, 4> FailingCommands; | ||
| C.ExecuteJobs(C.getJobs(), FailingCommands); | ||
| // If any of the preprocessing commands failed, clean up and exit. | ||
| if (!FailingCommands.empty()) { | ||
| Diag(clang::diag::note_drv_command_failed_diag_msg) | ||
| << "Error generating preprocessed source(s)."; | ||
| return; | ||
| } | ||
|
|
||
| // If any of the preprocessing commands failed, clean up and exit. | ||
| if (!FailingCommands.empty()) { | ||
| Diag(clang::diag::note_drv_command_failed_diag_msg) | ||
| << "Error generating preprocessed source(s)."; | ||
| return; | ||
| const ArgStringList &TempFiles = C.getTempFiles(); | ||
| if (TempFiles.empty()) { | ||
| Diag(clang::diag::note_drv_command_failed_diag_msg) | ||
| << "Error generating preprocessed source(s)."; | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| const ArgStringList &TempFiles = C.getTempFiles(); | ||
| if (TempFiles.empty()) { | ||
| Diag(clang::diag::note_drv_command_failed_diag_msg) | ||
| << "Error generating preprocessed source(s)."; | ||
| return; | ||
| // Copying filenames due to ownership. | ||
| const ArgStringList &Files = C.getTempFiles(); | ||
| SmallVector<std::string> TempFiles(Files.begin(), Files.end()); | ||
|
|
||
| // We'd like to copy the IR input file into our own temp file | ||
| // because the build system might try to clean-up after itself. | ||
| for (auto const *Input : IRInputs) { | ||
| int FD; | ||
| llvm::SmallVector<char, 64> Path; | ||
|
|
||
| StringRef extension = llvm::sys::path::extension(Input); | ||
| if (!extension.empty()) | ||
| extension = extension.drop_front(); | ||
|
|
||
| std::error_code EC = llvm::sys::fs::createTemporaryFile( | ||
| llvm::sys::path::stem(Input), extension, FD, Path); | ||
|
|
||
| if (EC) { | ||
| Diag(clang::diag::note_drv_command_failed_diag_msg) | ||
| << "Error generating run script: " << "Failed copying IR input files" | ||
| << " " << EC.message(); | ||
| return; | ||
| } | ||
| llvm::sys::fs::copy_file(Input, FD); | ||
|
||
|
|
||
| TempFiles.push_back(std::string(Path.begin(), Path.end())); | ||
| } | ||
|
|
||
| Diag(clang::diag::note_drv_command_failed_diag_msg) << BugReporMsg; | ||
|
|
||
| SmallString<128> VFS; | ||
| SmallString<128> ReproCrashFilename; | ||
| for (const char *TempFile : TempFiles) { | ||
| for (std::string &TempFile : TempFiles) { | ||
| Diag(clang::diag::note_drv_command_failed_diag_msg) << TempFile; | ||
| if (Report) | ||
| Report->TemporaryFiles.push_back(TempFile); | ||
|
|
@@ -2142,7 +2180,7 @@ void Driver::generateCompilationDiagnostics( | |
| } | ||
|
|
||
| for (const char *TempFile : SavedTemps) | ||
| C.addTempFile(TempFile); | ||
| TempFiles.push_back(TempFile); | ||
|
|
||
| // Assume associated files are based off of the first temporary file. | ||
| CrashReportInfo CrashInfo(TempFiles[0], VFS); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // RUN: %clang -S -emit-llvm -o %t.ll %s | ||
| // RUN: not %clang -DCRASH %s %t.ll 2>&1 | FileCheck %s | ||
|
||
|
|
||
| // CHECK: Preprocessed source(s) and associated run script(s) are located at: | ||
| // CHECK-NEXT: clang: note: diagnostic msg: {{.*}}.cpp | ||
| // CHECK-NEXT: clang: note: diagnostic msg: {{.*}}.ll | ||
| // CHECK-NEXT: clang: note: diagnostic msg: {{.*}}.sh | ||
|
|
||
| #ifdef CRASH | ||
| #pragma clang __debug parser_crash | ||
| #endif | ||
|
|
||
| int main() { | ||
| return 0; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.