Skip to content

Commit 430eb57

Browse files
committed
[LTO] Fix a crash with thin LTO caching and asm output
The commit function of CacheStream deletes the underlying raw stream. Some output streamers may hold a pointer to it, which in this case will outlive the stream object. In particular, MCAsmStreamer keeps the pointer to the raw stream though formatted_raw_stream, which calls flush() in its destructor. If commit is called before MCAsmStreamer destruction, it will access freed memory. S
1 parent b2e2ae8 commit 430eb57

File tree

1 file changed

+27
-21
lines changed

1 file changed

+27
-21
lines changed

llvm/lib/LTO/LTOBackend.cpp

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -439,27 +439,33 @@ static void codegen(const Config &Conf, TargetMachine *TM,
439439
std::unique_ptr<CachedFileStream> &Stream = *StreamOrErr;
440440
TM->Options.ObjectFilenameForDebug = Stream->ObjectPathName;
441441

442-
legacy::PassManager CodeGenPasses;
443-
TargetLibraryInfoImpl TLII(Mod.getTargetTriple());
444-
CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII));
445-
// No need to make index available if the module is empty.
446-
// In theory these passes should not use the index for an empty
447-
// module, however, this guards against doing any unnecessary summary-based
448-
// analysis in the case of a ThinLTO build where this might be an empty
449-
// regular LTO combined module, with a large combined index from ThinLTO.
450-
if (!isEmptyModule(Mod))
451-
CodeGenPasses.add(
452-
createImmutableModuleSummaryIndexWrapperPass(&CombinedIndex));
453-
if (Conf.PreCodeGenPassesHook)
454-
Conf.PreCodeGenPassesHook(CodeGenPasses);
455-
if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS,
456-
DwoOut ? &DwoOut->os() : nullptr,
457-
Conf.CGFileType))
458-
report_fatal_error("Failed to setup codegen");
459-
CodeGenPasses.run(Mod);
460-
461-
if (DwoOut)
462-
DwoOut->keep();
442+
// Create the codegen pipeline in its own scope so it gets deleted before
443+
// Stream->commit() is called. The commit function of CacheStream deletes
444+
// the raw stream, which is too early as streamers (e.g. MCAsmStreamer)
445+
// keep the pointer and may use it until their destruction. See #138194.
446+
{
447+
legacy::PassManager CodeGenPasses;
448+
TargetLibraryInfoImpl TLII(Mod.getTargetTriple());
449+
CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII));
450+
// No need to make index available if the module is empty.
451+
// In theory these passes should not use the index for an empty
452+
// module, however, this guards against doing any unnecessary summary-based
453+
// analysis in the case of a ThinLTO build where this might be an empty
454+
// regular LTO combined module, with a large combined index from ThinLTO.
455+
if (!isEmptyModule(Mod))
456+
CodeGenPasses.add(
457+
createImmutableModuleSummaryIndexWrapperPass(&CombinedIndex));
458+
if (Conf.PreCodeGenPassesHook)
459+
Conf.PreCodeGenPassesHook(CodeGenPasses);
460+
if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS,
461+
DwoOut ? &DwoOut->os() : nullptr,
462+
Conf.CGFileType))
463+
report_fatal_error("Failed to setup codegen");
464+
CodeGenPasses.run(Mod);
465+
466+
if (DwoOut)
467+
DwoOut->keep();
468+
}
463469

464470
if (Error Err = Stream->commit())
465471
report_fatal_error(std::move(Err));

0 commit comments

Comments
 (0)