diff options
author | Alexey Karyakin <akaryaki@quicinc.com> | 2025-05-14 10:33:57 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-05-14 10:33:57 -0500 |
commit | eac7466448f920e733f12beca28ff848cfa4810d (patch) | |
tree | 6dfdc9d6ae7f09c5116878d2fb50888f67337ce0 /llvm/lib/LTO/LTOBackend.cpp | |
parent | ee47454bb8be7f4cd1ecbd862c5a82d24ef696c7 (diff) | |
download | llvm-eac7466448f920e733f12beca28ff848cfa4810d.zip llvm-eac7466448f920e733f12beca28ff848cfa4810d.tar.gz llvm-eac7466448f920e733f12beca28ff848cfa4810d.tar.bz2 |
[LTO] Fix a crash with thin LTO caching and asm output (#138203)
The `CacheStream::commit()` function (defined in Caching.cpp) deletes
the underlying raw stream. Some output streamers may hold a pointer
to it, which then will outlive the stream object.
In particular, MCAsmStreamer keeps the pointer to the raw stream
though a separate `formatted_raw_stream` object, which buffers data and
there is no path to explicitly flush this data. Before this change,
the buffered data was flushed during the MCAsmStreamer destructor.
After #136121, this happened after the `commit()` function is called.
Therefore, it caused a crash because the `formatted_raw_stream` object
tries to write the buffered data into a deleted raw stream. Even if
we don't delete the stream to avoid the crash, it would be too late
as the output stream cannot accept data after commit().
Fixes: #138194.
Diffstat (limited to 'llvm/lib/LTO/LTOBackend.cpp')
-rw-r--r-- | llvm/lib/LTO/LTOBackend.cpp | 48 |
1 files changed, 27 insertions, 21 deletions
diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 8a85ac8..b7db70b 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -439,27 +439,33 @@ static void codegen(const Config &Conf, TargetMachine *TM, std::unique_ptr<CachedFileStream> &Stream = *StreamOrErr; TM->Options.ObjectFilenameForDebug = Stream->ObjectPathName; - legacy::PassManager CodeGenPasses; - TargetLibraryInfoImpl TLII(Mod.getTargetTriple()); - CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII)); - // No need to make index available if the module is empty. - // In theory these passes should not use the index for an empty - // module, however, this guards against doing any unnecessary summary-based - // analysis in the case of a ThinLTO build where this might be an empty - // regular LTO combined module, with a large combined index from ThinLTO. - if (!isEmptyModule(Mod)) - CodeGenPasses.add( - createImmutableModuleSummaryIndexWrapperPass(&CombinedIndex)); - if (Conf.PreCodeGenPassesHook) - Conf.PreCodeGenPassesHook(CodeGenPasses); - if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS, - DwoOut ? &DwoOut->os() : nullptr, - Conf.CGFileType)) - report_fatal_error("Failed to setup codegen"); - CodeGenPasses.run(Mod); - - if (DwoOut) - DwoOut->keep(); + // Create the codegen pipeline in its own scope so it gets deleted before + // Stream->commit() is called. The commit function of CacheStream deletes + // the raw stream, which is too early as streamers (e.g. MCAsmStreamer) + // keep the pointer and may use it until their destruction. See #138194. + { + legacy::PassManager CodeGenPasses; + TargetLibraryInfoImpl TLII(Mod.getTargetTriple()); + CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII)); + // No need to make index available if the module is empty. + // In theory these passes should not use the index for an empty + // module, however, this guards against doing any unnecessary summary-based + // analysis in the case of a ThinLTO build where this might be an empty + // regular LTO combined module, with a large combined index from ThinLTO. + if (!isEmptyModule(Mod)) + CodeGenPasses.add( + createImmutableModuleSummaryIndexWrapperPass(&CombinedIndex)); + if (Conf.PreCodeGenPassesHook) + Conf.PreCodeGenPassesHook(CodeGenPasses); + if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS, + DwoOut ? &DwoOut->os() : nullptr, + Conf.CGFileType)) + report_fatal_error("Failed to setup codegen"); + CodeGenPasses.run(Mod); + + if (DwoOut) + DwoOut->keep(); + } if (Error Err = Stream->commit()) report_fatal_error(std::move(Err)); |